From 3a2fb8fbf8b986016429073370d5fe41a23dc3c2 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Sun, 02 Sep 2007 01:12:13 +0000
Subject: [PATCH] Update the server so that it has the ability to save a copy of its current configuration into a ".startok" file whenever it starts successfully.  The start-ds script and DirectoryEnvironmentConfig class have been updated to expose an option to try to start the server using this "last known good" configuration rather than the active config file.

---
 opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java |  268 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 240 insertions(+), 28 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java b/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
index 54bfa16..228105f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -25,7 +25,6 @@
  *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
  */
 package org.opends.server.extensions;
-import org.opends.messages.Message;
 
 
 
@@ -60,6 +59,7 @@
 import javax.crypto.CipherOutputStream;
 import javax.crypto.Mac;
 
+import org.opends.messages.Message;
 import org.opends.server.api.AlertGenerator;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConfigAddListener;
@@ -135,6 +135,9 @@
   // Indicates whether to maintain a configuration archive.
   private boolean maintainConfigArchive;
 
+  // Indicates whether to start using the last known good configuration.
+  private boolean useLastKnownGoodConfig;
+
   // A SHA-1 digest of the last known configuration.  This should only be
   // incorrect if the server configuration file has been manually edited with
   // the server online, which is a bad thing.
@@ -199,15 +202,41 @@
     configLock = new ReentrantLock();
 
 
-    // Make sure that the configuration file exists.
+    // Determine whether we should try to start using the last known good
+    // configuration.  If so, then only do so if such a file exists.  If it
+    // doesn't exist, then fall back on the active configuration file.
     this.configFile = configFile;
-    File f = new File(configFile);
+    DirectoryEnvironmentConfig envConfig =
+         DirectoryServer.getEnvironmentConfig();
+    useLastKnownGoodConfig = envConfig.useLastKnownGoodConfiguration();
+    File f = null;
+    if (useLastKnownGoodConfig)
+    {
+      f = new File(configFile + ".startok");
+      if (! f.exists())
+      {
+        logError(WARN_CONFIG_FILE_NO_STARTOK_FILE.get(f.getAbsolutePath(),
+                                                      configFile));
+        useLastKnownGoodConfig = false;
+        f = new File(configFile);
+      }
+      else
+      {
+        logError(NOTE_CONFIG_FILE_USING_STARTOK_FILE.get(f.getAbsolutePath(),
+                                                         configFile));
+      }
+    }
+    else
+    {
+      f = new File(configFile);
+    }
 
     try
     {
       if (! f.exists())
       {
-        Message message = ERR_CONFIG_FILE_DOES_NOT_EXIST.get(configFile);
+        Message message = ERR_CONFIG_FILE_DOES_NOT_EXIST.get(
+                               f.getAbsolutePath());
         throw new InitializationException(message);
       }
     }
@@ -228,7 +257,7 @@
       }
 
       Message message = ERR_CONFIG_FILE_CANNOT_VERIFY_EXISTENCE.get(
-          configFile, String.valueOf(e));
+                             f.getAbsolutePath(), String.valueOf(e));
       throw new InitializationException(message);
     }
 
@@ -236,11 +265,9 @@
     // Check to see if a configuration archive exists.  If not, then create one.
     // If so, then check whether the current configuration matches the last
     // configuration in the archive.  If it doesn't, then archive it.
-    DirectoryEnvironmentConfig envConfig =
-         DirectoryServer.getEnvironmentConfig();
     maintainConfigArchive = envConfig.maintainConfigArchive();
     maxConfigArchiveSize  = envConfig.getMaxConfigArchiveSize();
-    if (maintainConfigArchive)
+    if (maintainConfigArchive & (! useLastKnownGoodConfig))
     {
       try
       {
@@ -307,7 +334,7 @@
     LDIFReader reader;
     try
     {
-      LDIFImportConfig importConfig = new LDIFImportConfig(configFile);
+      LDIFImportConfig importConfig = new LDIFImportConfig(f.getAbsolutePath());
 
       // FIXME -- Should we support encryption or compression for the config?
 
@@ -321,7 +348,7 @@
       }
 
       Message message = ERR_CONFIG_FILE_CANNOT_OPEN_FOR_READ.get(
-          configFile, String.valueOf(e));
+                             f.getAbsolutePath(), String.valueOf(e));
       throw new InitializationException(message, e);
     }
 
