From: Marcin Siodelski Date: Mon, 1 Sep 2014 15:32:47 +0000 (+0200) Subject: [3534] It is now possible to revert to a selected previous configuration. X-Git-Tag: trac3595_base~7^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d630dfc7534aa0ef808fc99586213fed0a179816;p=thirdparty%2Fkea.git [3534] It is now possible to revert to a selected previous configuration. --- diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc index 0176fc0e50..8145587b6d 100644 --- a/src/lib/dhcpsrv/cfgmgr.cc +++ b/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(); diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h index 1baaeab843..42509ee00e 100644 --- a/src/lib/dhcpsrv/cfgmgr.h +++ b/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 diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc index d3579f7e4f..5cc8c02fc2 100644 --- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc +++ b/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