Browse Source

make auth_srv use the Auth/database_file setting
if not set, the hardcoded default is used
Added removeDataSrc(ConstDataSrcPtr) to remove a running one (auth_srv has a copy of the currently running sqlite datasrcptr to keep track of this)
added test for addDataSrc and removeDataSrc (for which is also added an dataSrcCount() function)
removed zone_list from auth.spec to avoid confusion
updated ccsession to give a better error when there is something wrong (like a bad .spec file)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1203 e5f2f494-b856-4b98-b285-d166d9295462

Jelte Jansen 15 years ago
parent
commit
784ae3c558

+ 1 - 13
src/bin/auth/auth.spec

@@ -4,19 +4,7 @@
     "config_data": [
       { "item_name": "database_file",
         "item_type": "string",
-        "item_optional": False,
-        "item_default": "b10-auth.db"
-      },
-      { "item_name": "zone_list",
-        "item_type": "list",
-        "item_optional": False,
-        "item_default": [],
-        "list_item_spec":
-          { "item_name": "zone_name",
-            "item_type": "string",
-            "item_optional": True,
-            "item_default": ""
-          }
+        "item_optional": True
       }
     ],
     "commands": [

+ 43 - 14
src/bin/auth/auth_srv.cc

@@ -32,6 +32,8 @@
 #include <dns/rrttl.h>
 #include <dns/message.h>
 #include <config/ccsession.h>
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
 
 #include <auth/query.h>
 #include <auth/data_source.h>
@@ -65,18 +67,17 @@ public:
 };
 
 AuthSrvImpl::AuthSrvImpl() {
-    // add static data source
-    data_sources.addDataSrc(ConstDataSrcPtr(new StaticDataSrc));
-
-    // add SQL data source
-    Sqlite3DataSrc* sd = new Sqlite3DataSrc;
-    sd->init();
-    data_sources.addDataSrc(ConstDataSrcPtr(sd));
 }
 
 AuthSrv::AuthSrv()
 {
     impl_ = new AuthSrvImpl;
+    // set empty (sqlite) data source, once ccsession is up
+    // the datasource will be set by the configuration setting
+    // (or the default one if none is set)
+    cur_datasrc_ = ConstDataSrcPtr();
+    // add static data source
+    impl_->data_sources.addDataSrc(ConstDataSrcPtr(new StaticDataSrc));
 }
 
 AuthSrv::~AuthSrv()
@@ -133,24 +134,52 @@ AuthSrv::processMessage(const int fd)
     }
 }
 
-void
-AuthSrv::setDbFile(const std::string& db_file)
+ElementPtr
+AuthSrv::setDbFile(const isc::data::ElementPtr config)
 {
-    cout << "Change data source file, call our data source's function to now read " << db_file << endl;
-    impl_->_db_file = db_file;
+    if (config) {
+        impl_->_db_file = config->get("database_file")->stringValue();
+        cout << "[AuthSrv] Data source database file: " << impl_->_db_file << endl;
+    }
+
+    try {
+        // create SQL data source
+        // config may be empty here; in that case it will load the default
+        // database file
+        Sqlite3DataSrc* sd = new Sqlite3DataSrc;
+        sd->init(config);
+
+        if (cur_datasrc_) {
+            impl_->data_sources.removeDataSrc(cur_datasrc_);
+        }
+
+        ConstDataSrcPtr csd = ConstDataSrcPtr(sd);
+        impl_->data_sources.addDataSrc(csd);
+        cur_datasrc_ = csd;
+
+        return isc::config::createAnswer(0);
+    } catch (isc::Exception error) {
+        cout << "[AuthSrv] error: " << error.what() << endl;
+        return isc::config::createAnswer(1, error.what());
+    }
 }
 
 ElementPtr
 AuthSrv::updateConfig(isc::data::ElementPtr new_config)
 {
+    ElementPtr answer = isc::config::createAnswer(0);
     if (new_config) {
         // the ModuleCCSession has already checked if we have
         // the correct ElementPtr type as specified in our .spec file
         if (new_config->contains("database_file")) {
-            // We only get this if the value has actually changed.
-            setDbFile(new_config->get("database_file")->stringValue());
+            answer = setDbFile(new_config);
         }
     }
+
+    // if we have no sqlite3 data source, use the default
+    if (!cur_datasrc_) {
+        setDbFile(ElementPtr());
+    }
     
-    return isc::config::createAnswer(0);
+    return answer;
 }