@@ -352,7 +379,7 @@
       }
 
       Message message = ERR_CONFIG_FILE_INVALID_LDIF_ENTRY.get(
-          le.getLineNumber(), configFile, String.valueOf(le));
+          le.getLineNumber(), f.getAbsolutePath(), String.valueOf(le));
       throw new InitializationException(message, le);
     }
     catch (Exception e)
@@ -375,7 +402,8 @@
       }
 
       Message message =
-          ERR_CONFIG_FILE_READ_ERROR.get(configFile, String.valueOf(e));
+          ERR_CONFIG_FILE_READ_ERROR.get(f.getAbsolutePath(),
+                                       String.valueOf(e));
       throw new InitializationException(message, e);
     }
 
@@ -395,7 +423,7 @@
         }
       }
 
-      Message message = ERR_CONFIG_FILE_EMPTY.get(configFile);
+      Message message = ERR_CONFIG_FILE_EMPTY.get(f.getAbsolutePath());
       throw new InitializationException(message);
     }
 
@@ -407,7 +435,8 @@
       if (! entry.getDN().equals(configRootDN))
       {
         Message message = ERR_CONFIG_FILE_INVALID_BASE_DN.get(
-            configFile, entry.getDN().toString(), DN_CONFIG_ROOT);
+                               f.getAbsolutePath(), entry.getDN().toString(),
+                               DN_CONFIG_ROOT);
         throw new InitializationException(message);
       }
     }
@@ -452,8 +481,8 @@
       }
 
       // This should not happen, so we can use a generic error here.
-      Message message =
-          ERR_CONFIG_FILE_GENERIC_ERROR.get(configFile, String.valueOf(e));
+      Message message = ERR_CONFIG_FILE_GENERIC_ERROR.get(f.getAbsolutePath(),
+                                                          String.valueOf(e));
       throw new InitializationException(message, e);
     }
 
@@ -494,7 +523,8 @@
         }
 
         Message message = ERR_CONFIG_FILE_INVALID_LDIF_ENTRY.get(
-            le.getLineNumber(), configFile, String.valueOf(le));
+                               le.getLineNumber(), f.getAbsolutePath(),
+                               String.valueOf(le));
         throw new InitializationException(message, le);
       }
       catch (Exception e)
@@ -516,8 +546,8 @@
           }
         }
 
-        Message message =
-            ERR_CONFIG_FILE_READ_ERROR.get(configFile, String.valueOf(e));
+        Message message = ERR_CONFIG_FILE_READ_ERROR.get(f.getAbsolutePath(),
+                                                         String.valueOf(e));
         throw new InitializationException(message, e);
       }
 
@@ -559,8 +589,9 @@
         }
 
         Message message = ERR_CONFIG_FILE_DUPLICATE_ENTRY.get(
-            entryDN.toString(), String.valueOf(reader.getLastEntryLineNumber()),
-                configFile);
+                               entryDN.toString(),
+                               String.valueOf(reader.getLastEntryLineNumber()),
+                               f.getAbsolutePath());
         throw new InitializationException(message);
       }
 
@@ -582,7 +613,9 @@
         }
 
         Message message = ERR_CONFIG_FILE_UNKNOWN_PARENT.get(
-            entryDN.toString(), reader.getLastEntryLineNumber(), configFile);
+                               entryDN.toString(),
+                               reader.getLastEntryLineNumber(),
+                               f.getAbsolutePath());
         throw new InitializationException(message);
       }
 
@@ -601,9 +634,9 @@
           }
         }
 
-        Message message = ERR_CONFIG_FILE_NO_PARENT.
-            get(entryDN.toString(), reader.getLastEntryLineNumber(), configFile,
-                parentDN.toString());
+        Message message = ERR_CONFIG_FILE_NO_PARENT.get(entryDN.toString(),
+                               reader.getLastEntryLineNumber(),
+                               f.getAbsolutePath(), parentDN.toString());
         throw new InitializationException(message);
       }
 
