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