001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Portions Copyright 2013-2016 ForgeRock AS 025 */ 026package org.opends.server.tools.upgrade; 027 028import java.io.File; 029import java.io.FileWriter; 030import java.io.IOException; 031import java.util.Arrays; 032import java.util.LinkedList; 033import java.util.List; 034import java.util.NavigableMap; 035import java.util.TreeMap; 036 037import org.forgerock.i18n.LocalizableMessage; 038import org.forgerock.i18n.slf4j.LocalizedLogger; 039import org.opends.server.core.LockFileManager; 040import org.opends.server.util.BuildVersion; 041 042import com.forgerock.opendj.cli.ClientException; 043import com.forgerock.opendj.cli.ReturnCode; 044 045import static com.forgerock.opendj.cli.Utils.*; 046import static javax.security.auth.callback.ConfirmationCallback.*; 047import static javax.security.auth.callback.TextOutputCallback.WARNING; 048 049import static org.opends.messages.ToolMessages.*; 050import static org.opends.server.tools.upgrade.FormattedNotificationCallback.*; 051import static org.opends.server.tools.upgrade.LicenseFile.*; 052import static org.opends.server.tools.upgrade.UpgradeTasks.*; 053import static org.opends.server.tools.upgrade.UpgradeUtils.batDirectory; 054import static org.opends.server.tools.upgrade.UpgradeUtils.binDirectory; 055import static org.opends.server.tools.upgrade.UpgradeUtils.libDirectory; 056import static org.opends.server.util.StaticUtils.*; 057 058/** 059 * This class contains the table of upgrade tasks that need performing when 060 * upgrading from one version to another. 061 */ 062public final class Upgrade 063{ 064 /** Upgrade's logger. */ 065 private static LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 066 067 /** Upgrade supports version from 2.4.5. */ 068 private static BuildVersion UPGRADESUPPORTSVERSIONFROM = BuildVersion.valueOf("2.4.5.0000"); 069 070 /** The success exit code value. */ 071 static final int EXIT_CODE_SUCCESS = 0; 072 /** The error exit code value. */ 073 static final int EXIT_CODE_ERROR = 1; 074 075 /** 076 * The exit code value that will be used if upgrade requires manual 077 * intervention. 078 */ 079 static final int EXIT_CODE_MANUAL_INTERVENTION = 2; 080 081 /** If the upgrade contains some post upgrade tasks to do. */ 082 static boolean hasPostUpgradeTask; 083 084 /** Developers should register upgrade tasks below. */ 085 private static final NavigableMap<BuildVersion, List<UpgradeTask>> TASKS = new TreeMap<>(); 086 private static final List<UpgradeTask> MANDATORY_TASKS = new LinkedList<>(); 087 088 static 089 { 090 // @formatter:off 091 register("2.5.0", 092 modifyConfigEntry(INFO_UPGRADE_TASK_6869_SUMMARY.get(), 093 "(objectClass=ds-cfg-collation-matching-rule)", 094 "add: ds-cfg-collation", 095 "ds-cfg-collation: de:1.3.6.1.4.1.42.2.27.9.4.28.1", 096 "ds-cfg-collation: de-DE:1.3.6.1.4.1.42.2.27.9.4.28.1", 097 "-", 098 "delete: ds-cfg-collation", 099 "ds-cfg-collation: de:1.3.6.1.4.1.142.2.27.9.4.28.1", 100 "ds-cfg-collation: de-DE:1.3.6.1.4.1.142.2.27.9.4.28.1")); 101 102 register("2.5.0", 103 modifyConfigEntry(INFO_UPGRADE_TASK_7192_SUMMARY.get(), 104 "(objectClass=ds-cfg-password-policy)", 105 "add: objectClass", 106 "objectClass: ds-cfg-authentication-policy", 107 "-", 108 "add: ds-cfg-java-class", 109 "ds-cfg-java-class: org.opends.server.core.PasswordPolicyFactory")); 110 111 register("2.5.0", 112 modifyConfigEntry(INFO_UPGRADE_TASK_7364_SUMMARY.get(), 113 "(ds-cfg-java-class=org.opends.server.loggers.TextAuditLogPublisher)", 114 "add: objectClass", 115 "objectClass: ds-cfg-file-based-audit-log-publisher", 116 "-", 117 "delete: objectClass", 118 "objectClass: ds-cfg-file-based-access-log-publisher")); 119 120 register("2.5.0", 121 renameSnmpSecurityConfig(INFO_UPGRADE_TASK_7466_SUMMARY.get())); 122 123 register("2.5.0", 124 newAttributeTypes(INFO_UPGRADE_TASK_7748_1_SUMMARY.get(), 125 "00-core.ldif", "1.3.6.1.4.1.36733.2.1.1.59"), //etag 126 addConfigEntry(INFO_UPGRADE_TASK_7748_2_SUMMARY.get(), 127 "dn: cn=etag,cn=Virtual Attributes,cn=config", 128 "changetype: add", 129 "objectClass: top", 130 "objectClass: ds-cfg-virtual-attribute", 131 "objectClass: ds-cfg-entity-tag-virtual-attribute", 132 "cn: etag", 133 "ds-cfg-java-class: org.opends.server.extensions." 134 + "EntityTagVirtualAttributeProvider", 135 "ds-cfg-enabled: true", 136 "ds-cfg-attribute-type: etag", 137 "ds-cfg-conflict-behavior: real-overrides-virtual", 138 "ds-cfg-checksum-algorithm: adler-32", 139 "ds-cfg-excluded-attribute: ds-sync-hist")); 140 141 register("2.5.0", 142 addConfigEntry(INFO_UPGRADE_TASK_7834_SUMMARY.get(), 143 "dn: cn=Password Expiration Time,cn=Virtual Attributes,cn=config", 144 "changetype: add", 145 "objectClass: top", 146 "objectClass: ds-cfg-virtual-attribute", 147 "objectClass: ds-cfg-password-expiration-time-virtual-attribute", 148 "cn: Password Expiration Time", 149 "ds-cfg-java-class: org.opends.server.extensions." 150 + "PasswordExpirationTimeVirtualAttributeProvider", 151 "ds-cfg-enabled: true", 152 "ds-cfg-attribute-type: ds-pwp-password-expiration-time", 153 "ds-cfg-conflict-behavior: virtual-overrides-real")); 154 155 register("2.5.0", 156 modifyConfigEntry(INFO_UPGRADE_TASK_7979_SUMMARY.get(), 157 "(ds-cfg-java-class=org.opends.server.schema.CertificateSyntax)", 158 "add: objectClass", 159 "objectClass: ds-cfg-certificate-attribute-syntax", 160 "-", 161 "add: ds-cfg-strict-format", 162 "ds-cfg-strict-format: false")); 163 164 register("2.6.0", 165 modifyConfigEntry(INFO_UPGRADE_TASK_8124_SUMMARY.get(), 166 "(ds-cfg-java-class=org.opends.server.schema.JPEGSyntax)", 167 "add: objectClass", 168 "objectClass: ds-cfg-jpeg-attribute-syntax", 169 "-", 170 "add: ds-cfg-strict-format", 171 "ds-cfg-strict-format: false")); 172 173 register("2.6.0", 174 modifyConfigEntry(INFO_UPGRADE_TASK_8133_SUMMARY.get(), 175 "(ds-cfg-java-class=org.opends.server.schema.CountryStringSyntax)", 176 "add: objectClass", 177 "objectClass: ds-cfg-country-string-attribute-syntax", 178 "-", 179 "add: ds-cfg-strict-format", 180 "ds-cfg-strict-format: false")); 181 182 register("2.6.0", 183 requireConfirmation(INFO_UPGRADE_TASK_8214_DESCRIPTION.get(), YES, 184 modifyConfigEntry(INFO_UPGRADE_TASK_8214_SUMMARY.get(), 185 "(ds-cfg-java-class=org.opends.server.extensions.IsMemberOfVirtualAttributeProvider)", 186 "add: ds-cfg-filter", 187 "ds-cfg-filter: (|(objectClass=person)(objectClass=groupOfNames)" 188 + "(objectClass=groupOfUniqueNames)(objectClass=groupOfEntries))", 189 "-", 190 "delete: ds-cfg-filter", 191 "ds-cfg-filter: (objectClass=person)"))); 192 193 register("2.6.0", 194 modifyConfigEntry(INFO_UPGRADE_TASK_8387_SUMMARY.get(), 195 "(objectClass=ds-cfg-dictionary-password-validator)", 196 "add: ds-cfg-check-substrings", 197 "ds-cfg-check-substrings: false")); 198 199 register("2.6.0", 200 modifyConfigEntry(INFO_UPGRADE_TASK_8389_SUMMARY.get(), 201 "(objectClass=ds-cfg-attribute-value-password-validator)", 202 "add: ds-cfg-check-substrings", 203 "ds-cfg-check-substrings: false")); 204 205 register("2.6.0", 206 addConfigEntry(INFO_UPGRADE_TASK_8487_SUMMARY.get(), 207 "dn: cn=PBKDF2,cn=Password Storage Schemes,cn=config", 208 "changetype: add", 209 "objectClass: top", 210 "objectClass: ds-cfg-password-storage-scheme", 211 "objectClass: ds-cfg-pbkdf2-password-storage-scheme", 212 "cn: PBKDF2", 213 "ds-cfg-java-class: org.opends.server.extensions." 214 + "PBKDF2PasswordStorageScheme", 215 "ds-cfg-enabled: true")); 216 217 register("2.6.0", 218 addConfigFile("http-config.json"), 219 addConfigEntry(INFO_UPGRADE_TASK_8613_SUMMARY.get(), 220 "dn: cn=HTTP Connection Handler,cn=Connection Handlers,cn=config", 221 "changetype: add", 222 "objectClass: ds-cfg-http-connection-handler", 223 "objectClass: ds-cfg-connection-handler", 224 "objectClass: top", 225 "ds-cfg-listen-port: 8080", 226 "cn: HTTP Connection Handler", 227 "ds-cfg-max-blocked-write-time-limit: 2 minutes", 228 "ds-cfg-ssl-client-auth-policy: optional", 229 "ds-cfg-use-tcp-keep-alive: true", 230 "ds-cfg-max-request-size: 5 megabytes", 231 "ds-cfg-use-tcp-no-delay: true", 232 "ds-cfg-allow-tcp-reuse-address: true", 233 "ds-cfg-accept-backlog: 128", 234 "ds-cfg-authentication-required: true", 235 "ds-cfg-buffer-size: 4096 bytes", 236 "ds-cfg-config-file: config/http-config.json", 237 "ds-cfg-listen-address: 0.0.0.0", 238 "ds-cfg-java-class: " + 239 "org.opends.server.protocols.http.HTTPConnectionHandler", 240 "ds-cfg-keep-stats: true", 241 "ds-cfg-ssl-cert-nickname: server-cert", 242 "ds-cfg-use-ssl: false", 243 "ds-cfg-enabled: false")); 244 245 register("2.6.0", 246 addConfigEntry(INFO_UPGRADE_TASK_8832_SUMMARY.get(), 247 "dn: cn=File-Based HTTP Access Logger,cn=Loggers,cn=config", 248 "changetype: add", 249 "objectClass: ds-cfg-file-based-http-access-log-publisher", 250 "objectClass: top", 251 "objectClass: ds-cfg-http-access-log-publisher", 252 "objectClass: ds-cfg-log-publisher", 253 "cn: File-Based HTTP Access Logger", 254 "ds-cfg-java-class: " + 255 "org.opends.server.loggers.TextHTTPAccessLogPublisher", 256 "ds-cfg-asynchronous: true", 257 "ds-cfg-log-file: logs/http-access", 258 "ds-cfg-rotation-policy: " + 259 "cn=24 Hours Time Limit Rotation Policy," + 260 "cn=Log Rotation Policies,cn=config", 261 "ds-cfg-rotation-policy: " + 262 "cn=Size Limit Rotation Policy,cn=Log Rotation Policies,cn=config", 263 "ds-cfg-retention-policy: " + 264 "cn=File Count Retention Policy,cn=Log Retention Policies,cn=config", 265 "ds-cfg-log-file-permissions: 640", 266 "ds-cfg-enabled: false")); 267 268 register("2.6.0", 269 newAttributeTypes(INFO_UPGRADE_TASK_8985_1_SUMMARY.get(), 270 "00-core.ldif", "1.2.840.113549.1.9.1"), // emailAddress 271 modifyConfigEntry(INFO_UPGRADE_TASK_8985_2_SUMMARY.get(), 272 "&(ds-cfg-java-class=org.opends.server.extensions." + 273 "SubjectAttributeToUserAttributeCertificateMapper)" + 274 "(ds-cfg-subject-attribute-mapping=e:mail)", 275 "delete:ds-cfg-subject-attribute-mapping", 276 "ds-cfg-subject-attribute-mapping: e:mail", 277 "-", 278 "add:ds-cfg-subject-attribute-mapping", 279 "ds-cfg-subject-attribute-mapping: emailAddress:mail")); 280 281 /** See OPENDJ-992 */ 282 register("2.6.0", 283 regressionInVersion("2.5.0", 284 rebuildSingleIndex(INFO_UPGRADE_TASK_9013_DESCRIPTION.get(), 285 "ds-sync-hist"))); 286 287 /** See OPENDJ-1284 */ 288 register("2.8.0", // userCertificate OID / cACertificate OID 289 newAttributeTypes(INFO_UPGRADE_TASK_10133_1_SUMMARY.get(), 290 "00-core.ldif", "2.5.4.36", "2.5.4.37"), 291 addConfigEntry(INFO_UPGRADE_TASK_10133_2_SUMMARY.get(), 292 "dn: cn=Certificate Exact Matching Rule,cn=Matching Rules,cn=config", 293 "changetype: add", 294 "objectClass: top", 295 "objectClass: ds-cfg-matching-rule", 296 "objectClass: ds-cfg-equality-matching-rule", 297 "cn: Certificate Exact Matching Rule", 298 "ds-cfg-java-class: " 299 + "org.opends.server.schema.CertificateExactMatchingRuleFactory", 300 "ds-cfg-enabled: true")); 301 302 303 /** See OPENDJ-1295 */ 304 register("2.8.0", 305 copySchemaFile("03-pwpolicyextension.ldif")); 306 307 /** See OPENDJ-1490 and OPENDJ-1454 */ 308 register("2.8.0", 309 deleteConfigEntry(INFO_UPGRADE_TASK_10733_1_SUMMARY.get(), 310 "dn: ds-cfg-backend-id=replicationChanges,cn=Backends,cn=config"), 311 modifyConfigEntry(INFO_UPGRADE_TASK_10733_2_SUMMARY.get(), 312 "(objectClass=ds-cfg-dsee-compat-access-control-handler)", 313 "delete: ds-cfg-global-aci", 314 "ds-cfg-global-aci: " 315 + "(target=\"ldap:///dc=replicationchanges\")" 316 + "(targetattr=\"*\")" 317 + "(version 3.0; acl \"Replication backend access\"; " 318 + "deny (all) userdn=\"ldap:///anyone\";)")); 319 320 /** See OPENDJ-1351 */ 321 register("2.8.0", 322 modifyConfigEntry(INFO_UPGRADE_TASK_10820_SUMMARY.get(), 323 "(objectClass=ds-cfg-root-dn)", 324 "add: ds-cfg-default-root-privilege-name", 325 "ds-cfg-default-root-privilege-name: changelog-read")); 326 327 /** See OPENDJ-1580 */ 328 register("2.8.0", 329 addConfigEntry(INFO_UPGRADE_TASK_10908_SUMMARY.get(), 330 "dn: cn=PKCS5S2,cn=Password Storage Schemes,cn=config", 331 "changetype: add", 332 "objectClass: top", 333 "objectClass: ds-cfg-password-storage-scheme", 334 "objectClass: ds-cfg-pkcs5s2-password-storage-scheme", 335 "cn: PKCS5S2", 336 "ds-cfg-java-class: org.opends.server.extensions.PKCS5S2PasswordStorageScheme", 337 "ds-cfg-enabled: true")); 338 339 /** See OPENDJ-1322 and OPENDJ-1067 */ 340 register("2.8.0", 341 rerunJavaPropertiesTool(INFO_UPGRADE_TASK_9206_SUMMARY.get())); 342 343 register("2.8.0", 344 modifyConfigEntry(INFO_UPGRADE_TASK_10214_SUMMARY.get(), 345 "(ds-cfg-java-class=org.opends.server.loggers.debug.TextDebugLogPublisher)", 346 "delete:ds-cfg-java-class", 347 "-", 348 "add:ds-cfg-java-class", 349 "ds-cfg-java-class: org.opends.server.loggers.TextDebugLogPublisher")); 350 351 register("2.8.0", 352 modifyConfigEntry(INFO_UPGRADE_TASK_10232_SUMMARY.get(), 353 "(objectclass=ds-cfg-file-based-debug-log-publisher)", 354 "delete:ds-cfg-default-debug-level")); 355 356 register("2.8.0", 357 modifyConfigEntry(INFO_UPGRADE_TASK_10329_SUMMARY.get(), 358 "&(objectclass=ds-cfg-file-based-error-log-publisher)(cn=File-Based Error Logger)", 359 "delete:ds-cfg-default-severity", 360 "ds-cfg-default-severity: severe-warning", 361 "ds-cfg-default-severity: severe-error", 362 "ds-cfg-default-severity: fatal-error", 363 "-", 364 "add:ds-cfg-default-severity", 365 "ds-cfg-default-severity: error", 366 "ds-cfg-default-severity: warning" 367 )); 368 369 register("2.8.0", 370 modifyConfigEntry(INFO_UPGRADE_TASK_10339_SUMMARY.get(), 371 "&(objectclass=ds-cfg-file-based-error-log-publisher)(cn=Replication Repair Logger)", 372 "delete:ds-cfg-override-severity", 373 "-", 374 "add:ds-cfg-override-severity", 375 "ds-cfg-override-severity: SYNC=INFO,ERROR,WARNING,NOTICE")); 376 377 /** See OPENDJ-1545 */ 378 register("2.8.0", 379 deleteConfigEntry(INFO_UPGRADE_TASK_11237_1_SUMMARY.get(), 380 "dn: cn=Network Groups,cn=config"), 381 deleteConfigEntry(INFO_UPGRADE_TASK_11237_2_SUMMARY.get(), 382 "dn: cn=Workflows,cn=config"), 383 deleteConfigEntry(INFO_UPGRADE_TASK_11237_3_SUMMARY.get(), 384 "dn: cn=Workflow Elements,cn=config")); 385 register("2.8.0", 386 deleteConfigEntry(INFO_UPGRADE_TASK_11239_SUMMARY.get(), 387 "dn: cn=Network Group,cn=Plugins,cn=config")); 388 register("2.8.0", 389 deleteConfigEntry(INFO_UPGRADE_TASK_11339_SUMMARY.get(), 390 "dn: cn=Extensions,cn=config")); 391 392 /** See OPENDJ-1701 */ 393 register("2.8.0", 394 deleteConfigEntry(INFO_UPGRADE_TASK_11476_SUMMARY.get(), 395 "dn: cn=File System,cn=Entry Caches,cn=config")); 396 397 /** See OPENDJ-1869 */ 398 register("2.8.0", 399 modifyConfigEntry(INFO_UPGRADE_TASK_12226_SUMMARY.get(), 400 "(objectclass=ds-cfg-root-config)", 401 "delete: ds-cfg-entry-cache-preload")); 402 403 /** See OPENDJ-2054 */ 404 register("2.8.0", 405 deleteFile(new File(binDirectory, "dsframework")), 406 deleteFile(new File(batDirectory, "dsframework.bat"))); 407 408 /** If the upgraded version is a non OEM one, migrates local-db backends to JE Backend, see OPENDJ-2364 **/ 409 register("3.0.0", 410 conditionalUpgradeTasks( 411 new UpgradeCondition() { 412 @Override 413 public boolean shouldPerformUpgradeTasks(UpgradeContext context) throws ClientException { 414 return !isOEMVersion(); 415 } 416 417 @Override 418 public String toString() { 419 return "!isOEMVersion"; 420 } 421 }, 422 migrateLocalDBBackendsToJEBackends(), 423 modifyConfigEntry(INFO_UPGRADE_TASK_MIGRATE_JE_SUMMARY_2.get(), 424 "(objectClass=ds-cfg-local-db-backend)", 425 "replace: objectClass", 426 "objectClass: top", 427 "objectClass: ds-cfg-backend", 428 "objectClass: ds-cfg-pluggable-backend", 429 "objectClass: ds-cfg-je-backend", 430 "-", 431 "replace: ds-cfg-java-class", 432 "ds-cfg-java-class: org.opends.server.backends.jeb.JEBackend", 433 "-", 434 "delete: ds-cfg-import-thread-count", 435 "-", 436 "delete: ds-cfg-import-queue-size", 437 "-", 438 "delete: ds-cfg-subordinate-indexes-enabled", 439 "-" 440 ), 441 modifyConfigEntry(INFO_UPGRADE_TASK_MIGRATE_JE_SUMMARY_3.get(), 442 "(objectClass=ds-cfg-local-db-index)", 443 "replace: objectClass", 444 "objectClass: top", 445 "objectClass: ds-cfg-backend-index", 446 "-" 447 ), 448 modifyConfigEntry(INFO_UPGRADE_TASK_MIGRATE_JE_SUMMARY_4.get(), 449 "(objectClass=ds-cfg-local-db-vlv-index)", 450 "replace: objectClass", 451 "objectClass: top", 452 "objectClass: ds-cfg-backend-vlv-index", 453 "-", 454 "delete: ds-cfg-max-block-size", 455 "-" 456 ) 457 ) 458 ); 459 460 /** If the upgraded version is OEM, migrates local-db backends to PDB, see OPENDJ-2364 **/ 461 register("3.0.0", 462 conditionalUpgradeTasks( 463 new UpgradeCondition() { 464 @Override 465 public boolean shouldPerformUpgradeTasks(UpgradeContext context) throws ClientException { 466 return isOEMVersion(); 467 } 468 469 @Override 470 public String toString() { 471 return "isOEMVersion"; 472 } 473 }, 474 deleteFile(new File(libDirectory, "je.jar")), 475 requireConfirmation(INFO_UPGRADE_TASK_LOCAL_DB_TO_PDB_1_SUMMARY.get(), NO, 476 renameLocalDBBackendDirectories(), 477 // Convert JE backends to PDB backends. 478 modifyConfigEntry(INFO_UPGRADE_TASK_LOCAL_DB_TO_PDB_2_SUMMARY.get(), 479 "(objectclass=ds-cfg-local-db-backend)", 480 "delete: objectclass", 481 "objectclass: ds-cfg-local-db-backend", 482 "-", 483 "add: objectclass", 484 "objectclass: ds-cfg-pluggable-backend", 485 "objectclass: ds-cfg-pdb-backend", 486 "-", 487 "replace: ds-cfg-java-class", 488 "ds-cfg-java-class: org.opends.server.backends.pdb.PDBBackend", 489 "-", 490 "delete: ds-cfg-preload-time-limit", 491 "-", 492 "delete: ds-cfg-import-thread-count", 493 "-", 494 "delete: ds-cfg-import-queue-size", 495 "-", 496 "delete: ds-cfg-db-txn-write-no-sync", 497 "-", 498 "delete: ds-cfg-db-run-cleaner", 499 "-", 500 "delete: ds-cfg-db-cleaner-min-utilization", 501 "-", 502 "delete: ds-cfg-db-evictor-lru-only", 503 "-", 504 "delete: ds-cfg-db-evictor-core-threads", 505 "-", 506 "delete: ds-cfg-db-evictor-max-threads", 507 "-", 508 "delete: ds-cfg-db-evictor-keep-alive", 509 "-", 510 "delete: ds-cfg-db-evictor-nodes-per-scan", 511 "-", 512 "delete: ds-cfg-db-log-file-max", 513 "-", 514 "delete: ds-cfg-db-log-filecache-size", 515 "-", 516 "delete: ds-cfg-db-logging-file-handler-on", 517 "-", 518 "delete: ds-cfg-db-logging-level", 519 "-", 520 "delete: ds-cfg-db-checkpointer-bytes-interval", 521 "-", 522 "delete: ds-cfg-db-checkpointer-wakeup-interval", 523 "-", 524 "delete: ds-cfg-db-num-lock-tables", 525 "-", 526 "delete: ds-cfg-db-num-cleaner-threads", 527 "-", 528 "delete: ds-cfg-je-property", 529 "-", 530 "delete: ds-cfg-subordinate-indexes-enabled", 531 "-" 532 ), 533 // Convert JE backend indexes to PDB backend indexes. 534 modifyConfigEntry(INFO_UPGRADE_TASK_LOCAL_DB_TO_PDB_3_SUMMARY.get(), 535 "(objectclass=ds-cfg-local-db-index)", 536 "delete: objectclass", 537 "objectclass: ds-cfg-local-db-index", 538 "-", 539 "add: objectclass", 540 "objectclass: ds-cfg-backend-index", 541 "-" 542 ), 543 // Convert JE backend VLV indexes to PDB backend VLV indexes. 544 modifyConfigEntry(INFO_UPGRADE_TASK_LOCAL_DB_TO_PDB_4_SUMMARY.get(), 545 "(objectclass=ds-cfg-local-db-vlv-index)", 546 "delete: objectclass", 547 "objectclass: ds-cfg-local-db-vlv-index", 548 "-", 549 "add: objectclass", 550 "objectclass: ds-cfg-backend-vlv-index", 551 "-", 552 "delete: ds-cfg-max-block-size", 553 "-" 554 ) 555 ) 556 ) 557 ); 558 559 /** Remove dbtest tool (replaced by backendstat in 3.0.0) - see OPENDJ-1791 **/ 560 register("3.0.0", 561 deleteFile(new File(binDirectory, "dbtest")), 562 deleteFile(new File(batDirectory, "dbtest.bat"))); 563 564 /** 565 * Rebuild all indexes when upgrading to 3.0.0. 566 * 567 * 1) matching rules have changed in 2.8.0 and again in 3.0.0- see OPENDJ-1637 568 * 2) JE backend has been migrated to pluggable architecture. 569 */ 570 register("3.0.0", 571 rebuildAllIndexes(INFO_UPGRADE_TASK_11260_SUMMARY.get())); 572 573 /** See OPENDJ-1742 */ 574 register("3.0.0", 575 clearReplicationDbDirectory()); 576 577 /** 578 * All upgrades will refresh the server configuration schema and generate a new upgrade folder. 579 */ 580 registerLast( 581 copySchemaFile("02-config.ldif"), 582 updateConfigUpgradeFolder(), 583 postUpgradeRebuildIndexes()); 584 585 // @formatter:on 586 } 587 588 /** 589 * Returns a list containing all the tasks which are required in order to upgrade 590 * from {@code fromVersion} to {@code toVersion}. 591 * 592 * @param fromVersion 593 * The old version. 594 * @param toVersion 595 * The new version. 596 * @return A list containing all the tasks which are required in order to upgrade 597 * from {@code fromVersion} to {@code toVersion}. 598 */ 599 private static List<UpgradeTask> getUpgradeTasks(final BuildVersion fromVersion, final BuildVersion toVersion) 600 { 601 final List<UpgradeTask> tasks = new LinkedList<>(); 602 for (final List<UpgradeTask> subList : TASKS.subMap(fromVersion, false, 603 toVersion, true).values()) 604 { 605 tasks.addAll(subList); 606 } 607 tasks.addAll(MANDATORY_TASKS); 608 return tasks; 609 } 610 611 /** 612 * Upgrades the server from {@code fromVersion} to {@code toVersion} located in the upgrade context. 613 * 614 * @param context 615 * The context of the upgrade. 616 * @throws ClientException 617 * If an error occurred while performing the upgrade. 618 */ 619 public static void upgrade(final UpgradeContext context) 620 throws ClientException 621 { 622 // Checks and validates the version number. 623 isVersionCanBeUpdated(context); 624 625 // Server must be offline. 626 checkIfServerIsRunning(context); 627 628 context.notify(INFO_UPGRADE_TITLE.get(), TITLE_CALLBACK); 629 context.notify(INFO_UPGRADE_SUMMARY.get(context.getFromVersion(), context.getToVersion()), NOTICE_CALLBACK); 630 context.notify(INFO_UPGRADE_GENERAL_SEE_FOR_DETAILS.get(UpgradeLog.getLogFilePath()), NOTICE_CALLBACK); 631 632 // Checks License. 633 checkLicence(context); 634 635 logWarnAboutPatchesFolder(); 636 637 // Get the list of required upgrade tasks. 638 final List<UpgradeTask> tasks = 639 getUpgradeTasks(context.getFromVersion(), context.getToVersion()); 640 if (tasks.isEmpty()) 641 { 642 changeBuildInfoVersion(context); 643 return; 644 } 645 646 try 647 { 648 // Let tasks interact with the user in order to obtain user's selection. 649 context.notify(INFO_UPGRADE_REQUIREMENTS.get(), TITLE_CALLBACK); 650 for (final UpgradeTask task : tasks) 651 { 652 task.prepare(context); 653 } 654 655 // Starts upgrade 656 final int userResponse = context.confirmYN(INFO_UPGRADE_DISPLAY_CONFIRM_START.get(), YES); 657 if (userResponse == NO) 658 { 659 final LocalizableMessage message = INFO_UPGRADE_ABORTED_BY_USER.get(); 660 context.notify(message, WARNING); 661 throw new ClientException(ReturnCode.ERROR_UNEXPECTED, message); 662 } 663 664 // Perform the upgrade tasks. 665 context.notify(INFO_UPGRADE_PERFORMING_TASKS.get(), TITLE_CALLBACK); 666 for (final UpgradeTask task : tasks) 667 { 668 task.perform(context); 669 } 670 671 if (UpgradeTasks.countErrors == 0) 672 { 673 /* 674 * The end of a successful upgrade is marked up with the build info file update and the license, 675 * if present, requires the creation of an approval file. 676 */ 677 changeBuildInfoVersion(context); 678 679 createFileLicenseApproved(); 680 } 681 else 682 { 683 context.notify(ERR_UPGRADE_FAILS.get(UpgradeTasks.countErrors), TITLE_CALLBACK); 684 } 685 686 // Performs the post upgrade tasks. 687 if (hasPostUpgradeTask && UpgradeTasks.countErrors == 0) 688 { 689 context.notify(INFO_UPGRADE_PERFORMING_POST_TASKS.get(), TITLE_CALLBACK); 690 performPostUpgradeTasks(context, tasks); 691 context.notify(INFO_UPGRADE_POST_TASKS_COMPLETE.get(), TITLE_CALLBACK); 692 } 693 } 694 catch (final ClientException e) 695 { 696 context.notify(e.getMessageObject(), ERROR_CALLBACK); 697 throw e; 698 } 699 catch (final Exception e) 700 { 701 final LocalizableMessage message = ERR_UPGRADE_TASKS_FAIL.get(stackTraceToSingleLineString(e)); 702 context.notify(message, ERROR_CALLBACK); 703 throw new ClientException(ReturnCode.ERROR_UNEXPECTED, message, e); 704 } 705 finally 706 { 707 context.notify(INFO_UPGRADE_GENERAL_SEE_FOR_DETAILS.get(UpgradeLog.getLogFilePath()), NOTICE_CALLBACK); 708 logger.info(INFO_UPGRADE_PROCESS_END); 709 } 710 } 711 712 private static void performPostUpgradeTasks(final UpgradeContext context, final List<UpgradeTask> tasks) 713 throws ClientException 714 { 715 boolean isOk = true; 716 for (final UpgradeTask task : tasks) 717 { 718 if (isOk) 719 { 720 try 721 { 722 task.postUpgrade(context); 723 } 724 catch (ClientException e) 725 { 726 context.notify(e.getMessageObject(), WARNING); 727 isOk = false; 728 } 729 } 730 else 731 { 732 task.postponePostUpgrade(context); 733 } 734 } 735 } 736 737 private static void register(final String versionString, 738 final UpgradeTask... tasks) 739 { 740 final BuildVersion version = BuildVersion.valueOf(versionString); 741 List<UpgradeTask> taskList = TASKS.get(version); 742 if (taskList == null) 743 { 744 taskList = new LinkedList<>(); 745 TASKS.put(version, taskList); 746 } 747 taskList.addAll(Arrays.asList(tasks)); 748 } 749 750 private static void registerLast(final UpgradeTask... tasks) 751 { 752 MANDATORY_TASKS.addAll(Arrays.asList(tasks)); 753 } 754 755 /** 756 * The server must be offline during the upgrade. 757 * 758 * @throws ClientException 759 * An exception is thrown if the server is currently running. 760 */ 761 private static void checkIfServerIsRunning(final UpgradeContext context) throws ClientException 762 { 763 final String lockFile = LockFileManager.getServerLockFileName(); 764 765 final StringBuilder failureReason = new StringBuilder(); 766 try 767 { 768 // Assume that if we cannot acquire the lock file the server is running. 769 if (!LockFileManager.acquireExclusiveLock(lockFile, failureReason)) 770 { 771 final LocalizableMessage message = ERR_UPGRADE_REQUIRES_SERVER_OFFLINE.get(); 772 context.notify(message, NOTICE_CALLBACK); 773 throw new ClientException(ReturnCode.ERROR_UNEXPECTED, message); 774 } 775 } 776 finally 777 { 778 LockFileManager.releaseLock(lockFile, failureReason); 779 } 780 } 781 782 /** 783 * Checks if the version can be updated. 784 * 785 * @param context 786 * The current context which running the upgrade. 787 * @throws ClientException 788 * If an exception occurs - stops the process. 789 */ 790 private static void isVersionCanBeUpdated(final UpgradeContext context) 791 throws ClientException 792 { 793 if (context.getFromVersion().equals(context.getToVersion())) 794 { 795 // If the server is already up to date then treat it as a successful upgrade so that upgrade is idempotent. 796 final LocalizableMessage message = ERR_UPGRADE_VERSION_UP_TO_DATE.get(context.getToVersion()); 797 context.notify(message, NOTICE_CALLBACK); 798 throw new ClientException(ReturnCode.SUCCESS, message); 799 } 800 801 // The upgrade only supports version >= 2.4.5. 802 if (context.getFromVersion().compareTo(UPGRADESUPPORTSVERSIONFROM) < 0) 803 { 804 final LocalizableMessage message = 805 INFO_UPGRADE_VERSION_IS_NOT_SUPPORTED.get(UPGRADESUPPORTSVERSIONFROM, UPGRADESUPPORTSVERSIONFROM); 806 context.notify(message, NOTICE_CALLBACK); 807 throw new ClientException(ReturnCode.ERROR_UNEXPECTED, message); 808 } 809 } 810 811 /** 812 * Writes the up to date's version number within the build info file. 813 * 814 * @param context 815 * The current context which running the upgrade. 816 * @throws ClientException 817 * If an exception occurs when displaying the message. 818 */ 819 private static void changeBuildInfoVersion(final UpgradeContext context) 820 throws ClientException 821 { 822 File buildInfoFile = new File(UpgradeUtils.configDirectory, Installation.BUILDINFO_RELATIVE_PATH); 823 try (FileWriter buildInfo = new FileWriter(buildInfoFile, false)) 824 { 825 826 // Write the new version 827 buildInfo.write(context.getToVersion().toString()); 828 829 context.notify(INFO_UPGRADE_SUCCESSFUL.get(context.getFromVersion(), context.getToVersion()), TITLE_CALLBACK); 830 } 831 catch (IOException e) 832 { 833 final LocalizableMessage message = LocalizableMessage.raw(e.getMessage()); 834 context.notify(message, ERROR_CALLBACK); 835 throw new ClientException(ReturnCode.ERROR_UNEXPECTED, message); 836 } 837 } 838 839 private static void checkLicence(final UpgradeContext context) 840 throws ClientException 841 { 842 // Check license 843 if (LicenseFile.exists() && !LicenseFile.isAlreadyApproved()) 844 { 845 context.notify(LocalizableMessage.raw(LINE_SEPARATOR + LicenseFile.getText())); 846 context.notify(INFO_LICENSE_DETAILS_CLI_LABEL.get()); 847 if (!context.isAcceptLicenseMode()) 848 { 849 final int answer; 850 851 // The force cannot answer yes to the license's question, which is not a task even if it requires a user 852 // interaction OR -an accept license mode to continue the process. 853 if (context.isForceUpgradeMode()) 854 { 855 answer = NO; 856 context.notify( 857 LocalizableMessage.raw(INFO_LICENSE_ACCEPT.get() + " " + INFO_PROMPT_NO_COMPLETE_ANSWER.get())); 858 } 859 else 860 { 861 answer = context.confirmYN(INFO_LICENSE_ACCEPT.get(), NO); 862 } 863 864 if (answer == NO) 865 { 866 System.exit(EXIT_CODE_SUCCESS); 867 } 868 else if (answer == YES) 869 { 870 LicenseFile.setApproval(true); 871 } 872 } 873 else 874 { 875 // We automatically accept the license with this option. 876 context.notify( 877 LocalizableMessage.raw(INFO_LICENSE_ACCEPT.get() + " " + INFO_PROMPT_YES_COMPLETE_ANSWER.get())); 878 LicenseFile.setApproval(true); 879 } 880 } 881 } 882 883 /** 884 * The classes folder is renamed by the script launcher to avoid 885 * incompatibility between patches and upgrade process. If a folder 886 * "classes.disabled" is found, this function just displays a warning in the 887 * log file, meaning the "classes" folder has been renamed. See upgrade.sh / 888 * upgrade.bat scripts which hold the renaming process. (OPENDJ-1098) 889 */ 890 private static void logWarnAboutPatchesFolder() 891 { 892 try 893 { 894 final File backup = new File(UpgradeUtils.getInstancePath(), "classes.disabled"); 895 if (backup.exists()) { 896 final File[] files = backup.listFiles(); 897 if (files != null && files.length > 0) 898 { 899 logger.warn(INFO_UPGRADE_CLASSES_FOLDER_RENAMED, backup.getAbsoluteFile()); 900 } 901 } 902 } 903 catch (SecurityException e) 904 { 905 logger.debug(LocalizableMessage.raw(e.getMessage()), e); 906 } 907 } 908 909 /** 910 * Returns {@code true} if the current upgrade contains post upgrade tasks. 911 * 912 * @return {@code true} if the current upgrade contains post upgrade tasks. 913 */ 914 static boolean hasPostUpgradeTask() 915 { 916 return hasPostUpgradeTask; 917 } 918 919 /** 920 * Sets {@code true} if the current upgrade contains post upgrade tasks. 921 * 922 * @param hasPostUpgradeTask 923 * {@code true} if the current upgrade contains post upgrade tasks. 924 */ 925 static void setHasPostUpgradeTask(boolean hasPostUpgradeTask) 926 { 927 Upgrade.hasPostUpgradeTask = hasPostUpgradeTask; 928 } 929 930 /** Prevent instantiation. */ 931 private Upgrade() 932 { 933 // Nothing to do. 934 } 935}