@@ -636,8 +669,8 @@
           }
         }
 
-        Message message =
-            ERR_CONFIG_FILE_GENERIC_ERROR.get(configFile, String.valueOf(e));
+        Message message = ERR_CONFIG_FILE_GENERIC_ERROR.get(f.getAbsolutePath(),
+                                                            String.valueOf(e));
         throw new InitializationException(message, e);
       }
     }
@@ -651,7 +684,7 @@
     {
       try
       {
-        File configDirFile = new File(configFile).getParentFile();
+        File configDirFile = f.getParentFile();
         if ((configDirFile != null) &&
             configDirFile.getName().equals(CONFIG_DIR_NAME))
         {
@@ -2265,6 +2298,185 @@
 
 
   /**
+   * {@inheritDoc}
+   */
+  public void writeSuccessfulStartupConfig()
+  {
+    if (useLastKnownGoodConfig)
+    {
+      // The server was started with the "last known good" configuration, so we
+      // shouldn't overwrite it with something that is probably bad.
+      return;
+    }
+
+
+    String startOKFilePath = configFile + ".startok";
+    String tempFilePath    = startOKFilePath + ".tmp";
+    String oldFilePath     = startOKFilePath + ".old";
+
+
+    // Copy the current config file to a temporary file.
+    File tempFile = new File(tempFilePath);
+    FileInputStream inputStream = null;
+    try
+    {
+      inputStream = new FileInputStream(configFile);
+
+      FileOutputStream outputStream = null;
+      try
+      {
+        outputStream = new FileOutputStream(tempFilePath, false);
+
+        try
+        {
+          byte[] buffer = new byte[8192];
+          while (true)
+          {
+            int bytesRead = inputStream.read(buffer);
+            if (bytesRead < 0)
+            {
+              break;
+            }
+
+            outputStream.write(buffer, 0, bytesRead);
+          }
+        }
+        catch (Exception e)
+        {
+          if (debugEnabled())
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+
+          logError(ERR_STARTOK_CANNOT_WRITE.get(configFile, tempFilePath,
+                                                getExceptionMessage(e)));
+          return;
+        }
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+
+        logError(ERR_STARTOK_CANNOT_OPEN_FOR_WRITING.get(tempFilePath,
+                      getExceptionMessage(e)));
+        return;
+      }
+      finally
+      {
+        try
+        {
+          outputStream.close();
+        }
+        catch (Exception e)
+        {
+          if (debugEnabled())
+          {
+            TRACER.debugCaught(DebugLogLevel.ERROR, e);
+          }
+        }
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      logError(ERR_STARTOK_CANNOT_OPEN_FOR_READING.get(configFile,
+                                                       getExceptionMessage(e)));
+      return;
+    }
+    finally
+    {
+      try
+      {
+        inputStream.close();
+      }
+      catch (Exception e)
+      {
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+      }
+    }
+
+
+    // If a ".startok" file already exists, then move it to an ".old" file.
+    File oldFile = new File(oldFilePath);
+    try
+    {
+      if (oldFile.exists())
+      {
+        oldFile.delete();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+    }
+
+    File startOKFile = new File(startOKFilePath);
+    try
+    {
+      if (startOKFile.exists())
+      {
+        startOKFile.renameTo(oldFile);
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+    }
+
+
+    // Rename the temp file to the ".startok" file.
+    try
+    {
+      tempFile.renameTo(startOKFile);
+    } catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      logError(ERR_STARTOK_CANNOT_RENAME.get(tempFilePath, startOKFilePath,
+                                             getExceptionMessage(e)));
+      return;
+    }
+
+
+    // Remove the ".old" file if there is one.
+    try
+    {
+      if (oldFile.exists())
+      {
+        oldFile.delete();
+      }
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+    }
+  }
+
+
+
+  /**
    * Retrieves the OIDs of the controls that may be supported by this backend.
    *
    * @return  The OIDs of the controls that may be supported by this backend.

--
Gitblit v1.10.0