mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
02.41.2007 8ff034142142a3103f6e84e0c50fb6d77328c854
Provide new directory environment properties that can be used to indicate
whether the server should maintain a configuration archvie, and if so the
maximum number of archived configurations that it should keep. By default, the
archive will be enabled and will be configured to keep an unlimited number of
previous configurations.

This needs to be controlled via a directory environment property rather than a
configuration option, since first part of configuration archive processing
happens before the server has read and processed the configuration. The
DirectoryEnvironmentConfig class provides methods for interacting with these
settings.
3 files modified
378 ■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java 194 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/types/DirectoryEnvironmentConfig.java 162 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java 22 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -44,6 +44,7 @@
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
import java.util.TreeMap;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
@@ -76,6 +77,7 @@
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.schema.GeneralizedTimeSyntax;
import org.opends.server.tools.LDIFModify;
import org.opends.server.types.DirectoryEnvironmentConfig;
import org.opends.server.types.*;
@@ -130,6 +132,9 @@
  // Indicates whether to maintain a configuration archive.
  private boolean maintainConfigArchive;
  // 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.
@@ -145,6 +150,9 @@
  // The set of base DNs for this config handler backend.
  private DN[] baseDNs;
  // The maximum config archive size to maintain.
  private int maxConfigArchiveSize;
  // The write lock used to ensure that only one thread can apply a
  // configuration update at any given time.
  private ReentrantLock configLock;
@@ -228,30 +236,37 @@
    // 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.
    try
    {
      configurationDigest = calculateConfigDigest();
    }
    catch (DirectoryException de)
    {
      throw new InitializationException(de.getMessageObject(), de.getCause());
    }
    File archiveDirectory = new File(f.getParent(), CONFIG_ARCHIVE_DIR_NAME);
    if (archiveDirectory.exists())
    DirectoryEnvironmentConfig envConfig =
         DirectoryServer.getEnvironmentConfig();
    maintainConfigArchive = envConfig.maintainConfigArchive();
    maxConfigArchiveSize  = envConfig.getMaxConfigArchiveSize();
    if (maintainConfigArchive)
    {
      try
      {
        byte[] lastDigest = getLastConfigDigest(archiveDirectory);
        if (! Arrays.equals(configurationDigest, lastDigest))
        configurationDigest = calculateConfigDigest();
      }
      catch (DirectoryException de)
      {
        throw new InitializationException(de.getMessageObject(), de.getCause());
      }
      File archiveDirectory = new File(f.getParent(), CONFIG_ARCHIVE_DIR_NAME);
      if (archiveDirectory.exists())
      {
        try
        {
          writeConfigArchive();
        }
      } catch (Exception e) {}
    }
    else
    {
      writeConfigArchive();
          byte[] lastDigest = getLastConfigDigest(archiveDirectory);
          if (! Arrays.equals(configurationDigest, lastDigest))
          {
            writeConfigArchive();
          }
        } catch (Exception e) {}
      }
      else
      {
        writeConfigArchive();
      }
    }
@@ -267,8 +282,11 @@
      if (changesFile.exists())
      {
        applyChangesFile(f, changesFile);
        configurationDigest = calculateConfigDigest();
        writeConfigArchive();
        if (maintainConfigArchive)
        {
          configurationDigest = calculateConfigDigest();
          writeConfigArchive();
        }
      }
    }
    catch (Exception e)
