Browse Source

[3534] It is now possible to revert to a selected previous configuration.

Marcin Siodelski 10 years ago
parent
commit
d630dfc753
3 changed files with 98 additions and 0 deletions
  1. 33 0
      src/lib/dhcpsrv/cfgmgr.cc
  2. 17 0
      src/lib/dhcpsrv/cfgmgr.h
  3. 48 0
      src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

+ 33 - 0
src/lib/dhcpsrv/cfgmgr.cc

@@ -396,6 +396,39 @@ CfgMgr::rollback() {
     }
 }
 
+void
+CfgMgr::revert(const size_t index) {
+    ensureCurrentAllocated();
+    if (index == 0) {
+        isc_throw(isc::OutOfRange, "invalid commit index 0 when reverting"
+                  " to an old configuration");
+    } else if (index > configs_.size() - 1) {
+        isc_throw(isc::OutOfRange, "unable to revert to commit index '"
+                  << index << "', only '" << configs_.size() - 1
+                  << "' previous commits available");
+    }
+
+    // Let's rollback an existing configuration to make sure that the last
+    // configuration on the list is the current one. Note that all remaining
+    // operations in this function should be exception free so there shouldn't
+    // be a problem that the revert operation fails and the staging
+    // configuration is destroyed by this rollback.
+    rollback();
+
+    // Get the iterator to the current configuration and then advance to the
+    // desired one.
+    ConfigurationList::const_reverse_iterator it = configs_.rbegin();
+    std::advance(it, index);
+
+    // Copy the desired configuration to the new staging configuration. The
+    // staging configuration is re-created here because we rolled back earlier
+    // in this function.
+    (*it)->copy(*getStagingCfg());
+
+    // Make the staging configuration a current one.
+    commit();
+}
+
 ConstConfigurationPtr
 CfgMgr::getCurrentCfg() {
     ensureCurrentAllocated();

+ 17 - 0
src/lib/dhcpsrv/cfgmgr.h

@@ -424,6 +424,23 @@ public:
     /// This function is exception safe.
     void rollback();
 
+    /// @brief Reverts to one of the previous configurations.
+    ///
+    /// This function reverts to selected previous configuration. The previous
+    /// configuration is entirely copied to a new @c Configuration instance. This
+    /// new instance has a unique sequence id (sequence id is not copied). The
+    /// previous configuration (being copied) is not modified by this operation.
+    ///
+    /// The configuration to be copied is identified by the index value which
+    /// is the distance between the current (most recent) and desired
+    /// configuration. If the index is out of range an exception is thrown.
+    ///
+    /// @warning Revert operation will rollback any changes to the staging
+    /// configuration (if it exists).
+    ///
+    /// @throw isc::OutOfRange if the specified index is out of range.
+    void revert(const size_t index);
+
     /// @brief Returns a pointer to the current configuration.
     ///
     /// This function returns pointer to the current configuration. If the

+ 48 - 0
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

@@ -1209,6 +1209,54 @@ TEST_F(CfgMgrTest, staging) {
     EXPECT_EQ(0, config->getLoggingInfo().size());
 }
 
+// This test verifies that it is possible to revert to an old configuration.
+TEST_F(CfgMgrTest, revert) {
+    CfgMgr& cfg_mgr = CfgMgr::instance();
+    // Let's create 5 unique configurations: differing by a debug level in the
+    // range of 10 to 14.
+    for (int i = 0; i < 5; ++i) {
+        ConfigurationPtr config = cfg_mgr.getStagingCfg();
+        LoggingInfo logging_info;
+        logging_info.debuglevel_ = i + 10;
+        config->addLoggingInfo(logging_info);
+        cfg_mgr.commit();
+    }
+
+    // Now we have 5 configurations with:
+    // - debuglevel = 99 (a default one)
+    // - debuglevel = 10
+    // - debuglevel = 11
+    // - debuglevel = 12
+    // - debuglevel = 13
+    // - debuglevel = 14 (current)
+
+    // Hence, the maximum index of the configuration to revert is 5 (which
+    // points to the configuration with debuglevel = 99). For the index greater
+    // than 5 we should get an exception.
+    ASSERT_THROW(cfg_mgr.revert(6), isc::OutOfRange);
+    // Value of 0 also doesn't make sense.
+    ASSERT_THROW(cfg_mgr.revert(0), isc::OutOfRange);
+
+    // We should be able to revert to configuration with debuglevel = 10.
+    ASSERT_NO_THROW(cfg_mgr.revert(4));
+    // And this configuration should be now the current one and the debuglevel
+    // of this configuration is 10.
+    EXPECT_EQ(10, cfg_mgr.getCurrentCfg()->getLoggingInfo()[0].debuglevel_);
+
+    // The new set of configuration is now as follows:
+    // - debuglevel = 99
+    // - debuglevel = 10
+    // - debuglevel = 11
+    // - debuglevel = 12
+    // - debuglevel = 13
+    // - debuglevel = 14
+    // - debuglevel = 10 (current)
+    // So, reverting to configuration having index 3 means that the debug level
+    // of the current configuration will become 12.
+    ASSERT_NO_THROW(cfg_mgr.revert(3));
+    EXPECT_EQ(12, cfg_mgr.getCurrentCfg()->getLoggingInfo()[0].debuglevel_);
+}
+
 /// @todo Add unit-tests for testing:
 /// - addActiveIface() with invalid interface name
 /// - addActiveIface() with the same interface twice