+ 6 - 1
src/bin/auth/auth_srv.h

@@ -20,6 +20,7 @@
 #include <string>
 
 #include <cc/data.h>
+#include <auth/data_source.h>
 
 class AuthSrvImpl;
 
@@ -39,10 +40,14 @@ public:
     //@}
     void processMessage(int fd);
     void serve(std::string zone_name);
-    void setDbFile(const std::string& db_file);
+    isc::data::ElementPtr setDbFile(const isc::data::ElementPtr config);
     isc::data::ElementPtr updateConfig(isc::data::ElementPtr config);
 private:
     AuthSrvImpl* impl_;
+    /// We keep a pointer to the currently running sqlite datasource
+    /// so that we can specifically remove that one should the database
+    /// file change
+    isc::auth::ConstDataSrcPtr cur_datasrc_;
 };
 
 #endif // __AUTH_SRV_H

+ 1 - 3
src/bin/auth/main.cc

@@ -67,15 +67,13 @@ usage() {
 ElementPtr
 my_config_handler(ElementPtr new_config)
 {
-    auth_server->updateConfig(new_config);
-    return createAnswer(0);
+    return auth_server->updateConfig(new_config);
 }
 
 ElementPtr
 my_command_handler(const string& command, const ElementPtr args) {
     ElementPtr answer = createAnswer(0);
 
-    cout << "[XX] Handle command: " << endl << command << endl;
     if (command == "print_message") 
     {
         cout << args << endl;

+ 1 - 0
src/lib/auth/Makefile.am

@@ -23,6 +23,7 @@ run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD += .libs/libauth.a
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a 
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a 
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 endif
 

+ 13 - 0
src/lib/auth/data_source.cc

@@ -782,6 +782,19 @@ MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src)
 }
 
 void
+MetaDataSrc::removeDataSrc(ConstDataSrcPtr data_src)
+{
+    std::vector<ConstDataSrcPtr>::iterator it, itr;
+    for (it = data_sources.begin(); it != data_sources.end(); it++) {
+        if (*it == data_src) {
+            itr = it;
+        }
+    }
+
+    data_sources.erase(itr);
+}
+
+void
 MetaDataSrc::findClosestEnclosure(NameMatch& match, const RRClass& qclass) const
 {
     if (qclass == RRClass::ANY()) {

+ 6 - 0
src/lib/auth/data_source.h

@@ -25,6 +25,7 @@
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
+#include <cc/data.h>
 
 namespace isc {
 
@@ -102,6 +103,7 @@ public:
     // Optional 'low-level' methods.  These will have stub implementations
     // in the general DataSrc class but MAY be overwritten by subclasses
     virtual Result init() = 0;
+    virtual Result init(const isc::data::ElementPtr config) = 0;
     virtual Result close() = 0;
 
     // Mandatory 'low-level' methods: These will NOT be implemented by
@@ -181,6 +183,7 @@ public:
     void setClass(const isc::dns::RRClass& c) { rrclass = c; }
 
     Result init() { return NOT_IMPLEMENTED; }
+    Result init(const isc::data::ElementPtr config) { return NOT_IMPLEMENTED; }
     Result close() { return NOT_IMPLEMENTED; }
 
     virtual Result findRRset(const Query& q,
@@ -245,6 +248,9 @@ public:
     //@}
 
     void addDataSrc(ConstDataSrcPtr data_src);
+    void removeDataSrc(ConstDataSrcPtr data_src);
+    size_t dataSrcCount() { return data_sources.size(); };
+    
     void findClosestEnclosure(NameMatch& match,
                               const isc::dns::RRClass& qclass) const;
 

+ 6 - 9
src/lib/auth/data_source_sqlite3.cc

@@ -487,18 +487,15 @@ Sqlite3DataSrc::~Sqlite3DataSrc() {
 }
 
 DataSrc::Result
-Sqlite3DataSrc::init(const string& dbfile) {
-    open(dbfile);
-    cerr << "Schema version: " << getVersion() << endl;
-
+Sqlite3DataSrc::init(const isc::data::ElementPtr config) {
+    if (config and config->contains("database_file")) {
+        open(config->get("database_file")->stringValue());
+    } else {
+        open(DEFAULT_DB_FILE);
+    }
     return (SUCCESS);
 }
 
-DataSrc::Result
-Sqlite3DataSrc::init() {
-    return (init(DEFAULT_DB_FILE));
-}
-
 void
 Sqlite3DataSrc::findClosestEnclosure(NameMatch& match,
                                      const RRClass& qclass) const {

+ 2 - 2
src/lib/auth/data_source_sqlite3.h

@@ -102,8 +102,8 @@ public:
                              std::string& hash,
                              isc::dns::RRsetList& target) const;
 
-    Result init();
-    Result init(const std::string& dbfile);
+    Result init() { return init(isc::data::ElementPtr()); };
+    Result init(const isc::data::ElementPtr config);
     Result close();
 
 private:

+ 9 - 3
src/lib/auth/data_source_sqlite3_unittest.cc

@@ -29,6 +29,7 @@
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 #include <dns/rrsetlist.h>
+#include <cc/data.h>
 
 #include "query.h"
 #include "data_source.h"
@@ -38,15 +39,19 @@ using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::auth;
+using namespace isc::data;
 
 namespace {
-static const char* SQLITE_DBFILE_EXAMPLE = "testdata/test.sqlite3";
-static const char* SQLITE_DBFILE_EXAMPLE2 = "testdata/test2.sqlite3";
+static ElementPtr SQLITE_DBFILE_EXAMPLE = Element::createFromString(
+                     "{ \"database_file\": \"testdata/test.sqlite3\"}");
+static ElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::createFromString(
+                     "{ \"database_file\": \"testdata/test2.sqlite3\"}");
 // The following file must be non existent and mutt be "creatable";
 // the sqlite3 library will try to create a new DB file if it doesn't exist,
 // so to test a failure case the create operation should also fail.
 // The "nodir", a non existent directory, is inserted for this purpose.
-static const char* SQLITE_DBFILE_NOTEXIST = "testdata/nodir/notexist";
+static ElementPtr SQLITE_DBFILE_NOTEXIST = Element::createFromString(
+                     "{ \"database_file\": \"testdata/nodir/notexist\"}");
 
 static const string sigdata_common(" 20100322084538 20100220084538 "
                                    "33495 example.com. FAKEFAKEFAKEFAKE");
@@ -350,6 +355,7 @@ TEST_F(Sqlite3DataSourceTest, reOpen) {
     // Replace the data with a totally different zone.  This should succeed,
     // and shouldn't match any names in the previously managed domains.
     EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
+
     EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE2));
 
     NameMatch name_match(www_name);

+ 1 - 0
src/lib/auth/data_source_static.h

@@ -88,6 +88,7 @@ public:
                             isc::dns::RRsetList& target) const;
 
     Result init();
+    Result init(const isc::data::ElementPtr config) { return init(); };
     Result close();
 private:
     StaticDataSrcImpl* impl_;

+ 1 - 0
src/lib/auth/data_source_static_unittest.cc

@@ -27,6 +27,7 @@
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 #include <dns/rrsetlist.h>
+#include <cc/data.h>
 
 #include "query.h"
 #include "data_source.h"

+ 10 - 0
src/lib/auth/datasrc_unittest.cc

@@ -489,5 +489,15 @@ TEST_F(DataSrcTest, Nsec3Hash) {
     EXPECT_EQ("FHA27EURONFH5640SFJQ8MJAKMCVB7UJ", nsec3.getHash(Name("test2")));
     EXPECT_EQ("A4M93LR7A60IDDQMO6TCVUPCC60CU38A", nsec3.getHash(Name("test3")));
 }
+
+TEST_F(DataSrcTest, AddRemoveDataSrc) {
+    MetaDataSrc ds;
+    ConstDataSrcPtr tsp = ConstDataSrcPtr(new TestDataSrc);
+    EXPECT_EQ(0, ds.dataSrcCount());
+    ds.addDataSrc(tsp);
+    EXPECT_EQ(1, ds.dataSrcCount());
+    ds.removeDataSrc(tsp);
+    EXPECT_EQ(0, ds.dataSrcCount());
+}
 }
 

+ 6 - 0
src/lib/auth/unittest_ds.cc

@@ -96,6 +96,12 @@ RRsetPtr loop2_cname;
 }
 
 DataSrc::Result
+TestDataSrc::init(const isc::data::ElementPtr config)
+{
+    return init();
+}
+
+DataSrc::Result
 TestDataSrc::init() {
     if (initialized) {
         return (SUCCESS);

+ 1 - 0
src/lib/auth/unittest_ds.h

@@ -92,6 +92,7 @@ public:
                              isc::dns::RRsetList& target) const;
 
     Result init();
+    Result init(const isc::data::ElementPtr config);
     Result close() { return (SUCCESS); }
 
 private:

+ 11 - 3
src/lib/config/ccsession.cc

@@ -189,16 +189,24 @@ ModuleCCSession::ModuleCCSession(std::string spec_file_name,
     ElementPtr spec_msg = createCommand("module_spec", module_specification_.getFullSpec());
     session_.group_sendmsg(spec_msg, "ConfigManager");
     session_.group_recvmsg(env, answer, false);
-
+    int rcode;
+    ElementPtr err = parseAnswer(rcode, answer);
+    if (rcode != 0) {
+        std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
+    }
+    
     config_ = Element::createFromString("{}");
     // get any stored configuration from the manager
     if (config_handler_) {
         ElementPtr cmd = Element::createFromString("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
         session_.group_sendmsg(cmd, "ConfigManager");
         session_.group_recvmsg(env, answer, false);
-        int rcode;
         ElementPtr new_config = parseAnswer(rcode, answer);
-        handleConfigUpdate(new_config);
+        if (rcode == 0) {
+            handleConfigUpdate(new_config);
+        } else {
+            std::cerr << "[" << module_name_ << "] Error getting config: " << new_config << std::endl;
+        }
     }
 }
 

+ 3 - 3
src/lib/python/isc/cc/message.py

@@ -113,9 +113,9 @@ def _encode_item(item):
 def _encode_bool(item):
     """Encode a boolean value into a bytearray of one byte (0=false)"""
     if item:
-        return b'\x01'
+        return b'1'
     else:
-        return b'\x00'
+        return b'0'
 
 def _encode_array(item):
     """Encode an array, where each value is encoded recursively"""
@@ -203,7 +203,7 @@ def _decode_item(data):
     return (value, data)
 
 def _decode_bool(data):
-    return data == b'0x01'
+    return data == b'1' or data == b'0x01'
 
 def _decode_int(data):
     return int(str(data, 'utf-8'))

+ 1 - 1
src/lib/python/isc/config/cfgmgr.py

@@ -287,7 +287,6 @@ class ConfigManager:
                 self.config.data = old_data
                 answer = isc.config.ccsession.create_answer(1, " ".join(err_list))
         else:
-            print(cmd)
             answer = isc.config.ccsession.create_answer(1, "Wrong number of arguments")
         if not answer:
             answer = isc.config.ccsession.create_answer(1, "No answer message from " + cmd[0])
@@ -317,6 +316,7 @@ class ConfigManager:
         """Handle a command from the cc channel to the configuration manager"""
         answer = {}
         cmd, arg = isc.config.ccsession.parse_command(msg)
+        print("[b10-cfgmgr] got message: " + str(msg))
         if cmd:
             if cmd == isc.config.ccsession.COMMAND_GET_COMMANDS_SPEC:
                 answer = isc.config.ccsession.create_answer(0, self.get_commands_spec())