Commit d41d8af0 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[master] Merge branch 'trac2203'

parents daedcaea 44d9dfa8
......@@ -55,7 +55,7 @@ b10_auth_SOURCES += auth_config.cc auth_config.h
b10_auth_SOURCES += command.cc command.h
b10_auth_SOURCES += common.h common.cc
b10_auth_SOURCES += statistics.cc statistics.h
b10_auth_SOURCES += datasrc_configurator.h
b10_auth_SOURCES += datasrc_config.h datasrc_config.cc
b10_auth_SOURCES += main.cc
nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
......
......@@ -17,6 +17,7 @@ query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
query_bench_SOURCES += ../auth_config.h ../auth_config.cc
query_bench_SOURCES += ../statistics.h ../statistics.cc
query_bench_SOURCES += ../auth_log.h ../auth_log.cc
query_bench_SOURCES += ../datasrc_config.h ../datasrc_config.cc
nodist_query_bench_SOURCES = ../auth_messages.h ../auth_messages.cc
......
......@@ -30,7 +30,7 @@
#include <auth/auth_srv.h>
#include <auth/auth_config.h>
#include <auth/datasrc_configurator.h>
#include <auth/datasrc_config.h>
#include <auth/query.h>
#include <asiodns/asiodns.h>
......@@ -125,8 +125,8 @@ public:
OutputBuffer& buffer) :
QueryBenchMark(queries, query_message, buffer)
{
DataSourceConfigurator::testReconfigure(
server_.get(),
configureDataSource(
*server_,
Element::fromJSON("{\"IN\":"
" [{\"type\": \"sqlite3\","
" \"params\": {"
......@@ -139,13 +139,13 @@ class MemoryQueryBenchMark : public QueryBenchMark {
public:
MemoryQueryBenchMark(const char* const zone_file,
const char* const zone_origin,
const BenchQueries& queries,
Message& query_message,
OutputBuffer& buffer) :
const BenchQueries& queries,
Message& query_message,
OutputBuffer& buffer) :
QueryBenchMark(queries, query_message, buffer)
{
DataSourceConfigurator::testReconfigure(
server_.get(),
configureDataSource(
*server_,
Element::fromJSON("{\"IN\":"
" [{\"type\": \"MasterFiles\","
" \"cache-enable\": true, "
......
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <cc/data.h>
#include "auth_srv.h"
#include "datasrc_config.h"
// This is a trivial specialization for the commonly used version.
// Defined in .cc to avoid accidental creation of multiple copies.
void
configureDataSource(AuthSrv& server, const isc::data::ConstElementPtr& config)
{
return (configureDataSourceGeneric<AuthSrv,
isc::datasrc::ConfigurableClientList>(server, config));
}
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DATASRC_CONFIG_H
#define DATASRC_CONFIG_H
#include "auth_srv.h"
#include <cc/data.h>
#include <datasrc/client_list.h>
#include <util/threads/lock.h>
#include <boost/shared_ptr.hpp>
#include <set>
/// \brief Configure the authoritative server's data source lists
///
/// This will hook into the data_sources module configuration and it will
/// keep the local copy of data source clients in the list in the authoritative
/// server.
///
/// This function is templated. This is simply because of easier testing.
/// You don't need to pay attention to it, use the configureDataSource
/// specialization instead.
///
/// \param server It is the server to configure.
/// \param config The configuration value to parse. It is in the form
/// as an update from the config manager.
template<class Server, class List>
void
configureDataSourceGeneric(Server& server,
const isc::data::ConstElementPtr& config)
{
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;
// Lock the client lists, we're going to manipulate them.
isc::util::thread::Mutex::Locker locker(server.getClientListMutex());
// 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;
}
}
/// \brief Concrete version of configureDataSource() for the
/// use with authoritative server implementation.
void
configureDataSource(AuthSrv& server, const isc::data::ConstElementPtr& config);
#endif // DATASRC_CONFIG_H
// Local Variables:
// mode: c++
// End:
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DATASRC_CONFIGURATOR_H
#define DATASRC_CONFIGURATOR_H
#include "auth_srv.h"
#include <datasrc/client_list.h>
#include <config/ccsession.h>
#include <cc/data.h>
#include <util/threads/lock.h>
#include <set>
/// \brief A class to configure the authoritative server's data source lists
///
/// This will hook into the data_sources module configuration and it will
/// keep the local copy of data source clients in the list in the authoritative
/// server.
///
/// The class is slightly unusual. Due to some technical limitations, the hook
/// needs to be static method. Therefore it is not possible to create instances
/// of the class.
///
/// Also, the class is a template. This is simply because of easier testing.
/// You don't need to pay attention to it, use the DataSourceConfigurator
/// type alias instead.
template<class Server, class List>
class DataSourceConfiguratorGeneric {
private:
/// \brief Disallow creation of instances
DataSourceConfiguratorGeneric();
/// \brief Internal method to hook into the ModuleCCSession
///
/// It simply calls reconfigure.
static void reconfigureInternal(const std::string&,
isc::data::ConstElementPtr config,
const isc::config::ConfigData&)
{
if (config->contains("classes")) {
reconfigure(config->get("classes"));
}
}
static Server* server_;
static isc::config::ModuleCCSession* session_;
typedef boost::shared_ptr<List> ListPtr;
public:
/// \brief Initializes the class.
///
/// This configures which session and server should be used.
/// It hooks to the session now and downloads the configuration.
/// It is synchronous (it may block for some time).
///
/// Note that you need to call cleanup before the server or
/// session dies, otherwise it might access them after they
/// are destroyed.
///
/// \param session The session to hook into and to access the configuration
/// through.
/// \param server It is the server to configure.
/// \throw isc::InvalidOperation if this is called when already initialized.
/// \throw isc::InvalidParameter if any of the parameters is NULL
/// \throw isc::config::ModuleCCError if the remote configuration is not
/// available for some reason.
static void init(isc::config::ModuleCCSession* session,
Server* server)
{
if (session == NULL) {
isc_throw(isc::InvalidParameter, "The session must not be NULL");
}
if (server == NULL) {
isc_throw(isc::InvalidParameter, "The server must not be NULL");
}
if (server_ != NULL) {
isc_throw(isc::InvalidOperation,
"The configurator is already initialized");
}
server_ = server;
session_ = session;
session->addRemoteConfig("data_sources", reconfigureInternal, false);
}
/// \brief Deinitializes the class.
///
/// This detaches from the session and removes the server from internal
/// storage. The current configuration in the server is preserved.
///
/// This can be called even if it is not initialized currently. You
/// can initialize it again after this.
static void cleanup() {
if (session_ != NULL) {
session_->removeRemoteConfig("data_sources");
}
session_ = NULL;
server_ = NULL;
}
/// \brief Reads new configuration and replaces the old one.
///
/// It instructs the server to replace the lists with new ones as needed.
/// You don't need to call it directly (but you could, though the benefit
/// is unknown and it would be questionable at least). It is called
/// automatically on normal updates.
///
/// \param config The configuration value to parse. It is in the form
/// as an update from the config manager.
/// \throw InvalidOperation if it is called when not initialized.
static void reconfigure(const isc::data::ConstElementPtr& config) {
if (server_ == NULL) {
isc_throw(isc::InvalidOperation,
"Can't reconfigure while not initialized by init()");
}
// Lock the client lists, we're going to manipulate them.
isc::util::thread::Mutex::Locker locker(server_->getClientListMutex());
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;
// 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) {
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;
}
}
/// \brief Version of reconfigure for easier testing.
///
/// This method can be used to reconfigure a server without first
/// initializing the configurator. This does not need a session.
/// Otherwise, it acts the same as reconfigure.
///
/// This is not meant for production code. Do not use there.
///
/// \param server The server to configure.
/// \param config The config to use.
/// \throw isc::InvalidOperation if the configurator is initialized.
/// \throw anything that reconfigure does.
static void testReconfigure(Server* server,
const isc::data::ConstElementPtr& config)
{
if (server_ != NULL) {
isc_throw(isc::InvalidOperation, "Currently initialized.");
}
try {
server_ = server;
reconfigure(config);
server_ = NULL;
} catch (...) {
server_ = NULL;
throw;
}
}
};
template<class Server, class List>
isc::config::ModuleCCSession*
DataSourceConfiguratorGeneric<Server, List>::session_(NULL);
template<class Server, class List>
Server* DataSourceConfiguratorGeneric<Server, List>::server_(NULL);
/// \brief Concrete version of DataSourceConfiguratorGeneric for the
/// use in authoritative server.
typedef DataSourceConfiguratorGeneric<AuthSrv,
isc::datasrc::ConfigurableClientList>
DataSourceConfigurator;
#endif
......@@ -14,17 +14,6 @@
#include <config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <cassert>
#include <iostream>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
......@@ -45,13 +34,26 @@
#include <auth/command.h>
#include <auth/auth_srv.h>
#include <auth/auth_log.h>
#include <auth/datasrc_configurator.h>
#include <auth/datasrc_config.h>
#include <asiodns/asiodns.h>
#include <asiolink/asiolink.h>
#include <log/logger_support.h>
#include <server_common/keyring.h>
#include <server_common/socket_request.h>
#include <boost/bind.hpp>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <cassert>
#include <iostream>
using namespace std;
using namespace isc::asiodns;
using namespace isc::asiolink;
......@@ -70,7 +72,7 @@ namespace {
/* need global var for config/command handlers.
* todo: turn this around, and put handlers in the authserver
* class itself? */
AuthSrv *auth_server;
AuthSrv* auth_server;
ConstElementPtr
my_config_handler(ConstElementPtr new_config) {
......@@ -83,6 +85,29 @@ my_command_handler(const string& command, ConstElementPtr args) {
return (execAuthServerCommand(*auth_server, command, args));
}
void
datasrcConfigHandler(AuthSrv* server, bool* first_time,
ModuleCCSession* config_session, const std::string&,
isc::data::ConstElementPtr config,
const isc::config::ConfigData&)
{
assert(server != NULL);
if (config->contains("classes")) {
if (*first_time) {
// HACK: The default is not passed to the handler in the first
// callback. This one will get the default (or, current value).
// Further updates will work the usual way.
assert(config_session != NULL);
*first_time = false;
configureDataSource(*auth_server,
config_session->getRemoteConfigValue(
"data_sources", "classes"));
} else {
configureDataSource(*server, config->get("classes"));
}
}
}
void
usage() {
cerr << "Usage: b10-auth [-v]"
......@@ -191,13 +216,15 @@ main(int argc, char* argv[]) {
isc::server_common::initKeyring(*config_session);
auth_server->setTSIGKeyRing(&isc::server_common::keyring);
// Start the data source configuration
DataSourceConfigurator::init(config_session, auth_server);
// HACK: The default is not passed to the handler. This one will
// get the default (or, current value). Further updates will work
// the usual way.
DataSourceConfigurator::reconfigure(
config_session->getRemoteConfigValue("data_sources", "classes"));
// Start the data source configuration. We pass first_time and
// config_session for the hack described in datasrcConfigHandler.
bool first_time = true;
config_session->addRemoteConfig("data_sources",
boost::bind(datasrcConfigHandler,
auth_server, &first_time,
config_session,
_1, _2, _3),
false);
// Now start asynchronous read.
config_session->start();
......@@ -221,7 +248,10 @@ main(int argc, char* argv[]) {
xfrin_session->disconnect();
}
DataSourceConfigurator::cleanup();
// If we haven't registered callback for data sources, this will be just
// no-op.
config_session->removeRemoteConfig("data_sources");
delete xfrin_session;
delete config_session;
delete cc_session;
......
......@@ -42,6 +42,7 @@ run_unittests_SOURCES += ../auth_config.h ../auth_config.cc
run_unittests_SOURCES += ../command.h ../command.cc
run_unittests_SOURCES += ../common.h ../common.cc
run_unittests_SOURCES += ../statistics.h ../statistics.cc
run_unittests_SOURCES += ../datasrc_config.h ../datasrc_config.cc
run_unittests_SOURCES += datasrc_util.h datasrc_util.cc
run_unittests_SOURCES += auth_srv_unittest.cc
run_unittests_SOURCES += config_unittest.cc
......@@ -50,7 +51,7 @@ run_unittests_SOURCES += command_unittest.cc
run_unittests_SOURCES += common_unittest.cc
run_unittests_SOURCES += query_unittest.cc
run_unittests_SOURCES += statistics_unittest.cc
run_unittests_SOURCES += datasrc_configurator_unittest.cc
run_unittests_SOURCES += datasrc_config_unittest.cc
run_unittests_SOURCES += run_unittests.cc
nodist_run_unittests_SOURCES = ../auth_messages.h ../auth_messages.cc
......
......@@ -36,7 +36,7 @@
#include <auth/command.h>
#include <auth/common.h>
#include <auth/statistics.h>
#include <auth/datasrc_configurator.h>
#include <auth/datasrc_config.h>
#include <util/unittests/mock_socketsession.h>
#include <util/threads/lock.h>
......@@ -722,17 +722,17 @@ TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
}
void
updateDatabase(AuthSrv* server, const char* params) {
updateDatabase(AuthSrv& server, const char* params) {
const ConstElementPtr config(Element::fromJSON("{"
"\"IN\": [{"
" \"type\": \"sqlite3\","
" \"params\": " + string(params) +
"}]}"));
DataSourceConfigurator::testReconfigure(server, config);
configureDataSource(server, config);
}
void
updateInMemory(AuthSrv* server, const char* origin, const char* filename) {
updateInMemory(AuthSrv& server, const char* origin, const char* filename) {
const ConstElementPtr config(Element::fromJSON("{"
"\"IN\": [{"
" \"type\": \"MasterFiles\","
......@@ -745,17 +745,17 @@ updateInMemory(AuthSrv* server, const char* origin, const char* filename) {
" \"type\": \"static\","
" \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
"}]}"));
DataSourceConfigurator::testReconfigure(server, config);
configureDataSource(server, config);
}
void
updateBuiltin(AuthSrv* server) {
updateBuiltin(AuthSrv& server) {
const ConstElementPtr config(Element::fromJSON("{"
"\"CH\": [{"
" \"type\": \"static\","
" \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
"}]}"));
DataSourceConfigurator::testReconfigure(server, config);
configureDataSource(server, config);
}