@@ -628,7 +646,7 @@
    // Determine the appropriate server root.  If it's not defined in the
    // environment config, then try to figure it out from the location of the
    // configuration file.
    File rootFile = DirectoryServer.getEnvironmentConfig().getServerRoot();
    File rootFile = envConfig.getServerRoot();
    if (rootFile == null)
    {
      try
@@ -1952,61 +1970,64 @@
    // copy the current config off to the side before writing the new config
    // so that the manual changes don't get lost but also don't get applied.
    // Also, send an admin alert notifying administrators about the problem.
    try
    if (maintainConfigArchive)
    {
      byte[] currentDigest = calculateConfigDigest();
      if (! Arrays.equals(configurationDigest, currentDigest))
      try
      {
        File existingCfg   = new File(configFile);
        File newConfigFile = new File(existingCfg.getParent(),
                                      "config.manualedit-" +
                                           TimeThread.getGMTTime() + ".ldif");
        int counter = 2;
        while (newConfigFile.exists())
        byte[] currentDigest = calculateConfigDigest();
        if (! Arrays.equals(configurationDigest, currentDigest))
        {
          newConfigFile = new File(newConfigFile.getAbsolutePath() + "." +
                                   counter++);
        }
        FileInputStream  inputStream  = new FileInputStream(existingCfg);
        FileOutputStream outputStream = new FileOutputStream(newConfigFile);
        byte[] buffer = new byte[8192];
        while (true)
        {
          int bytesRead = inputStream.read(buffer);
          if (bytesRead < 0)
          File existingCfg   = new File(configFile);
          File newConfigFile = new File(existingCfg.getParent(),
                                        "config.manualedit-" +
                                             TimeThread.getGMTTime() + ".ldif");
          int counter = 2;
          while (newConfigFile.exists())
          {
            break;
            newConfigFile = new File(newConfigFile.getAbsolutePath() + "." +
                                     counter++);
          }
          outputStream.write(buffer, 0, bytesRead);
          FileInputStream  inputStream  = new FileInputStream(existingCfg);
          FileOutputStream outputStream = new FileOutputStream(newConfigFile);
          byte[] buffer = new byte[8192];
          while (true)
          {
            int bytesRead = inputStream.read(buffer);
            if (bytesRead < 0)
            {
              break;
            }
            outputStream.write(buffer, 0, bytesRead);
          }
          inputStream.close();
          outputStream.close();
          Message message = WARN_CONFIG_MANUAL_CHANGES_DETECTED.get(
              configFile, newConfigFile.getAbsolutePath());
          logError(message);
          DirectoryServer.sendAlertNotification(this,
               ALERT_TYPE_MANUAL_CONFIG_EDIT_HANDLED, message);
        }
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        inputStream.close();
        outputStream.close();
        Message message = WARN_CONFIG_MANUAL_CHANGES_DETECTED.get(
            configFile, newConfigFile.getAbsolutePath());
        Message message = ERR_CONFIG_MANUAL_CHANGES_LOST.get(
            configFile, stackTraceToSingleLineString(e));
        logError(message);
        DirectoryServer.sendAlertNotification(this,
             ALERT_TYPE_MANUAL_CONFIG_EDIT_HANDLED, message);
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_CONFIG_MANUAL_CHANGES_LOST.get(
          configFile, stackTraceToSingleLineString(e));
      logError(message);
      DirectoryServer.sendAlertNotification(this,
           ALERT_TYPE_MANUAL_CONFIG_EDIT_HANDLED, message);
    }
    // Write the new configuration to a temporary file.
@@ -2064,7 +2085,10 @@
    // Try to write the archive for the new configuration.
    writeConfigArchive();
    if (maintainConfigArchive)
    {
      writeConfigArchive();
    }
  }
@@ -2075,6 +2099,11 @@
   */
  private void writeConfigArchive()
  {
    if (! maintainConfigArchive)
    {
      return;
    }
    // Determine the path to the directory that will hold the archived
    // configuration files.
    File configDirectory  = new File(configFile).getParentFile();
@@ -2196,6 +2225,41 @@
        outputStream.close();
      } catch (Exception e) {}
    }
    // If we should enforce a maximum number of archived configurations, then
    // see if there are any old ones that we need to delete.
    if (maxConfigArchiveSize > 0)
    {
      String[] archivedFileList = archiveDirectory.list();
      int numToDelete = archivedFileList.length - maxConfigArchiveSize;
      if (numToDelete > 0)
      {
        TreeSet<String> archiveSet = new TreeSet<String>();
        for (String name : archivedFileList)
        {
          if (! name.startsWith("config-"))
          {
            continue;
          }
          // Simply ordering by filename should work, even when there are
          // timestamp conflicts, because the dash comes before the period in
          // the ASCII character set.
          archiveSet.add(name);
        }
        Iterator<String> iterator = archiveSet.iterator();
        for (int i=0; ((i < numToDelete) && iterator.hasNext()); i++)
        {
          File f = new File(archiveDirectory, iterator.next());
          try
          {
            f.delete();
          } catch (Exception e) {}
        }
      }
    }
  }
