const shared_ptr<TSIGKeyRing>* keyring_;
/// The data source client list
- shared_ptr<std::map<RRClass, shared_ptr<ConfigurableClientList> > >
- datasrc_client_lists_;
+ AuthSrv::DataSrcClientListsPtr datasrc_client_lists_;
shared_ptr<ConfigurableClientList> getClientList(const RRClass& rrclass) {
// TODO: Debug-build only check
}
}
+AuthSrv::DataSrcClientListsPtr
+AuthSrv::swapDataSrcClientLists(DataSrcClientListsPtr new_lists) {
+ {
+ thread::Mutex::Locker locker(impl_->mutex_);
+ std::swap(new_lists, impl_->datasrc_client_lists_);
+ }
+
+ return (new_lists);
+}
+
shared_ptr<ConfigurableClientList>
AuthSrv::getClientList(const RRClass& rrclass) {
return (impl_->getClientList(rrclass));
#ifndef __AUTH_SRV_H
#define __AUTH_SRV_H 1
-#include <string>
-
#include <config/ccsession.h>
+
#include <datasrc/factory.h>
+#include <datasrc/client_list.h>
+
#include <dns/message.h>
#include <dns/opcode.h>
#include <util/buffer.h>
#include <server_common/portconfig.h>
#include <auth/statistics.h>
+#include <boost/shared_ptr.hpp>
+
+#include <map>
+#include <string>
+
namespace isc {
namespace util {
namespace io {
boost::shared_ptr<isc::datasrc::ConfigurableClientList>&
list);
+ typedef boost::shared_ptr<std::map<
+ isc::dns::RRClass, boost::shared_ptr<
+ isc::datasrc::ConfigurableClientList> > >
+ DataSrcClientListsPtr;
+
+ DataSrcClientListsPtr swapDataSrcClientLists(DataSrcClientListsPtr
+ new_lists);
+
/// \brief Returns the currently used client list for the class.
///
/// \param rrclass The class for which to get the list.
#include <cc/data.h>
#include <datasrc/client_list.h>
-#include <util/threads/lock.h>
#include <boost/shared_ptr.hpp>
+#include <utility>
#include <set>
/// \brief Configure the authoritative server's data source lists
{
typedef boost::shared_ptr<List> ListPtr;
typedef std::map<std::string, isc::data::ConstElementPtr> Map;
- typedef std::pair<isc::dns::RRClass, ListPtr> RollbackPair;
- typedef std::pair<isc::dns::RRClass, isc::data::ConstElementPtr>
- RollbackConfiguration;
+ typedef std::map<isc::dns::RRClass, ListPtr> ListMap;
- // Lock the client lists, we're going to manipulate them.
- isc::util::thread::Mutex::Locker locker(server.getClientListMutex());
+ boost::shared_ptr<ListMap> new_lists(new ListMap);
- // Some structures to be able to perform a rollback
- std::vector<RollbackPair> rollback_sets;
- std::vector<RollbackConfiguration> rollback_configurations;
- try {
- // Get the configuration and current state.
- const Map& map(config->mapValue());
- const std::vector<isc::dns::RRClass>
- activeVector(server.getClientListClasses());
- std::set<isc::dns::RRClass> active(activeVector.begin(),
- activeVector.end());
- // Go through the configuration and change everything.
- for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
- const isc::dns::RRClass rrclass(it->first);
- active.erase(rrclass);
- ListPtr list(server.getClientList(rrclass));
- bool need_set(false);
- if (list) {
- rollback_configurations.
- push_back(RollbackConfiguration(rrclass,
- list->getConfiguration()));
- } else {
- list.reset(new List(rrclass));
- need_set = true;
- rollback_sets.push_back(RollbackPair(rrclass, ListPtr()));
- }
- list->configure(it->second, true);
- if (need_set) {
- server.setClientList(rrclass, list);
- }
- }
- // Remove the ones that are not in the configuration.
- for (std::set<isc::dns::RRClass>::iterator it(active.begin());
- it != active.end(); ++it) {
- // There seems to be no way the setClientList could throw.
- // But this is just to make sure in case it did to restore
- // the original.
- rollback_sets.push_back(
- RollbackPair(*it, server.getClientList(*it)));
- server.setClientList(*it, ListPtr());
- }
- } catch (...) {
- // Perform a rollback of the changes. The old configuration should
- // work.
- for (typename std::vector<RollbackPair>::const_iterator
- it(rollback_sets.begin()); it != rollback_sets.end(); ++it) {
- server.setClientList(it->first, it->second);
- }
- for (typename std::vector<RollbackConfiguration>::const_iterator
- it(rollback_configurations.begin());
- it != rollback_configurations.end(); ++it) {
- server.getClientList(it->first)->configure(it->second, true);
- }
- throw;
+ // Get the configuration and current state.
+ const Map& map(config->mapValue());
+
+ // Go through the configuration and create corresponding list.
+ for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
+ const isc::dns::RRClass rrclass(it->first);
+ ListPtr list(new List(rrclass));
+ list->configure(it->second, true);
+ new_lists->insert(std::pair<isc::dns::RRClass, ListPtr>(rrclass,
+ list));
}
+
+ // Replace the server's lists. By ignoring the return value we let the
+ // old lists be destroyed.
+ server.swapDataSrcClientLists(new_lists);
}
/// \brief Concrete version of configureDataSource() for the
#include "datasrc_util.h"
+#include <util/threads/lock.h>
+
#include <auth/auth_srv.h>
#include <auth/auth_config.h>
#include <auth/command.h>
class DatasrcConfigTest : public ::testing::Test {
public:
- // These pretend to be the server
- ListPtr getClientList(const RRClass& rrclass) {
- log_ += "get " + rrclass.toText() + "\n";
- return (lists_[rrclass]);
- }
- void setClientList(const RRClass& rrclass, const ListPtr& list) {
- log_ += "set " + rrclass.toText() + " " +
- (list ? list->getConf() : "") + "\n";
- lists_[rrclass] = list;
- }
- vector<RRClass> getClientListClasses() const {
- vector<RRClass> result;
- for (std::map<RRClass, ListPtr>::const_iterator it(lists_.begin());
- it != lists_.end(); ++it) {
- result.push_back(it->first);
+ // To pretend to be the server:
+ void swapDataSrcClientLists(shared_ptr<std::map<dns::RRClass, ListPtr> >
+ new_lists)
+ {
+ lists_.clear(); // first empty it
+
+ // Record the operation and results. Note that map elements are
+ // sorted by RRClass, so the ordering should be predictable.
+ for (std::map<dns::RRClass, ListPtr>::const_iterator it =
+ new_lists->begin();
+ it != new_lists->end();
+ ++it)
+ {
+ const RRClass rrclass = it->first;
+ ListPtr list = it->second;
+ log_ += "set " + rrclass.toText() + " " +
+ (list ? list->getConf() : "") + "\n";
+ lists_[rrclass] = list;
}
- return (result);
- }
- isc::util::thread::Mutex& getClientListMutex() const {
- return (mutex_);
}
+
protected:
DatasrcConfigTest() :
session(ElementPtr(new ListElement), ElementPtr(new ListElement),
session.addMessage(createCommand("config_update", config),
"data_sources", "*");
mccs->checkCommand();
- // Check it called the correct things (check that there's no IN yet and
- // set a new one.
- EXPECT_EQ("get IN\nset IN xxx\n", log_);
+ // Check that the passed config is stored.
+ EXPECT_EQ("set IN xxx\n", log_);
EXPECT_EQ(1, lists_.size());
}
FakeSession session;
}
TEST_F(DatasrcConfigTest, modifyList) {
- // First, initialize the list
+ // First, initialize the list, and confirm the current config
initializeINList();
+ EXPECT_EQ("xxx", lists_[RRClass::IN()]->getConf());
+
// And now change the configuration of the list
const ElementPtr
config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}]}"));
"*");
log_ = "";
mccs->checkCommand();
- // This one does not set
- EXPECT_EQ("get IN\n", log_);
- // But this should contain the yyy configuration
+ // Now the new one should be installed.
EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
EXPECT_EQ(1, lists_.size());
}
"*");
mccs->checkCommand();
// We have set commands for both classes.
- EXPECT_EQ("get CH\nset CH xxx\nget IN\nset IN yyy\n", log_);
+ EXPECT_EQ("set IN yyy\nset CH xxx\n", log_);
// We should have both there
EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
"*");
log_ = "";
mccs->checkCommand();
- // The CH is set, IN not
- EXPECT_EQ("get CH\nset CH xxx\nget IN\n", log_);
- // But this should contain the yyy configuration
+ EXPECT_EQ("set IN yyy\nset CH xxx\n", log_);
EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
EXPECT_EQ(2, lists_.size());
"*");
log_ = "";
mccs->checkCommand();
- EXPECT_EQ("get IN\nset IN \n", log_);
- EXPECT_FALSE(lists_[RRClass::IN()]);
- // In real auth server, the NULL one would be removed. However, we just
- // store it, so the IN bucket is still in there. This checks there's nothing
- // else.
- EXPECT_EQ(1, lists_.size());
+
+ // No operation takes place in the configuration, and the old one is
+ // just dropped
+ EXPECT_EQ("", log_);
+ EXPECT_TRUE(lists_.empty());
}
// Check that we can rollback an addition if something else fails