#include <log/logger_support.h>
#include <log/log_dbglevels.h>
+#include <auth/auth_srv.h>
+#include <auth/datasrc_config.h>
#include <cc/data.h>
+#include <datasrc/client_list.h>
+#include <dns/rrclass.h>
#include <auth/auth_log.h>
#include <boost/array.hpp>
#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
#include <list>
#include <utility>
/// \brief ID of commands from the DataSrcClientsMgr to DataSrcClientsBuilder.
enum CommandID {
NOOP, ///< Do nothing. Only useful for tests; no argument
+ RECONFIGURE, ///< Reconfigure the datasource client lists, configuration argument (TODO: describe here?)
SHUTDOWN, ///< Shutdown the builder; no argument
NUM_COMMANDS
};
typedef std::pair<CommandID, data::ConstElementPtr> Command;
} // namespace datasrc_clientmgr_internal
+typedef std::map<isc::dns::RRClass,
+ boost::shared_ptr<isc::datasrc::ConfigurableClientList> >
+ DataSrcClientListMap;
+
/// \brief Frontend to the manager object for data source clients.
///
/// This class provides interfaces for configuring and updating a set of
/// \throw std::bad_alloc internal memory allocation failure.
/// \throw isc::Unexpected general unexpected system errors.
DataSrcClientsMgrBase() :
- builder_(&command_queue_, &cond_, &queue_mutex_),
+ builder_(&command_queue_, &cond_, &queue_mutex_, &clients_map_, &map_mutex_),
builder_thread_(boost::bind(&BuilderType::run, &builder_))
{}
std::list<datasrc_clientmgr_internal::Command> command_queue_;
CondVarType cond_; // condition variable for queue operations
MutexType queue_mutex_; // mutex to protect the queue
-#ifdef notyet // until #2210 or #2212
- boost::shared_ptr<DataSrcClientListMap> clients_map_;
+ AuthSrv::DataSrcClientListsPtr clients_map_;
MutexType map_mutex_;
-#endif
BuilderType builder_;
ThreadType builder_thread_; // for safety this should be placed last
///
/// \throw None
DataSrcClientsBuilderBase(std::list<Command>* command_queue,
- CondVarType* cond, MutexType* queue_mutex
-#ifdef notyet
- // In #2210 or #2212 we pass other data
-#endif
+ CondVarType* cond, MutexType* queue_mutex,
+ AuthSrv::DataSrcClientListsPtr* clients_map,
+ MutexType* map_mutex
) :
- command_queue_(command_queue), cond_(cond), queue_mutex_(queue_mutex)
+ command_queue_(command_queue), cond_(cond), queue_mutex_(queue_mutex),
+ clients_map_(clients_map), map_mutex_(map_mutex)
{}
/// \brief The main loop.
// implementation really does nothing.
void doNoop() {}
+ void doReconfigure(const isc::data::ConstElementPtr& config) {
+ if (config) {
+ try {
+ AuthSrv::DataSrcClientListsPtr new_clients_map =
+ configureDataSource(config);
+ typename MutexType::Locker locker(*map_mutex_);
+ std::swap(new_clients_map, *clients_map_);
+ } catch (isc::data::TypeError) {
+ // TODO: log
+ std::cout << "[XX] type error" << std::endl;
+ } catch (std::exception stde) {
+ // TODO: log
+ std::cout << "[XX] bug error" << std::endl;
+ } catch (...) {
+ // TODO: log
+ std::cout << "[XX] unknown error" << std::endl;
+ }
+ }
+ // lock
+ }
+
// The following are shared with the manager
std::list<Command>* command_queue_;
CondVarType* cond_;
MutexType* queue_mutex_;
+ AuthSrv::DataSrcClientListsPtr* clients_map_;
+ MutexType* map_mutex_;
};
// Shortcut typedef for normal use
}
const boost::array<const char*, NUM_COMMANDS> command_desc = {
- {"NOOP", "SHUTDOWN"}
+ {"NOOP", "RECONFIGURE", "SHUTDOWN"}
};
LOG_DEBUG(auth_logger, DBGLVL_TRACE_BASIC,
AUTH_DATASRC_CLIENTS_BUILDER_COMMAND).arg(command_desc.at(cid));
switch (command.first) {
+ case RECONFIGURE:
+ doReconfigure(command.second);
+ break;
case SHUTDOWN:
return (false);
case NOOP:
class DataSrcClientsBuilderTest : public ::testing::Test {
protected:
DataSrcClientsBuilderTest() :
- builder(&command_queue, &cond, &queue_mutex),
+ builder(&command_queue, &cond, &queue_mutex, &clients_map, &map_mutex),
cond(command_queue, delayed_command_queue),
shutdown_cmd(SHUTDOWN, ConstElementPtr()),
noop_cmd(NOOP, ConstElementPtr())
TestDataSrcClientsBuilder builder;
std::list<Command> command_queue; // test command queue
std::list<Command> delayed_command_queue; // commands available after wait
+ AuthSrv::DataSrcClientListsPtr clients_map; // 'configured' clients
TestCondVar cond;
TestMutex queue_mutex;
+ TestMutex map_mutex;
const Command shutdown_cmd;
const Command noop_cmd;
};
EXPECT_EQ(2, queue_mutex.unlock_count);
}
+TEST_F(DataSrcClientsBuilderTest, reconfigure) {
+ // Full testing of different configurations is not here, but we
+ // do check a few cases of correct and erroneous input, to verify
+ // the error handling
+
+ // A command structure we'll modify to send different commands
+ Command reconfig_cmd(RECONFIGURE, ConstElementPtr());
+
+ // Initially, no clients should be there
+ EXPECT_EQ(AuthSrv::DataSrcClientListsPtr(), clients_map);
+
+ // A config that doesn't do much except be accepted
+ ConstElementPtr good_config = isc::data::Element::fromJSON(
+ "{"
+ "\"IN\": [{"
+ " \"type\": \"MasterFiles\","
+ " \"params\": {},"
+ " \"cache-enable\": true"
+ "}]"
+ "}"
+ );
+
+ reconfig_cmd.second = good_config;
+ EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+ EXPECT_EQ(1, clients_map->size());
+
+ // Store the nonempty clients map we now have
+ AuthSrv::DataSrcClientListsPtr working_config_clients(clients_map);
+
+ // If a 'bad' command argument got here, the config validation should
+ // have failed already, but still, the handler should return true,
+ // and the clients_map should not be updated.
+ reconfig_cmd.second = isc::data::Element::create("{ \"foo\": \"bar\" }");
+ EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+ EXPECT_EQ(working_config_clients, clients_map);
+
+ // The same goes for an empty parameter (it should at least be
+ // an empty map)
+ reconfig_cmd.second = ConstElementPtr();
+ EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+ EXPECT_EQ(working_config_clients, clients_map);
+
+ // Reconfigure again with the same good clients, the result should
+ // be a different map than the original, but not an empty one.
+ reconfig_cmd.second = good_config;
+ EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+ EXPECT_NE(working_config_clients, clients_map);
+ EXPECT_EQ(1, clients_map->size());
+
+ // And finally, try an empty config to disable all datasource clients
+ reconfig_cmd.second = isc::data::Element::createMap();
+ EXPECT_TRUE(builder.handleCommand(reconfig_cmd));
+ EXPECT_EQ(0, clients_map->size());
+}
+
TEST_F(DataSrcClientsBuilderTest, shutdown) {
EXPECT_FALSE(builder.handleCommand(shutdown_cmd));
}
+
TEST_F(DataSrcClientsBuilderTest, badCommand) {
// out-of-range command ID
EXPECT_THROW(builder.handleCommand(Command(NUM_COMMANDS,
// PERFORMANCE OF THIS SOFTWARE.
#include <exceptions/exceptions.h>
+#include <auth/datasrc_config.h>
#include "test_datasrc_clients_mgr.h"
TestCondVar* FakeDataSrcClientsBuilder::cond = NULL;
TestCondVar FakeDataSrcClientsBuilder::cond_copy;
TestMutex* FakeDataSrcClientsBuilder::queue_mutex = NULL;
+AuthSrv::DataSrcClientListsPtr* FakeDataSrcClientsBuilder::clients_map = NULL;
+TestMutex* FakeDataSrcClientsBuilder::map_mutex = NULL;
TestMutex FakeDataSrcClientsBuilder::queue_mutex_copy;
bool FakeDataSrcClientsBuilder::thread_waited = false;
FakeDataSrcClientsBuilder::ExceptionFromWait
#include <exceptions/exceptions.h>
#include <auth/datasrc_clients_mgr.h>
+#include <datasrc/datasrc_config.h>
#include <boost/function.hpp>
static std::list<Command>* command_queue;
static TestCondVar* cond;
static TestMutex* queue_mutex;
+ static AuthSrv::DataSrcClientListsPtr* clients_map;
+ static TestMutex* map_mutex;
static std::list<Command> command_queue_copy;
static TestCondVar cond_copy;
static TestMutex queue_mutex_copy;
FakeDataSrcClientsBuilder(
std::list<Command>* command_queue,
TestCondVar* cond,
- TestMutex* queue_mutex)
+ TestMutex* queue_mutex,
+ AuthSrv::DataSrcClientListsPtr* clients_map,
+ TestMutex* map_mutex)
{
FakeDataSrcClientsBuilder::started = false;
FakeDataSrcClientsBuilder::command_queue = command_queue;
FakeDataSrcClientsBuilder::cond = cond;
FakeDataSrcClientsBuilder::queue_mutex = queue_mutex;
+ FakeDataSrcClientsBuilder::clients_map = clients_map;
+ FakeDataSrcClientsBuilder::map_mutex = map_mutex;
FakeDataSrcClientsBuilder::thread_waited = false;
FakeDataSrcClientsBuilder::thread_throw_on_wait = NOTHROW;
}