opendj-sdk/opends/src/server/org/opends/server/types/DirectoryEnvironmentConfig.java
@@ -470,6 +470,168 @@
  /**
   * Indicates whether the Directory Server should maintain an archive
   * of previous configurations.  If no explicit value is defined,
   * then a default result of {@code true} will be returned.
   *
   * @return  {@code true} if the Directory Server should maintain an
   *          archive of previous configurations, or {@code false} if
   *          not.
   */
  public boolean maintainConfigArchive()
  {
    String maintainArchiveStr =
         getProperty(PROPERTY_MAINTAIN_CONFIG_ARCHIVE);
    if (maintainArchiveStr == null)
    {
      return true;
    }
    return (! maintainArchiveStr.equalsIgnoreCase("false"));
  }
  /**
   * Specifies whether the Directory Server should maintain an archive
   * of previous configurations.
   *
   * @param  maintainConfigArchive  Indicates whether the Directory
   *                                Server should maintain an archive
   *                                of previous configurations.
   *
   * @return  The previous setting for this configuration option.  If
   *          no previous value was specified, then {@code true} will
   *          be returned.
   *
   * @throws  InitializationException  If the Directory Server is
   *                                   already running.
   */
  public boolean setMaintainConfigArchive(
                      boolean maintainConfigArchive)
         throws InitializationException
  {
    if (DirectoryServer.isRunning())
    {
      throw new InitializationException(
              ERR_DIRCFG_SERVER_ALREADY_RUNNING.get());
    }
    String oldMaintainStr =
         setProperty(PROPERTY_MAINTAIN_CONFIG_ARCHIVE,
                     String.valueOf(maintainConfigArchive));
    if (oldMaintainStr == null)
    {
      return true;
    }
    else
    {
      return (! oldMaintainStr.equalsIgnoreCase("false"));
    }
  }
  /**
   * Retrieves the maximum number of archived configurations that the
   * Directory Server should maintain.  If no value is defined, then a
   * value of zero will be returned.
   *
   * @return  The maximum number of archived configurations that the
   *          Directory Server should maintain, or zero if there
   *          should not be any limit.
   */
  public int getMaxConfigArchiveSize()
  {
    String maxSizeStr =
         getProperty(PROPERTY_MAX_CONFIG_ARCHIVE_SIZE);
    if (maxSizeStr == null)
    {
      return 0;
    }
    try
    {
      int maxSize = Integer.parseInt(maxSizeStr);
      if (maxSize > 0)
      {
        return maxSize;
      }
      else
      {
        return 0;
      }
    }
    catch (Exception e)
    {
      return 0;
    }
  }
  /**
   * Specifies the maximum number of archived configurations that the
   * Directory Server should maintain.  A value that is less than or
   * equal to zero may be used to indicate that there should not be
   * any limit to the number of archived configurations.
   *
   * @param  maxConfigArchiveSize  The maximum number of archived
   *                               configurations that the Directory
   *                               Server should maintain.
   *
   * @return  The previous setting for this configuration option.  If
   *          no previous value was specified, then zero will be
   *          returned.
   *
   * @throws  InitializationException  If the Directory Server is
   *                                   already running.
   */
  public int setMaxConfigArchiveSize(int maxConfigArchiveSize)
         throws InitializationException
  {
    if (DirectoryServer.isRunning())
    {
      throw new InitializationException(
              ERR_DIRCFG_SERVER_ALREADY_RUNNING.get());
    }
    if (maxConfigArchiveSize < 0)
    {
      maxConfigArchiveSize = 0;
    }
    String oldMaxSizeStr =
         setProperty(PROPERTY_MAX_CONFIG_ARCHIVE_SIZE,
                     String.valueOf(maxConfigArchiveSize));
    if (oldMaxSizeStr == null)
    {
      return 0;
    }
    else
    {
      try
      {
        int oldMaxSize = Integer.parseInt(oldMaxSizeStr);
        if (oldMaxSize > 0)
        {
          return oldMaxSize;
        }
        else
        {
          return 0;
        }
      }
      catch (Exception e)
      {
        return 0;
      }
    }
  }
  /**
   * Retrieves the directory that contains the server schema
   * configuration files.  If no value is defined, but a default
   * directory of "config/schema" exists below the server root, then
opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -2531,6 +2531,28 @@
  /**
   * The name of the system property that can be used to determine whether the
   * server should maintain an archive of previous configurations.  If this is
   * not set, or if the value is anything other than "false", then the server
   * will maintain a configuration archive.
   */
  public static final String PROPERTY_MAINTAIN_CONFIG_ARCHIVE =
       "org.opends.server.MaintainConfigArchive";
  /**
   * The name of the system property that can be used to specify the maximum
   * number of archived configurations to maintain.  If this is not set, or if
   * it set to a zero or negative value, then there will be no limit on the
   * number of archived configurations.
   */
  public static final String PROPERTY_MAX_CONFIG_ARCHIVE_SIZE =
       "org.opends.server.MaxConfigArchiveSize";
  /**
   * The name of the system property that can be used to determine whether the
   * Directory Server is starting up for the purpose of running the unit tests.
   */
  public static final String PROPERTY_RUNNING_UNIT_TESTS =