OPENDJ-1490 (CR-3724) Replicated server fails to start after upgrade due to missing ReplicationBackend class
Added upgrade tasks for:
- Removing 'dc=replicationchanges' backend
- Removing ACI for 'dc=replicationchanges'
Upgrade.java:
Registered upgrade tasks.
UpgradeTasks.java:
Added deleteConfigEntry().
Factorized code by extracting method perform0().
Fixed javadocs.
UpgradeUtils.java:
In updateConfigFile(), renamed lines parameter to ldifLines + changed String dn local variable to DN ldifDN + added support for deleting entries.
tools.properties:
Added messages for upgrade tasks.
Fixed typos.
admin_tool.properties:
Fixed typos.
SaltedMD5PasswordStorageSchemeTestCase.java:
Removed unused import.
| | |
| | | following suffixes:%n%s%nTo avoid a single point of failure at least two \ |
| | | replication servers must be configured.%nDo you want to continue? |
| | | INFO_DISABLE_REPLICATION_DISABLE_IN_REMOTE=You have decided to disable the \ |
| | | replication server (replication changelog). At least one replicaton server \ |
| | | replication server (replication changelog). At least one replication server \ |
| | | is required in a replication topology and this is the last replication server \ |
| | | for the following suffixes:%n%s%nReplication will be disabled for these \ |
| | | servers. |
| | | INFO_DISABLE_REPLICATION_DISABLE_IN_REMOTE_PROMPT=You have decided to disable \ |
| | | the replication server (replication changelog). At least one replicaton \ |
| | | the replication server (replication changelog). At least one replication \ |
| | | server is required in a replication topology and this is the last replication \ |
| | | server for the following suffixes:%n%s%nReplication will be disabled for \ |
| | | these servers.%nDo you want to continue? |
| | |
| | | INFO_REPLICATION_WARNING_NO_REPLICATION_SERVER_TO_DISABLE=There is no \ |
| | | replication server configured in '%s'. |
| | | INFO_REPLICATION_PROMPT_DISABLE_REPLICATION_SERVER=Do you want to disable the \ |
| | | replication server (changelog and replicatin port '%d') on the server? |
| | | replication server (changelog and replication port '%d') on the server? |
| | | INFO_REPLICATION_CONFIRM_INITIALIZE_ADS=You chose to initialize the contents \ |
| | | of base DN %s on server %s with the contents in server %s. This base DN is \ |
| | | used by the replication mechanism and by some administrative tools and it is \ |
| | |
| | | provided LDIF files must be conform to the server schema |
| | | SEVERE_WARN_LDIFDIFF_NO_CONFIG_FILE_1675=WARNING: no configuration file was \ |
| | | provided as argument. No schema check will be performed. If this is being \ |
| | | called throught the '%s' command-line, verify that the script has not been \ |
| | | called through the '%s' command-line, verify that the script has not been \ |
| | | modified |
| | | INFO_LDAPAUTH_NON_EMPTY_PASSWORD_1676=You must provide a non-empty password \ |
| | | to continue |
| | |
| | | INFO_UPGRADE_REBUILD_INDEX_ENDS_1840=Rebuild index task ends |
| | | INFO_UPGRADE_PERFORMING_POST_TASKS_1841=Performing post upgrade tasks |
| | | INFO_UPGRADE_POST_TASKS_COMPLETE_1842=Post upgrade tasks complete |
| | | SEVERE_ERR_UPGRADE_PERFORMING_POST_TASKS_FAIL_1843=An error occured during post \ |
| | | SEVERE_ERR_UPGRADE_PERFORMING_POST_TASKS_FAIL_1843=An error occurred during post \ |
| | | upgrade task. Process aborted. Please check log for further details |
| | | INFO_UPGRADE_REBUILD_INDEX_DECLINED_1844 =You have to rebuild the '%s' index \ |
| | | manually to get a fully functional server |
| | |
| | | INFO_UPGRADE_TASK_10133_1_SUMMARY_10021=Changing matching rule for 'userCertificate' and \ |
| | | 'caCertificate' to CertificateExactMatch |
| | | INFO_UPGRADE_TASK_10133_2_SUMMARY_10022=Configuring 'CertificateExactMatch' matching rule |
| | | INFO_UPGRADE_TASK_10733_1_SUMMARY_10023=Removing 'dc=replicationchanges' backend |
| | | INFO_UPGRADE_TASK_10733_2_SUMMARY_10024=Removing ACI for 'dc=replicationchanges' |
| | |
| | | "delete: objectClass", |
| | | "objectClass: ds-cfg-file-based-access-log-publisher")); |
| | | |
| | | register ("2.5.0.7466", |
| | | register("2.5.0.7466", |
| | | renameSnmpSecurityConfig(INFO_UPGRADE_TASK_7466_SUMMARY.get())); |
| | | |
| | | register("2.5.0.7748", |
| | |
| | | register("2.7.0.10215", |
| | | copySchemaFile("03-pwpolicyextension.ldif")); |
| | | |
| | | /** See OPENDJ-1490 and OPENDJ-1454 */ |
| | | register("2.7.0.10703", |
| | | deleteConfigEntry(INFO_UPGRADE_TASK_10733_1_SUMMARY.get(), |
| | | "dn: ds-cfg-backend-id=replicationChanges,cn=Backends,cn=config"), |
| | | modifyConfigEntry(INFO_UPGRADE_TASK_10733_2_SUMMARY.get(), |
| | | "(objectClass=ds-cfg-dsee-compat-access-control-handler)", |
| | | "delete: ds-cfg-global-aci", |
| | | "ds-cfg-global-aci: " |
| | | + "(target=\"ldap:///dc=replicationchanges\")" |
| | | + "(targetattr=\"*\")" |
| | | + "(version 3.0; acl \"Replication backend access\"; " |
| | | + "deny (all) userdn=\"ldap:///anyone\";)")); |
| | | |
| | | /* |
| | | * All upgrades will refresh the server configuration schema and generate |
| | | * a new upgrade folder. |
| | |
| | | static boolean isRebuildAllIndexesTaskAccepted = false; |
| | | |
| | | /** |
| | | * Returns a new upgrade task which applies an LDIF record to all |
| | | * configuration entries matching the provided filter. |
| | | * Returns a new upgrade task which adds a config entry to the underlying |
| | | * config file. |
| | | * |
| | | * @param summary |
| | | * The summary of this upgrade task. |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns a new upgrade task which deletes a config entry from the underlying |
| | | * config file. |
| | | * |
| | | * @param summary |
| | | * The summary of this upgrade task. |
| | | * @param dnInLDIF |
| | | * The dn to delete in the form of LDIF. |
| | | * @return A new upgrade task which applies an LDIF record to all |
| | | * configuration entries matching the provided filter. |
| | | */ |
| | | public static UpgradeTask deleteConfigEntry(final Message summary, |
| | | final String dnInLDIF) |
| | | { |
| | | return new AbstractUpgradeTask() |
| | | { |
| | | @Override |
| | | public void perform(final UpgradeContext context) throws ClientException |
| | | { |
| | | perform0(summary, null, ChangeOperationType.DELETE, context, dnInLDIF); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * Returns a new upgrade task which applies an LDIF record to all |
| | | * configuration entries matching the provided filter. |
| | | * |
| | |
| | | { |
| | | if (userConfirmation) |
| | | { |
| | | displayTaskLogInformation(summary.toString(), null, ldif); |
| | | |
| | | final ProgressNotificationCallback pnc = |
| | | new ProgressNotificationCallback(0, summary, 20); |
| | | |
| | | context.notifyProgress(pnc); |
| | | |
| | | try |
| | | { |
| | | // TODO change the directory to the config if it exists. |
| | | final File configFile = |
| | | new File(configDirectory, |
| | | Installation.CURRENT_CONFIG_FILE_NAME); |
| | | |
| | | final int changeCount = |
| | | updateConfigFile(configFile.getPath(), null, |
| | | ChangeOperationType.ADD, ldif); |
| | | |
| | | displayChangeCount(configFile.getPath(), changeCount); |
| | | |
| | | context.notifyProgress(pnc.setProgress(100)); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | manageTaskException(context, Message.fromObject(e.getMessage()), |
| | | pnc); |
| | | } |
| | | perform0(summary, null, ChangeOperationType.ADD, context, ldif); |
| | | } |
| | | } |
| | | }; |
| | |
| | | { |
| | | if (userConfirmation) |
| | | { |
| | | displayTaskLogInformation(summary.toString(), filter, ldif); |
| | | |
| | | final ProgressNotificationCallback pnc = |
| | | new ProgressNotificationCallback(0, summary, 20); |
| | | |
| | | context.notifyProgress(pnc); |
| | | |
| | | try |
| | | { |
| | | final File configFile = |
| | | new File(configDirectory, |
| | | Installation.CURRENT_CONFIG_FILE_NAME); |
| | | |
| | | final int changeCount = |
| | | updateConfigFile(configFile.getPath(), Filter.valueOf(filter), |
| | | ChangeOperationType.MODIFY, ldif); |
| | | |
| | | displayChangeCount(configFile.getPath(), changeCount); |
| | | |
| | | context.notifyProgress(pnc.setProgress(100)); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | manageTaskException(context, Message.fromObject(e.getMessage()), |
| | | pnc); |
| | | } |
| | | perform0(summary, filter, ChangeOperationType.MODIFY, context, ldif); |
| | | } |
| | | } |
| | | |
| | | }; |
| | | } |
| | | |
| | | private static void perform0(final Message summary, final String filter, |
| | | final ChangeOperationType changeOperationType, |
| | | final UpgradeContext context, final String... ldif) |
| | | throws ClientException |
| | | { |
| | | displayTaskLogInformation(summary.toString(), filter, ldif); |
| | | |
| | | final ProgressNotificationCallback pnc = |
| | | new ProgressNotificationCallback(0, summary, 20); |
| | | |
| | | context.notifyProgress(pnc); |
| | | |
| | | try |
| | | { |
| | | final File configFile = |
| | | new File(configDirectory, Installation.CURRENT_CONFIG_FILE_NAME); |
| | | |
| | | final Filter filterVal = filter != null ? Filter.valueOf(filter) : null; |
| | | final int changeCount = |
| | | updateConfigFile(configFile.getPath(), filterVal, |
| | | changeOperationType, ldif); |
| | | |
| | | displayChangeCount(configFile.getPath(), changeCount); |
| | | |
| | | context.notifyProgress(pnc.setProgress(100)); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | manageTaskException(context, Message.fromObject(e.getMessage()), pnc); |
| | | } |
| | | } |
| | | |
| | | // Prevent instantiation. |
| | | private UpgradeTasks() |
| | |
| | | import static org.opends.server.tools.upgrade.FileManager.deleteRecursively; |
| | | import static org.opends.server.tools.upgrade.FileManager.rename; |
| | | import static org.opends.server.tools.upgrade.Installation.*; |
| | | import static org.opends.server.util.ChangeOperationType.*; |
| | | |
| | | /** |
| | | * Common utility methods needed by the upgrade. |
| | |
| | | /** |
| | | * Updates the config file during the upgrade process. |
| | | * |
| | | * |
| | | * @param configPath |
| | | * The original path to the file. |
| | | * @param filter |
| | | * The filter to avoid files. |
| | | * The filter to select entries. Only useful for modify change type. |
| | | * @param changeType |
| | | * The change type which must be applied to ldif lines. |
| | | * @param lines |
| | | * @param ldifLines |
| | | * The change record ldif lines. |
| | | * For ADD change type, the first line must be the dn. |
| | | * For DELETE change type, the first and only line must be the dn. |
| | | * @throws IOException |
| | | * If an Exception occurs during the input output methods. |
| | | * @return The changes number that have occurred. |
| | | */ |
| | | static int updateConfigFile(final String configPath, |
| | | final Filter filter, final ChangeOperationType changeType, |
| | | final String... lines) throws IOException |
| | | final String... ldifLines) throws IOException |
| | | { |
| | | final File original = new File(configPath); |
| | | final File copyConfig = |
| | |
| | | writer.writeComment(INFO_CONFIG_FILE_HEADER.get()); |
| | | writer.setWrapColumn(0); |
| | | |
| | | boolean alreadyExist = false; |
| | | String dn = null; |
| | | if (filter == null && changeType == ChangeOperationType.ADD) |
| | | boolean entryAlreadyExist = false; |
| | | DN ldifDN = null; |
| | | if (filter == null && (changeType == ADD || changeType == DELETE)) |
| | | { |
| | | // For an Add, the first line should start with dn: |
| | | dn = lines[0].replaceFirst("dn: ",""); |
| | | // The first line should start with dn: |
| | | ldifDN = DN.valueOf(ldifLines[0].replaceFirst("dn: ", "")); |
| | | } |
| | | final Matcher matcher = |
| | | filter != null ? filter.matcher(schema) : Filter.alwaysFalse() |
| | | .matcher(schema); |
| | | final Filter f = filter != null ? filter : Filter.alwaysFalse(); |
| | | final Matcher matcher = f.matcher(schema); |
| | | while (entryReader.hasNext()) |
| | | { |
| | | Entry entry = entryReader.readEntry(); |
| | | final DN entryDN = entry.getName(); |
| | | // Searching for the related entries |
| | | if (matcher.matches(entry) == ConditionResult.TRUE) |
| | | if (changeType == MODIFY |
| | | && matcher.matches(entry) == ConditionResult.TRUE) |
| | | { |
| | | try |
| | | { |
| | | final ModifyRequest mr = |
| | | Requests.newModifyRequest(readLDIFLines(entry.getName(), |
| | | changeType, lines)); |
| | | final ModifyRequest mr = Requests.newModifyRequest( |
| | | readLDIFLines(entryDN, changeType, ldifLines)); |
| | | entry = Entries.modifyEntryPermissive(entry, mr.getModifications()); |
| | | changeCount++; |
| | | LOG.log(Level.INFO, |
| | | String.format("The following entry has been modified : %s", |
| | | entry.getName())); |
| | | LOG.log(Level.INFO, String.format( |
| | | "The following entry has been modified : %s", entryDN)); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LOG.log(Level.SEVERE, ex.getMessage()); |
| | | } |
| | | } |
| | | if (dn != null // This is an ADD |
| | | && entry.getName().equals(DN.valueOf(dn))) |
| | | |
| | | if (entryDN.equals(ldifDN)) |
| | | { |
| | | LOG.log(Level.INFO, String.format("Entry %s found", entry.getName() |
| | | .toString())); |
| | | alreadyExist = true; |
| | | LOG.log(Level.INFO, String.format( |
| | | "Entry %s found", entryDN.toString())); |
| | | entryAlreadyExist = true; |
| | | |
| | | if (changeType == DELETE) |
| | | { |
| | | entry = null; |
| | | changeCount++; |
| | | LOG.log(Level.INFO, String.format( |
| | | "The following entry has been deleted : %s", entryDN)); |
| | | } |
| | | } |
| | | writer.writeEntry(entry); |
| | | |
| | | if (entry != null) |
| | | { |
| | | writer.writeEntry(entry); |
| | | } |
| | | } |
| | | |
| | | // If it's an ADD and the entry doesn't exist yet |
| | | if (dn != null && !alreadyExist) |
| | | if (changeType == ADD && !entryAlreadyExist) |
| | | { |
| | | final AddRequest ar = Requests.newAddRequest(lines); |
| | | final AddRequest ar = Requests.newAddRequest(ldifLines); |
| | | writer.writeEntry(ar); |
| | | LOG.log(Level.INFO, String.format("Entry successfully added %s in %s", |
| | | dn, original.getAbsolutePath())); |
| | | ldifDN, original.getAbsolutePath())); |
| | | changeCount++; |
| | | } |
| | | } |
| | |
| | | final String[] modifiedLines = new String[lines.length + 2]; |
| | | |
| | | int index = 0; |
| | | if (changeType == ChangeOperationType.MODIFY) |
| | | if (changeType == MODIFY) |
| | | { |
| | | modifiedLines[0] = "dn: " + dn; |
| | | modifiedLines[1] = "changetype: modify"; |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock, AS |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta.SaltedMD5PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.SaltedMD5PasswordStorageSchemeCfg; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.schema.UserPasswordSyntax; |
| | | import org.opends.server.types.ByteString; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.testng.Assert.assertTrue; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | /** |
| | | * A set of test cases for the salted MD5 password storage scheme. |
| | |
| | | super("cn=Salted MD5,cn=Password Storage Schemes,cn=config"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves an initialized instance of this password storage scheme. |
| | | * |
| | | * @return An initialized instance of this password storage scheme. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | protected PasswordStorageScheme getScheme() |
| | | throws Exception |
| | | protected PasswordStorageScheme getScheme() throws Exception |
| | | { |
| | | SaltedMD5PasswordStorageScheme scheme = |
| | | new SaltedMD5PasswordStorageScheme(); |
| | |
| | | |
| | | /** |
| | | * Tests matching with a different salt size. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test |
| | | public void testDifferentSaltSize() |
| | | throws Exception { |
| | | public void testDifferentSaltSize() throws Exception { |
| | | SaltedMD5PasswordStorageScheme scheme = |
| | | new SaltedMD5PasswordStorageScheme(); |
| | | |
| | |
| | | ByteString.valueOf("so5s1vK3oEi4uL/oVY3bqs5LRlKjgMN+u4A4bw=="))); |
| | | } |
| | | } |
| | | |