opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java
@@ -627,21 +627,29 @@ // and to take appropriate actions. DirectoryServer.notifyImportBeginning(backend, importConfig); // Disable the backend. /* * From here the listeners must be told that the import is over whichever way this * method returns: a listener which took something offline when it began - a * replication domain disables itself - gets no other chance to put it back. */ boolean backendDisabled = false; boolean successful = false; try { TaskUtils.disableBackend(backend.getBackendID()); } catch (DirectoryException e) { logger.traceException(e); // Disable the backend. try { TaskUtils.disableBackend(backend.getBackendID()); backendDisabled = true; } catch (DirectoryException e) { logger.traceException(e); logger.error(e.getMessageObject()); return TaskState.STOPPED_BY_ERROR; } logger.error(e.getMessageObject()); return TaskState.STOPPED_BY_ERROR; } try { // Acquire an exclusive lock for the backend. try { @@ -665,12 +673,12 @@ try { backend.importLDIF(importConfig, DirectoryServer.getInstance().getServerContext()); successful = true; } catch (DirectoryException de) { logger.traceException(de); DirectoryServer.notifyImportEnded(backend, importConfig, false); if (de.getResultCode().equals(DirectoryServer.getCoreConfigManager().getServerErrorResultCode())) { logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(de.getMessageObject())); @@ -685,7 +693,6 @@ { logger.traceException(e); DirectoryServer.notifyImportEnded(backend, importConfig, false); logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT, getExceptionMessage(e)); return TaskState.STOPPED_BY_ERROR; } @@ -713,23 +720,32 @@ } finally { // Enable the backend. try // Enable the backend, if it was this task which disabled it. boolean backendLeftDisabled = false; if (backendDisabled) { TaskUtils.enableBackend(backend.getBackendID()); // It is necessary to retrieve the backend structure again // because disabling and enabling it again may have resulted // in a new backend being registered to the server. backend = getServerContext().getBackendConfigManager().getLocalBackendById(backend.getBackendID()); } catch (DirectoryException e) { logger.traceException(e); try { TaskUtils.enableBackend(backend.getBackendID()); // It is necessary to retrieve the backend structure again // because disabling and enabling it again may have resulted // in a new backend being registered to the server. backend = getServerContext().getBackendConfigManager().getLocalBackendById(backend.getBackendID()); } catch (DirectoryException e) { logger.traceException(e); logger.error(e.getMessageObject()); logger.error(e.getMessageObject()); backendLeftDisabled = true; } } // Notified once, after the backend is back, so that a listener can read it again. DirectoryServer.notifyImportEnded(backend, importConfig, successful); if (backendLeftDisabled) { return TaskState.STOPPED_BY_ERROR; } DirectoryServer.notifyImportEnded(backend, importConfig, true); } // Clean up after the import by closing the import config. opendj-server-legacy/src/main/java/org/opends/server/tasks/RestoreTask.java
@@ -13,6 +13,7 @@ * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions Copyright 2014-2016 ForgeRock AS. * Portions Copyright 2026 3A Systems, LLC. */ package org.opends.server.tasks; @@ -262,25 +263,32 @@ // and to take appropriate actions. DirectoryServer.notifyRestoreBeginning(backend, restoreConfig); // Disable the backend. if ( !verifyOnly) { try { TaskUtils.disableBackend(backendID); } catch (DirectoryException e) { logger.traceException(e); logger.error(e.getMessageObject()); return TaskState.STOPPED_BY_ERROR; } } // From here we must make sure to re-enable the backend before returning. /* * From here the listeners must be told that the restore is over whichever way this * method returns: a listener which took something offline when it began - a * replication domain disables itself - gets no other chance to put it back. */ boolean backendDisabled = false; boolean errorsEncountered = false; try { // Disable the backend. From here the finally below re-enables it before returning. if ( !verifyOnly) { try { TaskUtils.disableBackend(backendID); backendDisabled = true; } catch (DirectoryException e) { logger.traceException(e); logger.error(e.getMessageObject()); errorsEncountered = true; return TaskState.STOPPED_BY_ERROR; } } // Acquire an exclusive lock for the backend. if (verifyOnly || lockBackend(backend)) { @@ -294,13 +302,11 @@ } catch (DirectoryException de) { DirectoryServer.notifyRestoreEnded(backend, restoreConfig, false); logger.error(ERR_RESTOREDB_ERROR_DURING_BACKUP, backupID, backupDir.getPath(), de.getMessageObject()); errorsEncountered = true; } catch (Exception e) { DirectoryServer.notifyRestoreEnded(backend, restoreConfig, false); logger.error(ERR_RESTOREDB_ERROR_DURING_BACKUP, backupID, backupDir.getPath(), getExceptionMessage(e)); errorsEncountered = true; } @@ -317,8 +323,8 @@ } finally { // Enable the backend. if (! verifyOnly) // Enable the backend, if it was this task which disabled it. if (backendDisabled) { try { @@ -335,7 +341,8 @@ errorsEncountered = true; } } DirectoryServer.notifyRestoreEnded(backend, restoreConfig, true); // Notified once, after the backend is back, so that a listener can read it again. DirectoryServer.notifyRestoreEnded(backend, restoreConfig, !errorsEncountered); } if (errorsEncountered) opendj-server-legacy/src/test/java/org/opends/server/tasks/TestImportAndExport.java
@@ -22,9 +22,11 @@ import org.forgerock.opendj.ldap.ResultCode; import org.opends.server.TestCaseUtils; import org.opends.server.api.LocalBackend; import org.opends.server.api.TestTaskListener; import org.opends.server.backends.task.TaskState; import org.opends.server.core.AddOperation; import org.opends.server.core.BackendConfigManager; import org.opends.server.core.DirectoryServer; import org.opends.server.types.Entry; import org.forgerock.opendj.ldap.schema.ObjectClass; @@ -383,6 +385,83 @@ } /** * An import which cannot disable its backend must still tell the import task listeners * that the import is over: a listener which took something offline when the import began * - a replication domain disables itself - has no other chance to put it back. */ @Test public void testImportEndsWhenTheBackendCannotBeDisabled() throws Exception { /* * A backend registered at runtime has no entry in cn=config, and disabling a backend * is a modification of that entry, so TaskUtils.disableBackend() cannot do it. */ final String backendID = "importTaskUnconfiguredBackend"; TestCaseUtils.initializeMemoryBackend(backendID, "dc=unconfigured,dc=com", true); try { int importBeginCount = TestTaskListener.importBeginCount.get(); int importEndCount = TestTaskListener.importEndCount.get(); Entry taskEntry = TestCaseUtils.makeEntry( "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks", "objectclass: top", "objectclass: ds-task", "objectclass: ds-task-import", "ds-task-class-name: org.opends.server.tasks.ImportTask", "ds-task-import-backend-id: " + backendID, "ds-task-import-ldif-file: " + ldifFile.getPath()); testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60); assertEquals(TestTaskListener.importBeginCount.get(), importBeginCount + 1); assertEquals(TestTaskListener.importEndCount.get(), importEndCount + 1); } finally { removeMemoryBackend(backendID); } } /** * A failed import must notify the listeners exactly once, as its beginning was notified * once: a replication domain enabled a second time reloads and rewinds its replication * state for nothing. */ @Test public void testFailedImportEndsOnlyOnce() throws Exception { int importBeginCount = TestTaskListener.importBeginCount.get(); int importEndCount = TestTaskListener.importEndCount.get(); // A directory can be read, so the task accepts it, but it cannot be read as LDIF. Entry taskEntry = TestCaseUtils.makeEntry( "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks", "objectclass: top", "objectclass: ds-task", "objectclass: ds-task-import", "ds-task-class-name: org.opends.server.tasks.ImportTask", "ds-task-import-backend-id: userRoot", "ds-task-import-ldif-file: " + ldifFile.getParent()); testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60); assertEquals(TestTaskListener.importBeginCount.get(), importBeginCount + 1); assertEquals(TestTaskListener.importEndCount.get(), importEndCount + 1); } private void removeMemoryBackend(String backendID) throws Exception { BackendConfigManager backendConfigManager = TestCaseUtils.getServerContext().getBackendConfigManager(); LocalBackend<?> backend = backendConfigManager.getLocalBackendById(backendID); if (backend != null) { backend.finalizeBackend(); backendConfigManager.deregisterLocalBackend(backend); } } /** * Add a task definition and check that it completes with the expected state. * @param taskEntry The task entry. * @param resultCode The expected result code of the task add.