Browse Source

[master] Merged trac5145b (hooks and D2 client configs)

Francis Dupont 8 years ago
parent
commit
d94eb9c791
38 changed files with 4035 additions and 4042 deletions
  1. 2 2
      src/bin/agent/ca_cfg_mgr.cc
  2. 14 14
      src/bin/agent/ca_cfg_mgr.h
  3. 7 8
      src/bin/agent/simple_parser.cc
  4. 14 16
      src/bin/agent/tests/ca_cfg_mgr_unittests.cc
  5. 666 690
      src/bin/dhcp4/dhcp4_lexer.cc
  6. 0 9
      src/bin/dhcp4/dhcp4_lexer.ll
  7. 946 958
      src/bin/dhcp4/dhcp4_parser.cc
  8. 80 92
      src/bin/dhcp4/dhcp4_parser.h
  9. 0 7
      src/bin/dhcp4/dhcp4_parser.yy
  10. 10 12
      src/bin/dhcp4/json_config_parser.cc
  11. 1 1
      src/bin/dhcp4/location.hh
  12. 1 1
      src/bin/dhcp4/position.hh
  13. 1 1
      src/bin/dhcp4/stack.hh
  14. 0 2
      src/bin/dhcp4/tests/config_parser_unittest.cc
  15. 0 1
      src/bin/dhcp4/tests/d2_unittest.cc
  16. 862 885
      src/bin/dhcp6/dhcp6_lexer.cc
  17. 0 9
      src/bin/dhcp6/dhcp6_lexer.ll
  18. 967 981
      src/bin/dhcp6/dhcp6_parser.cc
  19. 82 93
      src/bin/dhcp6/dhcp6_parser.h
  20. 0 7
      src/bin/dhcp6/dhcp6_parser.yy
  21. 10 12
      src/bin/dhcp6/json_config_parser.cc
  22. 1 1
      src/bin/dhcp6/location.hh
  23. 1 1
      src/bin/dhcp6/position.hh
  24. 1 1
      src/bin/dhcp6/stack.hh
  25. 0 2
      src/bin/dhcp6/tests/config_parser_unittest.cc
  26. 0 1
      src/bin/dhcp6/tests/d2_unittest.cc
  27. 1 1
      src/lib/Makefile.am
  28. 29 47
      src/lib/dhcpsrv/parsers/dhcp_parsers.cc
  29. 0 12
      src/lib/dhcpsrv/parsers/dhcp_parsers.h
  30. 23 5
      src/lib/dhcpsrv/srv_config.cc
  31. 18 0
      src/lib/dhcpsrv/srv_config.h
  32. 22 53
      src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
  33. 27 0
      src/lib/dhcpsrv/tests/srv_config_unittest.cc
  34. 1 0
      src/lib/hooks/Makefile.am
  35. 129 0
      src/lib/hooks/hooks_config.cc
  36. 108 0
      src/lib/hooks/hooks_config.h
  37. 5 55
      src/lib/hooks/hooks_parser.cc
  38. 6 62
      src/lib/hooks/hooks_parser.h

+ 2 - 2
src/bin/agent/ca_cfg_mgr.cc

@@ -24,7 +24,7 @@ CtrlAgentCfgContext::CtrlAgentCfgContext()
 
 
 CtrlAgentCfgContext::CtrlAgentCfgContext(const CtrlAgentCfgContext& orig)
 CtrlAgentCfgContext::CtrlAgentCfgContext(const CtrlAgentCfgContext& orig)
     : DCfgContextBase(),http_host_(orig.http_host_), http_port_(orig.http_port_),
     : DCfgContextBase(),http_host_(orig.http_host_), http_port_(orig.http_port_),
-      libraries_(orig.libraries_) {
+      hooks_config_(orig.hooks_config_) {
 
 
     // We're copying pointers here only. The underlying data will be shared by
     // We're copying pointers here only. The underlying data will be shared by
     // old and new context. That's how shared pointers work and I see no reason
     // old and new context. That's how shared pointers work and I see no reason
@@ -74,7 +74,7 @@ CtrlAgentCfgMgr::getConfigSummary(const uint32_t /*selection*/) {
     }
     }
 
 
     // Finally, print the hook libraries names
     // Finally, print the hook libraries names
-    const hooks::HookLibsCollection libs = ctx->getLibraries();
+    const isc::hooks::HookLibsCollection libs = ctx->getHooksConfig().get();
     s << ", " << libs.size() << " lib(s):";
     s << ", " << libs.size() << " lib(s):";
     for (auto lib = libs.begin(); lib != libs.end(); ++lib) {
     for (auto lib = libs.begin(); lib != libs.end(); ++lib) {
         s << lib->first << " ";
         s << lib->first << " ";

+ 14 - 14
src/bin/agent/ca_cfg_mgr.h

@@ -8,9 +8,9 @@
 #define CTRL_AGENT_CFG_MGR_H
 #define CTRL_AGENT_CFG_MGR_H
 
 
 #include <cc/data.h>
 #include <cc/data.h>
+#include <hooks/hooks_config.h>
 #include <process/d_cfg_mgr.h>
 #include <process/d_cfg_mgr.h>
 #include <boost/pointer_cast.hpp>
 #include <boost/pointer_cast.hpp>
-#include <hooks/libinfo.h>
 
 
 namespace isc {
 namespace isc {
 namespace agent {
 namespace agent {
@@ -61,7 +61,7 @@ public:
     ///
     ///
     /// @param type type of the server being controlled
     /// @param type type of the server being controlled
     /// @return pointer to the Element that holds control-socket map (or NULL)
     /// @return pointer to the Element that holds control-socket map (or NULL)
-    const data::ConstElementPtr getControlSocketInfo(ServerType type) const;
+    const isc::data::ConstElementPtr getControlSocketInfo(ServerType type) const;
 
 
     /// @brief Sets information about the control socket
     /// @brief Sets information about the control socket
     ///
     ///
@@ -102,20 +102,20 @@ public:
         return (http_port_);
         return (http_port_);
     }
     }
 
 
-    /// @brief Returns a list of hook libraries
-    /// @return a list of hook libraries
-    const hooks::HookLibsCollection& getLibraries() const {
-        return (libraries_);
+    /// @brief Returns non-const reference to configured hooks libraries.
+    ///
+    /// @return non-const reference to configured hooks libraries.
+    isc::hooks::HooksConfig& getHooksConfig() {
+        return (hooks_config_);
     }
     }
 
 
-    /// @brief Sets the list of hook libraries
+    /// @brief Returns const reference to configured hooks libraries.
     ///
     ///
-    /// @params libs a coolection of libraries to remember.
-    void setLibraries(const hooks::HookLibsCollection& libs) {
-        libraries_ = libs;
+    /// @return const reference to configured hooks libraries.
+    const isc::hooks::HooksConfig& getHooksConfig() const {
+        return (hooks_config_);
     }
     }
 
 
-
 private:
 private:
 
 
     /// @brief Private copy constructor
     /// @brief Private copy constructor
@@ -132,7 +132,7 @@ private:
     CtrlAgentCfgContext& operator=(const CtrlAgentCfgContext& rhs);
     CtrlAgentCfgContext& operator=(const CtrlAgentCfgContext& rhs);
 
 
     /// Socket information will be stored here (for all supported servers)
     /// Socket information will be stored here (for all supported servers)
-    data::ConstElementPtr ctrl_sockets_[MAX_TYPE_SUPPORTED + 1];
+    isc::data::ConstElementPtr ctrl_sockets_[MAX_TYPE_SUPPORTED + 1];
 
 
     /// Hostname the CA should listen on.
     /// Hostname the CA should listen on.
     std::string http_host_;
     std::string http_host_;
@@ -140,8 +140,8 @@ private:
     /// TCP port the CA should listen on.
     /// TCP port the CA should listen on.
     uint16_t http_port_;
     uint16_t http_port_;
 
 
-    /// List of hook libraries.
-    hooks::HookLibsCollection libraries_;
+    /// @brief Configured hooks libraries.
+    isc::hooks::HooksConfig hooks_config_;
 };
 };
 
 
 /// @brief Ctrl Agent Configuration Manager.
 /// @brief Ctrl Agent Configuration Manager.

+ 7 - 8
src/bin/agent/simple_parser.cc

@@ -107,22 +107,21 @@ AgentSimpleParser::parse(const CtrlAgentCfgContextPtr& ctx,
     }
     }
 
 
     // Finally, let's get the hook libs!
     // Finally, let's get the hook libs!
-    hooks::HooksLibrariesParser hooks_parser;
+    
+    using namespace isc::hooks;
+    HooksConfig& libraries = ctx->getHooksConfig();
     ConstElementPtr hooks = config->get("hooks-libraries");
     ConstElementPtr hooks = config->get("hooks-libraries");
     if (hooks) {
     if (hooks) {
-        hooks_parser.parse(hooks);
-        hooks_parser.verifyLibraries();
-
-        hooks::HookLibsCollection libs;
-        hooks_parser.getLibraries(libs);
-        ctx->setLibraries(libs);
+        HooksLibrariesParser hooks_parser;
+        hooks_parser.parse(libraries, hooks);
+        libraries.verifyLibraries(hooks->getPosition());
     }
     }
 
 
     if (!check_only) {
     if (!check_only) {
         // This occurs last as if it succeeds, there is no easy way
         // This occurs last as if it succeeds, there is no easy way
         // revert it.  As a result, the failure to commit a subsequent
         // revert it.  As a result, the failure to commit a subsequent
         // change causes problems when trying to roll back.
         // change causes problems when trying to roll back.
-        hooks_parser.loadLibraries();
+        libraries.loadLibraries();
     }
     }
 }
 }
 
 

+ 14 - 16
src/bin/agent/tests/ca_cfg_mgr_unittests.cc

@@ -10,12 +10,12 @@
 #include <process/testutils/d_test_stubs.h>
 #include <process/testutils/d_test_stubs.h>
 #include <process/d_cfg_mgr.h>
 #include <process/d_cfg_mgr.h>
 #include <agent/tests/test_libraries.h>
 #include <agent/tests/test_libraries.h>
-#include <hooks/libinfo.h>
 #include <boost/scoped_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 using namespace isc::agent;
 using namespace isc::agent;
 using namespace isc::data;
 using namespace isc::data;
+using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace isc::hooks;
 using namespace isc::process;
 using namespace isc::process;
 
 
@@ -123,11 +123,10 @@ TEST(CtrlAgentCfgMgr, contextSocketInfoCopy) {
     EXPECT_NO_THROW(ctx.setHttpPort(12345));
     EXPECT_NO_THROW(ctx.setHttpPort(12345));
     EXPECT_NO_THROW(ctx.setHttpHost("bellatrix"));
     EXPECT_NO_THROW(ctx.setHttpHost("bellatrix"));
 
 
-    HookLibsCollection libs;
+    HooksConfig& libs = ctx.getHooksConfig();
     string exp_name("testlib1.so");
     string exp_name("testlib1.so");
     ConstElementPtr exp_param(new StringElement("myparam"));
     ConstElementPtr exp_param(new StringElement("myparam"));
-    libs.push_back(make_pair(exp_name, exp_param));
-    ctx.setLibraries(libs);
+    libs.add(exp_name, exp_param);
 
 
     // Make a copy.
     // Make a copy.
     DCfgContextBasePtr copy_base(ctx.clone());
     DCfgContextBasePtr copy_base(ctx.clone());
@@ -147,7 +146,7 @@ TEST(CtrlAgentCfgMgr, contextSocketInfoCopy) {
     EXPECT_EQ(socket3->str(), copy->getControlSocketInfo(CtrlAgentCfgContext::TYPE_DHCP6)->str());
     EXPECT_EQ(socket3->str(), copy->getControlSocketInfo(CtrlAgentCfgContext::TYPE_DHCP6)->str());
 
 
     // Check hook libs
     // Check hook libs
-    HookLibsCollection libs2 = copy->getLibraries();
+    const HookLibsCollection& libs2 = copy->getHooksConfig().get();
     ASSERT_EQ(1, libs2.size());
     ASSERT_EQ(1, libs2.size());
     EXPECT_EQ(exp_name, libs2[0].first);
     EXPECT_EQ(exp_name, libs2[0].first);
     ASSERT_TRUE(libs2[0].second);
     ASSERT_TRUE(libs2[0].second);
@@ -160,19 +159,18 @@ TEST(CtrlAgentCfgMgr, contextHookParams) {
     CtrlAgentCfgContext ctx;
     CtrlAgentCfgContext ctx;
 
 
     // By default there should be no hooks.
     // By default there should be no hooks.
-    HookLibsCollection libs = ctx.getLibraries();
-    EXPECT_TRUE(libs.empty());
+    HooksConfig& libs = ctx.getHooksConfig();
+    EXPECT_TRUE(libs.get().empty());
 
 
-    libs.push_back(std::make_pair("libone.so", ConstElementPtr()));
-    libs.push_back(std::make_pair("libtwo.so", Element::fromJSON("{\"foo\": true}")));
-    libs.push_back(std::make_pair("libthree.so", Element::fromJSON("{\"bar\": 42}")));
+    libs.add("libone.so", ConstElementPtr());
+    libs.add("libtwo.so", Element::fromJSON("{\"foo\": true}"));
+    libs.add("libthree.so", Element::fromJSON("{\"bar\": 42}"));
 
 
-    ctx.setLibraries(libs);
+    const HooksConfig& stored_libs = ctx.getHooksConfig();
+    EXPECT_EQ(3, stored_libs.get().size());
 
 
-    HookLibsCollection stored_libs = ctx.getLibraries();
-    EXPECT_EQ(3, stored_libs.size());
-
-    EXPECT_EQ(libs, stored_libs);
+    // @todo add a == operator to HooksConfig
+    EXPECT_EQ(libs.get(), stored_libs.get());
 }
 }
 
 
 /// Control Agent configurations used in tests.
 /// Control Agent configurations used in tests.
@@ -389,7 +387,7 @@ TEST_F(AgentParserTest, configParseHooks) {
 
 
     // The context now should have the library specified.
     // The context now should have the library specified.
     CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
     CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
-    HookLibsCollection libs = ctx->getLibraries();
+    const HookLibsCollection libs = ctx->getHooksConfig().get();
     ASSERT_EQ(1, libs.size());
     ASSERT_EQ(1, libs.size());
     EXPECT_EQ(string(BASIC_CALLOUT_LIBRARY), libs[0].first);
     EXPECT_EQ(string(BASIC_CALLOUT_LIBRARY), libs[0].first);
     ASSERT_TRUE(libs[0].second);
     ASSERT_TRUE(libs[0].second);

File diff suppressed because it is too large
+ 666 - 690
src/bin/dhcp4/dhcp4_lexer.cc


+ 0 - 9
src/bin/dhcp4/dhcp4_lexer.ll

@@ -1018,15 +1018,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     }
     }
 }
 }
 
 
-\"allow-client-update\" {
-    switch(driver.ctx_) {
-    case isc::dhcp::Parser4Context::DHCP_DDNS:
-        return isc::dhcp::Dhcp4Parser::make_ALLOW_CLIENT_UPDATE(driver.loc_);
-    default:
-        return isc::dhcp::Dhcp4Parser::make_STRING("allow-client-update", driver.loc_);
-    }
-}
-
 \"override-no-update\" {
 \"override-no-update\" {
     switch(driver.ctx_) {
     switch(driver.ctx_) {
     case isc::dhcp::Parser4Context::DHCP_DDNS:
     case isc::dhcp::Parser4Context::DHCP_DDNS:

File diff suppressed because it is too large
+ 946 - 958
src/bin/dhcp4/dhcp4_parser.cc


+ 80 - 92
src/bin/dhcp4/dhcp4_parser.h

@@ -445,40 +445,39 @@ namespace isc { namespace dhcp {
         TOKEN_NCR_PROTOCOL = 354,
         TOKEN_NCR_PROTOCOL = 354,
         TOKEN_NCR_FORMAT = 355,
         TOKEN_NCR_FORMAT = 355,
         TOKEN_ALWAYS_INCLUDE_FQDN = 356,
         TOKEN_ALWAYS_INCLUDE_FQDN = 356,
-        TOKEN_ALLOW_CLIENT_UPDATE = 357,
-        TOKEN_OVERRIDE_NO_UPDATE = 358,
-        TOKEN_OVERRIDE_CLIENT_UPDATE = 359,
-        TOKEN_REPLACE_CLIENT_NAME = 360,
-        TOKEN_GENERATED_PREFIX = 361,
-        TOKEN_TCP = 362,
-        TOKEN_JSON = 363,
-        TOKEN_WHEN_PRESENT = 364,
-        TOKEN_NEVER = 365,
-        TOKEN_ALWAYS = 366,
-        TOKEN_WHEN_NOT_PRESENT = 367,
-        TOKEN_LOGGING = 368,
-        TOKEN_LOGGERS = 369,
-        TOKEN_OUTPUT_OPTIONS = 370,
-        TOKEN_OUTPUT = 371,
-        TOKEN_DEBUGLEVEL = 372,
-        TOKEN_SEVERITY = 373,
-        TOKEN_DHCP6 = 374,
-        TOKEN_DHCPDDNS = 375,
-        TOKEN_TOPLEVEL_JSON = 376,
-        TOKEN_TOPLEVEL_DHCP4 = 377,
-        TOKEN_SUB_DHCP4 = 378,
-        TOKEN_SUB_INTERFACES4 = 379,
-        TOKEN_SUB_SUBNET4 = 380,
-        TOKEN_SUB_POOL4 = 381,
-        TOKEN_SUB_RESERVATION = 382,
-        TOKEN_SUB_OPTION_DEF = 383,
-        TOKEN_SUB_OPTION_DATA = 384,
-        TOKEN_SUB_HOOKS_LIBRARY = 385,
-        TOKEN_SUB_DHCP_DDNS = 386,
-        TOKEN_STRING = 387,
-        TOKEN_INTEGER = 388,
-        TOKEN_FLOAT = 389,
-        TOKEN_BOOLEAN = 390
+        TOKEN_OVERRIDE_NO_UPDATE = 357,
+        TOKEN_OVERRIDE_CLIENT_UPDATE = 358,
+        TOKEN_REPLACE_CLIENT_NAME = 359,
+        TOKEN_GENERATED_PREFIX = 360,
+        TOKEN_TCP = 361,
+        TOKEN_JSON = 362,
+        TOKEN_WHEN_PRESENT = 363,
+        TOKEN_NEVER = 364,
+        TOKEN_ALWAYS = 365,
+        TOKEN_WHEN_NOT_PRESENT = 366,
+        TOKEN_LOGGING = 367,
+        TOKEN_LOGGERS = 368,
+        TOKEN_OUTPUT_OPTIONS = 369,
+        TOKEN_OUTPUT = 370,
+        TOKEN_DEBUGLEVEL = 371,
+        TOKEN_SEVERITY = 372,
+        TOKEN_DHCP6 = 373,
+        TOKEN_DHCPDDNS = 374,
+        TOKEN_TOPLEVEL_JSON = 375,
+        TOKEN_TOPLEVEL_DHCP4 = 376,
+        TOKEN_SUB_DHCP4 = 377,
+        TOKEN_SUB_INTERFACES4 = 378,
+        TOKEN_SUB_SUBNET4 = 379,
+        TOKEN_SUB_POOL4 = 380,
+        TOKEN_SUB_RESERVATION = 381,
+        TOKEN_SUB_OPTION_DEF = 382,
+        TOKEN_SUB_OPTION_DATA = 383,
+        TOKEN_SUB_HOOKS_LIBRARY = 384,
+        TOKEN_SUB_DHCP_DDNS = 385,
+        TOKEN_STRING = 386,
+        TOKEN_INTEGER = 387,
+        TOKEN_FLOAT = 388,
+        TOKEN_BOOLEAN = 389
       };
       };
     };
     };
 
 
@@ -995,10 +994,6 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_ALLOW_CLIENT_UPDATE (const location_type& l);
-
-    static inline
-    symbol_type
     make_OVERRIDE_NO_UPDATE (const location_type& l);
     make_OVERRIDE_NO_UPDATE (const location_type& l);
 
 
     static inline
     static inline
@@ -1334,12 +1329,12 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 733,     ///< Last index in yytable_.
-      yynnts_ = 307,  ///< Number of nonterminal symbols.
+      yylast_ = 729,     ///< Last index in yytable_.
+      yynnts_ = 306,  ///< Number of nonterminal symbols.
       yyfinal_ = 24, ///< Termination state number.
       yyfinal_ = 24, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
-      yyntokens_ = 136  ///< Number of tokens.
+      yyntokens_ = 135  ///< Number of tokens.
     };
     };
 
 
 
 
@@ -1394,10 +1389,9 @@ namespace isc { namespace dhcp {
       95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
       95,    96,    97,    98,    99,   100,   101,   102,   103,   104,
      105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
      105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
-     125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
-     135
+     125,   126,   127,   128,   129,   130,   131,   132,   133,   134
     };
     };
-    const unsigned int user_token_number_max_ = 390;
+    const unsigned int user_token_number_max_ = 389;
     const token_number_type undef_token_ = 2;
     const token_number_type undef_token_ = 2;
 
 
     if (static_cast<int>(t) <= yyeof_)
     if (static_cast<int>(t) <= yyeof_)
@@ -1430,28 +1424,28 @@ namespace isc { namespace dhcp {
   {
   {
       switch (other.type_get ())
       switch (other.type_get ())
     {
     {
-      case 149: // value
-      case 153: // map_value
-      case 191: // socket_type
-      case 200: // db_type
-      case 405: // ncr_protocol_value
-      case 414: // replace_client_name_value
+      case 148: // value
+      case 152: // map_value
+      case 190: // socket_type
+      case 199: // db_type
+      case 404: // ncr_protocol_value
+      case 412: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
-      case 135: // "boolean"
+      case 134: // "boolean"
         value.copy< bool > (other.value);
         value.copy< bool > (other.value);
         break;
         break;
 
 
-      case 134: // "floating point"
+      case 133: // "floating point"
         value.copy< double > (other.value);
         value.copy< double > (other.value);
         break;
         break;
 
 
-      case 133: // "integer"
+      case 132: // "integer"
         value.copy< int64_t > (other.value);
         value.copy< int64_t > (other.value);
         break;
         break;
 
 
-      case 132: // "constant string"
+      case 131: // "constant string"
         value.copy< std::string > (other.value);
         value.copy< std::string > (other.value);
         break;
         break;
 
 
@@ -1472,28 +1466,28 @@ namespace isc { namespace dhcp {
     (void) v;
     (void) v;
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 149: // value
-      case 153: // map_value
-      case 191: // socket_type
-      case 200: // db_type
-      case 405: // ncr_protocol_value
-      case 414: // replace_client_name_value
+      case 148: // value
+      case 152: // map_value
+      case 190: // socket_type
+      case 199: // db_type
+      case 404: // ncr_protocol_value
+      case 412: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
-      case 135: // "boolean"
+      case 134: // "boolean"
         value.copy< bool > (v);
         value.copy< bool > (v);
         break;
         break;
 
 
-      case 134: // "floating point"
+      case 133: // "floating point"
         value.copy< double > (v);
         value.copy< double > (v);
         break;
         break;
 
 
-      case 133: // "integer"
+      case 132: // "integer"
         value.copy< int64_t > (v);
         value.copy< int64_t > (v);
         break;
         break;
 
 
-      case 132: // "constant string"
+      case 131: // "constant string"
         value.copy< std::string > (v);
         value.copy< std::string > (v);
         break;
         break;
 
 
@@ -1573,28 +1567,28 @@ namespace isc { namespace dhcp {
     // Type destructor.
     // Type destructor.
     switch (yytype)
     switch (yytype)
     {
     {
-      case 149: // value
-      case 153: // map_value
-      case 191: // socket_type
-      case 200: // db_type
-      case 405: // ncr_protocol_value
-      case 414: // replace_client_name_value
+      case 148: // value
+      case 152: // map_value
+      case 190: // socket_type
+      case 199: // db_type
+      case 404: // ncr_protocol_value
+      case 412: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
-      case 135: // "boolean"
+      case 134: // "boolean"
         value.template destroy< bool > ();
         value.template destroy< bool > ();
         break;
         break;
 
 
-      case 134: // "floating point"
+      case 133: // "floating point"
         value.template destroy< double > ();
         value.template destroy< double > ();
         break;
         break;
 
 
-      case 133: // "integer"
+      case 132: // "integer"
         value.template destroy< int64_t > ();
         value.template destroy< int64_t > ();
         break;
         break;
 
 
-      case 132: // "constant string"
+      case 131: // "constant string"
         value.template destroy< std::string > ();
         value.template destroy< std::string > ();
         break;
         break;
 
 
@@ -1621,28 +1615,28 @@ namespace isc { namespace dhcp {
     super_type::move(s);
     super_type::move(s);
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 149: // value
-      case 153: // map_value
-      case 191: // socket_type
-      case 200: // db_type
-      case 405: // ncr_protocol_value
-      case 414: // replace_client_name_value
+      case 148: // value
+      case 152: // map_value
+      case 190: // socket_type
+      case 199: // db_type
+      case 404: // ncr_protocol_value
+      case 412: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
-      case 135: // "boolean"
+      case 134: // "boolean"
         value.move< bool > (s.value);
         value.move< bool > (s.value);
         break;
         break;
 
 
-      case 134: // "floating point"
+      case 133: // "floating point"
         value.move< double > (s.value);
         value.move< double > (s.value);
         break;
         break;
 
 
-      case 133: // "integer"
+      case 132: // "integer"
         value.move< int64_t > (s.value);
         value.move< int64_t > (s.value);
         break;
         break;
 
 
-      case 132: // "constant string"
+      case 131: // "constant string"
         value.move< std::string > (s.value);
         value.move< std::string > (s.value);
         break;
         break;
 
 
@@ -1714,7 +1708,7 @@ namespace isc { namespace dhcp {
      355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
      355,   356,   357,   358,   359,   360,   361,   362,   363,   364,
      365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
      365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
      375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
      375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
-     385,   386,   387,   388,   389,   390
+     385,   386,   387,   388,   389
     };
     };
     return static_cast<token_type> (yytoken_number_[type]);
     return static_cast<token_type> (yytoken_number_[type]);
   }
   }
@@ -2320,12 +2314,6 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp4Parser::symbol_type
   Dhcp4Parser::symbol_type
-  Dhcp4Parser::make_ALLOW_CLIENT_UPDATE (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_ALLOW_CLIENT_UPDATE, l);
-  }
-
-  Dhcp4Parser::symbol_type
   Dhcp4Parser::make_OVERRIDE_NO_UPDATE (const location_type& l)
   Dhcp4Parser::make_OVERRIDE_NO_UPDATE (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_OVERRIDE_NO_UPDATE, l);
     return symbol_type (token::TOKEN_OVERRIDE_NO_UPDATE, l);
@@ -2526,7 +2514,7 @@ namespace isc { namespace dhcp {
 
 
 #line 14 "dhcp4_parser.yy" // lalr1.cc:377
 #line 14 "dhcp4_parser.yy" // lalr1.cc:377
 } } // isc::dhcp
 } } // isc::dhcp
-#line 2530 "dhcp4_parser.h" // lalr1.cc:377
+#line 2518 "dhcp4_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 0 - 7
src/bin/dhcp4/dhcp4_parser.yy

@@ -155,7 +155,6 @@ using namespace std;
   NCR_PROTOCOL "ncr-protocol"
   NCR_PROTOCOL "ncr-protocol"
   NCR_FORMAT "ncr-format"
   NCR_FORMAT "ncr-format"
   ALWAYS_INCLUDE_FQDN "always-include-fqdn"
   ALWAYS_INCLUDE_FQDN "always-include-fqdn"
-  ALLOW_CLIENT_UPDATE "allow-client-update"
   OVERRIDE_NO_UPDATE "override-no-update"
   OVERRIDE_NO_UPDATE "override-no-update"
   OVERRIDE_CLIENT_UPDATE "override-client-update"
   OVERRIDE_CLIENT_UPDATE "override-client-update"
   REPLACE_CLIENT_NAME "replace-client-name"
   REPLACE_CLIENT_NAME "replace-client-name"
@@ -1487,7 +1486,6 @@ dhcp_ddns_param: enable_updates
                | ncr_protocol
                | ncr_protocol
                | ncr_format
                | ncr_format
                | always_include_fqdn
                | always_include_fqdn
-               | allow_client_update
                | override_no_update
                | override_no_update
                | override_client_update
                | override_client_update
                | replace_client_name
                | replace_client_name
@@ -1564,11 +1562,6 @@ always_include_fqdn: ALWAYS_INCLUDE_FQDN COLON BOOLEAN {
     ctx.stack_.back()->set("always-include-fqdn", b);
     ctx.stack_.back()->set("always-include-fqdn", b);
 };
 };
 
 
-allow_client_update: ALLOW_CLIENT_UPDATE COLON BOOLEAN {
-    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
-    ctx.stack_.back()->set("allow-client-update",  b);
-};
-
 override_no_update: OVERRIDE_NO_UPDATE COLON BOOLEAN {
 override_no_update: OVERRIDE_NO_UPDATE COLON BOOLEAN {
     ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
     ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("override-no-update", b);
     ctx.stack_.back()->set("override-no-update", b);

+ 10 - 12
src/bin/dhcp4/json_config_parser.cc

@@ -42,6 +42,7 @@ using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::asiolink;
 using namespace isc::asiolink;
+using namespace isc::hooks;
 
 
 namespace {
 namespace {
 
 
@@ -431,11 +432,6 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
     // for option definitions. This is equivalent to commiting empty container.
     // for option definitions. This is equivalent to commiting empty container.
     LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
     LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
 
 
-    // Some of the parsers alter the state of the system in a way that can't
-    // easily be undone. (Or alter it in a way such that undoing the change has
-    // the same risk of failure as doing the change.)
-    hooks::HooksLibrariesParser hooks_parser;
-
     // Answer will hold the result.
     // Answer will hold the result.
     ConstElementPtr answer;
     ConstElementPtr answer;
     // Rollback informs whether error occurred and original data
     // Rollback informs whether error occurred and original data
@@ -515,17 +511,17 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
             }
             }
 
 
             if (config_pair.first == "hooks-libraries") {
             if (config_pair.first == "hooks-libraries") {
-                hooks_parser.parse(config_pair.second);
-                hooks_parser.verifyLibraries();
+                HooksLibrariesParser hooks_parser;
+                HooksConfig& libraries = srv_cfg->getHooksConfig();
+                hooks_parser.parse(libraries, config_pair.second);
+                libraries.verifyLibraries(config_pair.second->getPosition());
                 continue;
                 continue;
             }
             }
 
 
             // Legacy DhcpConfigParser stuff below
             // Legacy DhcpConfigParser stuff below
             if (config_pair.first == "dhcp-ddns") {
             if (config_pair.first == "dhcp-ddns") {
-                // Apply defaults if not in short cut
-                if (!D2ClientConfigParser::isShortCutDisabled(config_pair.second)) {
-                    D2ClientConfigParser::setAllDefaults(config_pair.second);
-                }
+                // Apply defaults
+                D2ClientConfigParser::setAllDefaults(config_pair.second);
                 D2ClientConfigParser parser;
                 D2ClientConfigParser parser;
                 D2ClientConfigPtr cfg = parser.parse(config_pair.second);
                 D2ClientConfigPtr cfg = parser.parse(config_pair.second);
                 srv_cfg->setD2ClientConfig(cfg);
                 srv_cfg->setD2ClientConfig(cfg);
@@ -637,7 +633,9 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
             // This occurs last as if it succeeds, there is no easy way
             // This occurs last as if it succeeds, there is no easy way
             // revert it.  As a result, the failure to commit a subsequent
             // revert it.  As a result, the failure to commit a subsequent
             // change causes problems when trying to roll back.
             // change causes problems when trying to roll back.
-            hooks_parser.loadLibraries();
+            const HooksConfig& libraries =
+                CfgMgr::instance().getStagingCfg()->getHooksConfig();
+            libraries.loadLibraries();
         }
         }
         catch (const isc::Exception& ex) {
         catch (const isc::Exception& ex) {
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());

+ 1 - 1
src/bin/dhcp4/location.hh

@@ -1,4 +1,4 @@
-// Generated 201703010915
+// Generated 201703041501
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Locations for Bison parsers in C++
 // Locations for Bison parsers in C++

+ 1 - 1
src/bin/dhcp4/position.hh

@@ -1,4 +1,4 @@
-// Generated 201703010915
+// Generated 201703041501
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Positions for Bison parsers in C++
 // Positions for Bison parsers in C++

+ 1 - 1
src/bin/dhcp4/stack.hh

@@ -1,4 +1,4 @@
-// Generated 201703010915
+// Generated 201703041501
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Stack handling for Bison parsers in C++
 // Stack handling for Bison parsers in C++

+ 0 - 2
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -3414,7 +3414,6 @@ TEST_F(Dhcp4ParserTest, d2ClientConfig) {
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
         "     \"always-include-fqdn\" : true, "
-        "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"replace-client-name\" : \"when-present\", "
         "     \"replace-client-name\" : \"when-present\", "
@@ -3476,7 +3475,6 @@ TEST_F(Dhcp4ParserTest, invalidD2ClientConfig) {
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
         "     \"always-include-fqdn\" : true, "
-        "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"replace-client-name\" : \"when-present\", "
         "     \"replace-client-name\" : \"when-present\", "

+ 0 - 1
src/bin/dhcp4/tests/d2_unittest.cc

@@ -109,7 +109,6 @@ Dhcp4SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
         "     \"always-include-fqdn\" : true, "
-        "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"replace-client-name\" : \"when-present\", "
         "     \"replace-client-name\" : \"when-present\", "

File diff suppressed because it is too large
+ 862 - 885
src/bin/dhcp6/dhcp6_lexer.cc


+ 0 - 9
src/bin/dhcp6/dhcp6_lexer.ll

@@ -263,15 +263,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     }
     }
 }
 }
 
 
-\"allow-client-update\" {
-    switch(driver.ctx_) {
-    case isc::dhcp::Parser6Context::DHCP_DDNS:
-        return isc::dhcp::Dhcp6Parser::make_ALLOW_CLIENT_UPDATE(driver.loc_);
-    default:
-        return isc::dhcp::Dhcp6Parser::make_STRING("allow-client-update", driver.loc_);
-    }
-}
-
 \"override-no-update\" {
 \"override-no-update\" {
     switch(driver.ctx_) {
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::DHCP_DDNS:
     case isc::dhcp::Parser6Context::DHCP_DDNS:

File diff suppressed because it is too large
+ 967 - 981
src/bin/dhcp6/dhcp6_parser.cc


+ 82 - 93
src/bin/dhcp6/dhcp6_parser.h

@@ -451,42 +451,41 @@ namespace isc { namespace dhcp {
         TOKEN_NCR_PROTOCOL = 360,
         TOKEN_NCR_PROTOCOL = 360,
         TOKEN_NCR_FORMAT = 361,
         TOKEN_NCR_FORMAT = 361,
         TOKEN_ALWAYS_INCLUDE_FQDN = 362,
         TOKEN_ALWAYS_INCLUDE_FQDN = 362,
-        TOKEN_ALLOW_CLIENT_UPDATE = 363,
-        TOKEN_OVERRIDE_NO_UPDATE = 364,
-        TOKEN_OVERRIDE_CLIENT_UPDATE = 365,
-        TOKEN_REPLACE_CLIENT_NAME = 366,
-        TOKEN_GENERATED_PREFIX = 367,
-        TOKEN_UDP = 368,
-        TOKEN_TCP = 369,
-        TOKEN_JSON = 370,
-        TOKEN_WHEN_PRESENT = 371,
-        TOKEN_NEVER = 372,
-        TOKEN_ALWAYS = 373,
-        TOKEN_WHEN_NOT_PRESENT = 374,
-        TOKEN_LOGGING = 375,
-        TOKEN_LOGGERS = 376,
-        TOKEN_OUTPUT_OPTIONS = 377,
-        TOKEN_OUTPUT = 378,
-        TOKEN_DEBUGLEVEL = 379,
-        TOKEN_SEVERITY = 380,
-        TOKEN_DHCP4 = 381,
-        TOKEN_DHCPDDNS = 382,
-        TOKEN_TOPLEVEL_JSON = 383,
-        TOKEN_TOPLEVEL_DHCP6 = 384,
-        TOKEN_SUB_DHCP6 = 385,
-        TOKEN_SUB_INTERFACES6 = 386,
-        TOKEN_SUB_SUBNET6 = 387,
-        TOKEN_SUB_POOL6 = 388,
-        TOKEN_SUB_PD_POOL = 389,
-        TOKEN_SUB_RESERVATION = 390,
-        TOKEN_SUB_OPTION_DEF = 391,
-        TOKEN_SUB_OPTION_DATA = 392,
-        TOKEN_SUB_HOOKS_LIBRARY = 393,
-        TOKEN_SUB_DHCP_DDNS = 394,
-        TOKEN_STRING = 395,
-        TOKEN_INTEGER = 396,
-        TOKEN_FLOAT = 397,
-        TOKEN_BOOLEAN = 398
+        TOKEN_OVERRIDE_NO_UPDATE = 363,
+        TOKEN_OVERRIDE_CLIENT_UPDATE = 364,
+        TOKEN_REPLACE_CLIENT_NAME = 365,
+        TOKEN_GENERATED_PREFIX = 366,
+        TOKEN_UDP = 367,
+        TOKEN_TCP = 368,
+        TOKEN_JSON = 369,
+        TOKEN_WHEN_PRESENT = 370,
+        TOKEN_NEVER = 371,
+        TOKEN_ALWAYS = 372,
+        TOKEN_WHEN_NOT_PRESENT = 373,
+        TOKEN_LOGGING = 374,
+        TOKEN_LOGGERS = 375,
+        TOKEN_OUTPUT_OPTIONS = 376,
+        TOKEN_OUTPUT = 377,
+        TOKEN_DEBUGLEVEL = 378,
+        TOKEN_SEVERITY = 379,
+        TOKEN_DHCP4 = 380,
+        TOKEN_DHCPDDNS = 381,
+        TOKEN_TOPLEVEL_JSON = 382,
+        TOKEN_TOPLEVEL_DHCP6 = 383,
+        TOKEN_SUB_DHCP6 = 384,
+        TOKEN_SUB_INTERFACES6 = 385,
+        TOKEN_SUB_SUBNET6 = 386,
+        TOKEN_SUB_POOL6 = 387,
+        TOKEN_SUB_PD_POOL = 388,
+        TOKEN_SUB_RESERVATION = 389,
+        TOKEN_SUB_OPTION_DEF = 390,
+        TOKEN_SUB_OPTION_DATA = 391,
+        TOKEN_SUB_HOOKS_LIBRARY = 392,
+        TOKEN_SUB_DHCP_DDNS = 393,
+        TOKEN_STRING = 394,
+        TOKEN_INTEGER = 395,
+        TOKEN_FLOAT = 396,
+        TOKEN_BOOLEAN = 397
       };
       };
     };
     };
 
 
@@ -1027,10 +1026,6 @@ namespace isc { namespace dhcp {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_ALLOW_CLIENT_UPDATE (const location_type& l);
-
-    static inline
-    symbol_type
     make_OVERRIDE_NO_UPDATE (const location_type& l);
     make_OVERRIDE_NO_UPDATE (const location_type& l);
 
 
     static inline
     static inline
@@ -1374,12 +1369,12 @@ namespace isc { namespace dhcp {
     enum
     enum
     {
     {
       yyeof_ = 0,
       yyeof_ = 0,
-      yylast_ = 781,     ///< Last index in yytable_.
-      yynnts_ = 322,  ///< Number of nonterminal symbols.
+      yylast_ = 777,     ///< Last index in yytable_.
+      yynnts_ = 321,  ///< Number of nonterminal symbols.
       yyfinal_ = 26, ///< Termination state number.
       yyfinal_ = 26, ///< Termination state number.
       yyterror_ = 1,
       yyterror_ = 1,
       yyerrcode_ = 256,
       yyerrcode_ = 256,
-      yyntokens_ = 144  ///< Number of tokens.
+      yyntokens_ = 143  ///< Number of tokens.
     };
     };
 
 
 
 
@@ -1435,9 +1430,9 @@ namespace isc { namespace dhcp {
      105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
      105,   106,   107,   108,   109,   110,   111,   112,   113,   114,
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
      125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
      125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
-     135,   136,   137,   138,   139,   140,   141,   142,   143
+     135,   136,   137,   138,   139,   140,   141,   142
     };
     };
-    const unsigned int user_token_number_max_ = 398;
+    const unsigned int user_token_number_max_ = 397;
     const token_number_type undef_token_ = 2;
     const token_number_type undef_token_ = 2;
 
 
     if (static_cast<int>(t) <= yyeof_)
     if (static_cast<int>(t) <= yyeof_)
@@ -1470,28 +1465,28 @@ namespace isc { namespace dhcp {
   {
   {
       switch (other.type_get ())
       switch (other.type_get ())
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 203: // db_type
-      case 395: // duid_type
-      case 428: // ncr_protocol_value
-      case 437: // replace_client_name_value
+      case 157: // value
+      case 161: // map_value
+      case 202: // db_type
+      case 394: // duid_type
+      case 427: // ncr_protocol_value
+      case 435: // replace_client_name_value
         value.copy< ElementPtr > (other.value);
         value.copy< ElementPtr > (other.value);
         break;
         break;
 
 
-      case 143: // "boolean"
+      case 142: // "boolean"
         value.copy< bool > (other.value);
         value.copy< bool > (other.value);
         break;
         break;
 
 
-      case 142: // "floating point"
+      case 141: // "floating point"
         value.copy< double > (other.value);
         value.copy< double > (other.value);
         break;
         break;
 
 
-      case 141: // "integer"
+      case 140: // "integer"
         value.copy< int64_t > (other.value);
         value.copy< int64_t > (other.value);
         break;
         break;
 
 
-      case 140: // "constant string"
+      case 139: // "constant string"
         value.copy< std::string > (other.value);
         value.copy< std::string > (other.value);
         break;
         break;
 
 
@@ -1512,28 +1507,28 @@ namespace isc { namespace dhcp {
     (void) v;
     (void) v;
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 203: // db_type
-      case 395: // duid_type
-      case 428: // ncr_protocol_value
-      case 437: // replace_client_name_value
+      case 157: // value
+      case 161: // map_value
+      case 202: // db_type
+      case 394: // duid_type
+      case 427: // ncr_protocol_value
+      case 435: // replace_client_name_value
         value.copy< ElementPtr > (v);
         value.copy< ElementPtr > (v);
         break;
         break;
 
 
-      case 143: // "boolean"
+      case 142: // "boolean"
         value.copy< bool > (v);
         value.copy< bool > (v);
         break;
         break;
 
 
-      case 142: // "floating point"
+      case 141: // "floating point"
         value.copy< double > (v);
         value.copy< double > (v);
         break;
         break;
 
 
-      case 141: // "integer"
+      case 140: // "integer"
         value.copy< int64_t > (v);
         value.copy< int64_t > (v);
         break;
         break;
 
 
-      case 140: // "constant string"
+      case 139: // "constant string"
         value.copy< std::string > (v);
         value.copy< std::string > (v);
         break;
         break;
 
 
@@ -1613,28 +1608,28 @@ namespace isc { namespace dhcp {
     // Type destructor.
     // Type destructor.
     switch (yytype)
     switch (yytype)
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 203: // db_type
-      case 395: // duid_type
-      case 428: // ncr_protocol_value
-      case 437: // replace_client_name_value
+      case 157: // value
+      case 161: // map_value
+      case 202: // db_type
+      case 394: // duid_type
+      case 427: // ncr_protocol_value
+      case 435: // replace_client_name_value
         value.template destroy< ElementPtr > ();
         value.template destroy< ElementPtr > ();
         break;
         break;
 
 
-      case 143: // "boolean"
+      case 142: // "boolean"
         value.template destroy< bool > ();
         value.template destroy< bool > ();
         break;
         break;
 
 
-      case 142: // "floating point"
+      case 141: // "floating point"
         value.template destroy< double > ();
         value.template destroy< double > ();
         break;
         break;
 
 
-      case 141: // "integer"
+      case 140: // "integer"
         value.template destroy< int64_t > ();
         value.template destroy< int64_t > ();
         break;
         break;
 
 
-      case 140: // "constant string"
+      case 139: // "constant string"
         value.template destroy< std::string > ();
         value.template destroy< std::string > ();
         break;
         break;
 
 
@@ -1661,28 +1656,28 @@ namespace isc { namespace dhcp {
     super_type::move(s);
     super_type::move(s);
       switch (this->type_get ())
       switch (this->type_get ())
     {
     {
-      case 158: // value
-      case 162: // map_value
-      case 203: // db_type
-      case 395: // duid_type
-      case 428: // ncr_protocol_value
-      case 437: // replace_client_name_value
+      case 157: // value
+      case 161: // map_value
+      case 202: // db_type
+      case 394: // duid_type
+      case 427: // ncr_protocol_value
+      case 435: // replace_client_name_value
         value.move< ElementPtr > (s.value);
         value.move< ElementPtr > (s.value);
         break;
         break;
 
 
-      case 143: // "boolean"
+      case 142: // "boolean"
         value.move< bool > (s.value);
         value.move< bool > (s.value);
         break;
         break;
 
 
-      case 142: // "floating point"
+      case 141: // "floating point"
         value.move< double > (s.value);
         value.move< double > (s.value);
         break;
         break;
 
 
-      case 141: // "integer"
+      case 140: // "integer"
         value.move< int64_t > (s.value);
         value.move< int64_t > (s.value);
         break;
         break;
 
 
-      case 140: // "constant string"
+      case 139: // "constant string"
         value.move< std::string > (s.value);
         value.move< std::string > (s.value);
         break;
         break;
 
 
@@ -1755,7 +1750,7 @@ namespace isc { namespace dhcp {
      365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
      365,   366,   367,   368,   369,   370,   371,   372,   373,   374,
      375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
      375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
      385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
      385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398
+     395,   396,   397
     };
     };
     return static_cast<token_type> (yytoken_number_[type]);
     return static_cast<token_type> (yytoken_number_[type]);
   }
   }
@@ -2397,12 +2392,6 @@ namespace isc { namespace dhcp {
   }
   }
 
 
   Dhcp6Parser::symbol_type
   Dhcp6Parser::symbol_type
-  Dhcp6Parser::make_ALLOW_CLIENT_UPDATE (const location_type& l)
-  {
-    return symbol_type (token::TOKEN_ALLOW_CLIENT_UPDATE, l);
-  }
-
-  Dhcp6Parser::symbol_type
   Dhcp6Parser::make_OVERRIDE_NO_UPDATE (const location_type& l)
   Dhcp6Parser::make_OVERRIDE_NO_UPDATE (const location_type& l)
   {
   {
     return symbol_type (token::TOKEN_OVERRIDE_NO_UPDATE, l);
     return symbol_type (token::TOKEN_OVERRIDE_NO_UPDATE, l);
@@ -2615,7 +2604,7 @@ namespace isc { namespace dhcp {
 
 
 #line 14 "dhcp6_parser.yy" // lalr1.cc:377
 #line 14 "dhcp6_parser.yy" // lalr1.cc:377
 } } // isc::dhcp
 } } // isc::dhcp
-#line 2619 "dhcp6_parser.h" // lalr1.cc:377
+#line 2608 "dhcp6_parser.h" // lalr1.cc:377
 
 
 
 
 
 

+ 0 - 7
src/bin/dhcp6/dhcp6_parser.yy

@@ -161,7 +161,6 @@ using namespace std;
   NCR_PROTOCOL "ncr-protocol"
   NCR_PROTOCOL "ncr-protocol"
   NCR_FORMAT "ncr-format"
   NCR_FORMAT "ncr-format"
   ALWAYS_INCLUDE_FQDN "always-include-fqdn"
   ALWAYS_INCLUDE_FQDN "always-include-fqdn"
-  ALLOW_CLIENT_UPDATE "allow-client-update"
   OVERRIDE_NO_UPDATE "override-no-update"
   OVERRIDE_NO_UPDATE "override-no-update"
   OVERRIDE_CLIENT_UPDATE "override-client-update"
   OVERRIDE_CLIENT_UPDATE "override-client-update"
   REPLACE_CLIENT_NAME "replace-client-name"
   REPLACE_CLIENT_NAME "replace-client-name"
@@ -1575,7 +1574,6 @@ dhcp_ddns_param: enable_updates
                | ncr_protocol
                | ncr_protocol
                | ncr_format
                | ncr_format
                | always_include_fqdn
                | always_include_fqdn
-               | allow_client_update
                | override_no_update
                | override_no_update
                | override_client_update
                | override_client_update
                | replace_client_name
                | replace_client_name
@@ -1652,11 +1650,6 @@ always_include_fqdn: ALWAYS_INCLUDE_FQDN COLON BOOLEAN {
     ctx.stack_.back()->set("always-include-fqdn", b);
     ctx.stack_.back()->set("always-include-fqdn", b);
 };
 };
 
 
-allow_client_update: ALLOW_CLIENT_UPDATE COLON BOOLEAN {
-    ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
-    ctx.stack_.back()->set("allow-client-update",  b);
-};
-
 override_no_update: OVERRIDE_NO_UPDATE COLON BOOLEAN {
 override_no_update: OVERRIDE_NO_UPDATE COLON BOOLEAN {
     ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
     ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("override-no-update", b);
     ctx.stack_.back()->set("override-no-update", b);

+ 10 - 12
src/bin/dhcp6/json_config_parser.cc

@@ -54,6 +54,7 @@ using namespace isc;
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
 using namespace isc::asiolink;
+using namespace isc::hooks;
 
 
 namespace {
 namespace {
 
 
@@ -638,11 +639,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
     // for option definitions. This is equivalent to commiting empty container.
     // for option definitions. This is equivalent to commiting empty container.
     LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
     LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
 
 
-    // Some of the parsers alter state of the system that can't easily
-    // be undone. (Or alter it in a way such that undoing the change
-    // has the same risk of failure as doing the change.)
-    hooks::HooksLibrariesParser hooks_parser;
-
     // This is a way to convert ConstElementPtr to ElementPtr.
     // This is a way to convert ConstElementPtr to ElementPtr.
     // We need a config that can be edited, because we will insert
     // We need a config that can be edited, because we will insert
     // default values and will insert derived values as well.
     // default values and will insert derived values as well.
@@ -738,16 +734,16 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
             }
             }
 
 
             if (config_pair.first == "hooks-libraries") {
             if (config_pair.first == "hooks-libraries") {
-                hooks_parser.parse(config_pair.second);
-                hooks_parser.verifyLibraries();
+                HooksLibrariesParser hooks_parser;
+                HooksConfig& libraries = srv_config->getHooksConfig();
+                hooks_parser.parse(libraries, config_pair.second);
+                libraries.verifyLibraries(config_pair.second->getPosition());
                 continue;
                 continue;
             }
             }
 
 
             if (config_pair.first == "dhcp-ddns") {
             if (config_pair.first == "dhcp-ddns") {
-                // Apply defaults if not in short cut
-                if (!D2ClientConfigParser::isShortCutDisabled(config_pair.second)) {
-                    D2ClientConfigParser::setAllDefaults(config_pair.second);
-                }
+                // Apply defaults
+                D2ClientConfigParser::setAllDefaults(config_pair.second);
                 D2ClientConfigParser parser;
                 D2ClientConfigParser parser;
                 D2ClientConfigPtr cfg = parser.parse(config_pair.second);
                 D2ClientConfigPtr cfg = parser.parse(config_pair.second);
                 srv_config->setD2ClientConfig(cfg);
                 srv_config->setD2ClientConfig(cfg);
@@ -860,7 +856,9 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
             // This occurs last as if it succeeds, there is no easy way to
             // This occurs last as if it succeeds, there is no easy way to
             // revert it.  As a result, the failure to commit a subsequent
             // revert it.  As a result, the failure to commit a subsequent
             // change causes problems when trying to roll back.
             // change causes problems when trying to roll back.
-            hooks_parser.loadLibraries();
+            const HooksConfig& libraries =
+                CfgMgr::instance().getStagingCfg()->getHooksConfig();
+            libraries.loadLibraries();
         }
         }
         catch (const isc::Exception& ex) {
         catch (const isc::Exception& ex) {
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());

+ 1 - 1
src/bin/dhcp6/location.hh

@@ -1,4 +1,4 @@
-// Generated 201703010915
+// Generated 201703041501
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Locations for Bison parsers in C++
 // Locations for Bison parsers in C++

+ 1 - 1
src/bin/dhcp6/position.hh

@@ -1,4 +1,4 @@
-// Generated 201703010915
+// Generated 201703041501
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Positions for Bison parsers in C++
 // Positions for Bison parsers in C++

+ 1 - 1
src/bin/dhcp6/stack.hh

@@ -1,4 +1,4 @@
-// Generated 201703010915
+// Generated 201703041501
 // A Bison parser, made by GNU Bison 3.0.4.
 // A Bison parser, made by GNU Bison 3.0.4.
 
 
 // Stack handling for Bison parsers in C++
 // Stack handling for Bison parsers in C++

+ 0 - 2
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -3954,7 +3954,6 @@ TEST_F(Dhcp6ParserTest, d2ClientConfig) {
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
         "     \"always-include-fqdn\" : true, "
-        "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"replace-client-name\" : \"when-present\", "
         "     \"replace-client-name\" : \"when-present\", "
@@ -4015,7 +4014,6 @@ TEST_F(Dhcp6ParserTest, invalidD2ClientConfig) {
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
         "     \"always-include-fqdn\" : true, "
-        "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"replace-client-name\" : \"when-present\", "
         "     \"replace-client-name\" : \"when-present\", "

+ 0 - 1
src/bin/dhcp6/tests/d2_unittest.cc

@@ -114,7 +114,6 @@ Dhcp6SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
         "     \"always-include-fqdn\" : true, "
-        "     \"allow-client-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-no-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"override-client-update\" : true, "
         "     \"replace-client-name\" : \"when-present\", "
         "     \"replace-client-name\" : \"when-present\", "

+ 1 - 1
src/lib/Makefile.am

@@ -1,3 +1,3 @@
 # The following build order must be maintained.
 # The following build order must be maintained.
-SUBDIRS = exceptions util log cryptolink dns cc hooks asiolink testutils dhcp config \
+SUBDIRS = exceptions util log cryptolink dns cc asiolink testutils hooks dhcp config \
 	      stats asiodns dhcp_ddns eval dhcpsrv cfgrpt process http
 	      stats asiodns dhcp_ddns eval dhcpsrv cfgrpt process http

+ 29 - 47
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -989,25 +989,8 @@ D2ClientConfigPtr
 D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
 D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
     D2ClientConfigPtr new_config;
     D2ClientConfigPtr new_config;
 
 
-    if (isShortCutDisabled(client_config)) {
-      // If enable-updates is the only parameter and it is false then
-      // we're done.  This allows for an abbreviated configuration entry
-      // that only contains that flag.  Use the default D2ClientConfig
-      // constructor to a create a disabled instance.
-      new_config.reset(new D2ClientConfig());
-      return (new_config);
-    }
-
-    // As isShortCutDisabled() was called this cannot fail
-    bool enable_updates = client_config->get("enable-updates")->boolValue();
-
     // Get all parameters that are needed to create the D2ClientConfig.
     // Get all parameters that are needed to create the D2ClientConfig.
-    std::string qualifying_suffix;
-    bool found_qualifying_suffix = false;
-    if (client_config->contains("qualifying-suffix")) {
-            qualifying_suffix = getString(client_config, "qualifying-suffix");
-            found_qualifying_suffix = true;
-    }   
+    bool enable_updates = getBoolean(client_config, "enable-updates");
 
 
     IOAddress server_ip = getIOAddress(client_config, "server-ip");
     IOAddress server_ip = getIOAddress(client_config, "server-ip");
 
 
@@ -1028,8 +1011,6 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
     bool always_include_fqdn =
     bool always_include_fqdn =
         getBoolean(client_config, "always-include-fqdn");
         getBoolean(client_config, "always-include-fqdn");
 
 
-    // bool allow_client_update; (unused)
-
     bool override_no_update =
     bool override_no_update =
         getBoolean(client_config, "override-no-update");
         getBoolean(client_config, "override-no-update");
 
 
@@ -1042,14 +1023,13 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
     std::string generated_prefix =
     std::string generated_prefix =
         getString(client_config, "generated-prefix");
         getString(client_config, "generated-prefix");
 
 
-
-    // Qualifying-suffix is required when updates are enabled
-    if (enable_updates && !found_qualifying_suffix) {
-        isc_throw(DhcpConfigError,
-                  "parameter 'qualifying-suffix' is required when "
-                  "updates are enabled ("
-                  << client_config->getPosition() << ")");
-    }
+    // qualifying-suffix is the only parameter which has no default
+    std::string qualifying_suffix = "";
+    bool found_qualifying_suffix = false;
+    if (client_config->contains("qualifying-suffix")) {
+            qualifying_suffix = getString(client_config, "qualifying-suffix");
+            found_qualifying_suffix = true;
+    }   
 
 
     IOAddress sender_ip(0);
     IOAddress sender_ip(0);
     if (sender_ip_str.empty()) {
     if (sender_ip_str.empty()) {
@@ -1066,6 +1046,14 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
         }
         }
     }
     }
 
 
+    // Qualifying-suffix is required when updates are enabled
+    if (enable_updates && !found_qualifying_suffix) {
+        isc_throw(DhcpConfigError,
+                  "parameter 'qualifying-suffix' is required when "
+                  "updates are enabled ("
+                  << client_config->getPosition() << ")");
+    }
+
     // Now we check for logical errors. This repeats what is done in
     // Now we check for logical errors. This repeats what is done in
     // D2ClientConfig::validate(), but doing it here permits us to
     // D2ClientConfig::validate(), but doing it here permits us to
     // emit meaningful parameter position info in the error.
     // emit meaningful parameter position info in the error.
@@ -1104,19 +1092,19 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
     try {
     try {
         // Attempt to create the new client config.
         // Attempt to create the new client config.
         new_config.reset(new D2ClientConfig(enable_updates,
         new_config.reset(new D2ClientConfig(enable_updates,
-                                                      server_ip,
-                                                      server_port,
-                                                      sender_ip,
-                                                      sender_port,
-                                                      max_queue_size,
-                                                      ncr_protocol,
-                                                      ncr_format,
-                                                      always_include_fqdn,
-                                                      override_no_update,
-                                                      override_client_update,
-                                                      replace_client_name_mode,
-                                                      generated_prefix,
-                                                      qualifying_suffix));
+                                            server_ip,
+                                            server_port,
+                                            sender_ip,
+                                            sender_port,
+                                            max_queue_size,
+                                            ncr_protocol,
+                                            ncr_format,
+                                            always_include_fqdn,
+                                            override_no_update,
+                                            override_client_update,
+                                            replace_client_name_mode,
+                                            generated_prefix,
+                                            qualifying_suffix));
 
 
     }  catch (const std::exception& ex) {
     }  catch (const std::exception& ex) {
         isc_throw(DhcpConfigError, ex.what() << " ("
         isc_throw(DhcpConfigError, ex.what() << " ("
@@ -1126,12 +1114,6 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
     return(new_config);
     return(new_config);
 }
 }
 
 
-bool
-D2ClientConfigParser::isShortCutDisabled(isc::data::ConstElementPtr d2_config) {
-    bool value = getBoolean(d2_config, "enable-updates");
-    return (!value && (d2_config->mapValue().size() == 1));
-}
-
 /// @brief This table defines default values for D2 client configuration
 /// @brief This table defines default values for D2 client configuration
 const SimpleDefaults D2ClientConfigParser::D2_CLIENT_CONFIG_DEFAULTS = {
 const SimpleDefaults D2ClientConfigParser::D2_CLIENT_CONFIG_DEFAULTS = {
     // enable-updates is unconditionally required
     // enable-updates is unconditionally required

+ 0 - 12
src/lib/dhcpsrv/parsers/dhcp_parsers.h

@@ -753,7 +753,6 @@ public:
     /// -# ncr-protocol
     /// -# ncr-protocol
     /// -# ncr-format
     /// -# ncr-format
     /// -# always-include-fqdn
     /// -# always-include-fqdn
-    /// -# allow-client-update
     /// -# override-no-update
     /// -# override-no-update
     /// -# override-client-update
     /// -# override-client-update
     /// -# replace-client-name
     /// -# replace-client-name
@@ -762,17 +761,6 @@ public:
     /// @return returns a pointer to newly created D2ClientConfig.
     /// @return returns a pointer to newly created D2ClientConfig.
     D2ClientConfigPtr parse(isc::data::ConstElementPtr d2_client_cfg);
     D2ClientConfigPtr parse(isc::data::ConstElementPtr d2_client_cfg);
 
 
-    /// @brief Check the short cut disabled updates condition
-    ///
-    /// The condition is that the d2 client configuration is
-    /// reduced to "enable-updates": false
-    ///
-    /// @param d2_config d2 client configuration
-    /// @return true if and only if the condition matches.
-    /// @throw DhcpConfigError if enable-updates is not present or
-    /// is not a boolean
-    static bool isShortCutDisabled(isc::data::ConstElementPtr d2_config);
-
     /// @brief Defaults for the D2 client configuration.
     /// @brief Defaults for the D2 client configuration.
     static const isc::data::SimpleDefaults D2_CLIENT_CONFIG_DEFAULTS;
     static const isc::data::SimpleDefaults D2_CLIENT_CONFIG_DEFAULTS;
 
 

+ 23 - 5
src/lib/dhcpsrv/srv_config.cc

@@ -110,6 +110,14 @@ SrvConfig::copy(SrvConfig& new_config) const {
     new_config.class_dictionary_.reset(new ClientClassDictionary(*class_dictionary_));
     new_config.class_dictionary_.reset(new ClientClassDictionary(*class_dictionary_));
     // Replace the D2 client configuration
     // Replace the D2 client configuration
     new_config.setD2ClientConfig(getD2ClientConfig());
     new_config.setD2ClientConfig(getD2ClientConfig());
+    // Replace configured hooks libraries.
+    new_config.hooks_config_.clear();
+    using namespace isc::hooks;
+    for (HookLibsCollection::const_iterator it =
+           hooks_config_.get().begin();
+         it != hooks_config_.get().end(); ++it) {
+        new_config.hooks_config_.add(it->first, it->second);
+    }
 }
 }
 
 
 void
 void
@@ -151,11 +159,21 @@ SrvConfig::equals(const SrvConfig& other) const {
         }
         }
     }
     }
     // Logging information is equal between objects, so check other values.
     // Logging information is equal between objects, so check other values.
-    return ((*cfg_iface_ == *other.cfg_iface_) &&
-            (*cfg_option_def_ == *other.cfg_option_def_) &&
-            (*cfg_option_ == *other.cfg_option_) &&
-            (*class_dictionary_ == *other.class_dictionary_) &&
-            (*d2_client_config_ == *other.d2_client_config_));
+    if ((*cfg_iface_ != *other.cfg_iface_) ||
+        (*cfg_option_def_ != *other.cfg_option_def_) ||
+        (*cfg_option_ != *other.cfg_option_) ||
+        (*class_dictionary_ != *other.class_dictionary_) ||
+        (*d2_client_config_ != *other.d2_client_config_)) {
+        return (false);
+    }
+    // Now only configured hooks libraries can differ.
+    // If number of configured hooks libraries are different, then
+    // configurations aren't equal.
+    if (hooks_config_.get().size() != other.hooks_config_.get().size()) {
+        return (false);
+    }
+    // Pass through all configured hooks libraries.
+    return (hooks_config_.equal(other.hooks_config_));
 }
 }
 
 
 void
 void

+ 18 - 0
src/lib/dhcpsrv/srv_config.h

@@ -22,6 +22,7 @@
 #include <dhcpsrv/client_class_def.h>
 #include <dhcpsrv/client_class_def.h>
 #include <dhcpsrv/d2_client_cfg.h>
 #include <dhcpsrv/d2_client_cfg.h>
 #include <dhcpsrv/logging_info.h>
 #include <dhcpsrv/logging_info.h>
+#include <hooks/hooks_config.h>
 #include <cc/data.h>
 #include <cc/data.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 #include <vector>
 #include <vector>
@@ -365,6 +366,20 @@ public:
         class_dictionary_ = dictionary;
         class_dictionary_ = dictionary;
     }
     }
 
 
+    /// @brief Returns non-const reference to configured hooks libraries.
+    ///
+    /// @return non-const reference to configured hooks libraries.
+    isc::hooks::HooksConfig& getHooksConfig() {
+        return (hooks_config_);
+    }
+
+    /// @brief Returns const reference to configured hooks libraries.
+    ///
+    /// @return const reference to configured hooks libraries.
+    const isc::hooks::HooksConfig& getHooksConfig() const {
+        return (hooks_config_);
+    }
+
     /// @brief Copies the current configuration to a new configuration.
     /// @brief Copies the current configuration to a new configuration.
     ///
     ///
     /// This method copies the parameters stored in the configuration to
     /// This method copies the parameters stored in the configuration to
@@ -593,6 +608,9 @@ private:
     /// @brief Pointer to the dictionary of global client class definitions
     /// @brief Pointer to the dictionary of global client class definitions
     ClientClassDictionaryPtr class_dictionary_;
     ClientClassDictionaryPtr class_dictionary_;
 
 
+    /// @brief Configured hooks libraries.
+    isc::hooks::HooksConfig hooks_config_;
+
     /// @brief Decline Period time
     /// @brief Decline Period time
     ///
     ///
     /// This timer specifies decline probation period, the time after a declined
     /// This timer specifies decline probation period, the time after a declined

+ 22 - 53
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -18,10 +18,10 @@
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/cfg_mac_source.h>
 #include <dhcpsrv/cfg_mac_source.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
-#include <hooks/hooks_parser.h>
 #include <dhcpsrv/tests/test_libraries.h>
 #include <dhcpsrv/tests/test_libraries.h>
 #include <dhcpsrv/testutils/config_result_check.h>
 #include <dhcpsrv/testutils/config_result_check.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
+#include <hooks/hooks_parser.h>
 #include <hooks/hooks_manager.h>
 #include <hooks/hooks_manager.h>
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
@@ -377,10 +377,12 @@ public:
                 }
                 }
 
 
                 if (config_pair.first == "hooks-libraries") {
                 if (config_pair.first == "hooks-libraries") {
-                    hooks_libraries_parser_.reset(new HooksLibrariesParser());
-                    hooks_libraries_parser_->parse(config_pair.second);
-                    hooks_libraries_parser_->verifyLibraries();
-                    hooks_libraries_parser_->loadLibraries();
+                    HooksLibrariesParser hook_parser;
+                    HooksConfig&  libraries =
+                        CfgMgr::instance().getStagingCfg()->getHooksConfig();
+                    hook_parser.parse(libraries, config_pair.second);
+                    libraries.verifyLibraries(config_pair.second->getPosition());
+                    libraries.loadLibraries();
                     continue;
                     continue;
                 }
                 }
             }
             }
@@ -528,8 +530,7 @@ public:
 
 
         /// D2 client configuration code is in this library
         /// D2 client configuration code is in this library
         ConstElementPtr d2_client = config->get("dhcp-ddns");
         ConstElementPtr d2_client = config->get("dhcp-ddns");
-        if (d2_client &&
-            !D2ClientConfigParser::isShortCutDisabled(d2_client)) {
+        if (d2_client) {
             D2ClientConfigParser::setAllDefaults(d2_client);
             D2ClientConfigParser::setAllDefaults(d2_client);
         }
         }
     }
     }
@@ -610,10 +611,10 @@ public:
         CfgMgr::instance().setD2ClientConfig(tmp);
         CfgMgr::instance().setD2ClientConfig(tmp);
     }
     }
 
 
-    /// @brief Parsers used in the parsing of the configuration
-    ///
-    /// Allows the tests to interrogate the state of the parsers (if required).
-    boost::shared_ptr<HooksLibrariesParser> hooks_libraries_parser_;
+    /// Allows the tests to interrogate the state of the libraries (if required).
+    const isc::hooks::HookLibsCollection& getLibraries() {
+        return (CfgMgr::instance().getStagingCfg()->getHooksConfig().get());
+    }
 
 
     /// @brief specifies IP protocol family (AF_INET or AF_INET6)
     /// @brief specifies IP protocol family (AF_INET or AF_INET6)
     uint16_t family_;
     uint16_t family_;
@@ -1306,8 +1307,7 @@ TEST_F(ParseConfigTest, noHooksLibraries) {
     ASSERT_TRUE(rcode == 0) << error_text_;
     ASSERT_TRUE(rcode == 0) << error_text_;
 
 
     // Check that the parser recorded nothing.
     // Check that the parser recorded nothing.
-    isc::hooks::HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     EXPECT_TRUE(libraries.empty());
     EXPECT_TRUE(libraries.empty());
 
 
     // Check that there are still no libraries loaded.
     // Check that there are still no libraries loaded.
@@ -1329,8 +1329,7 @@ TEST_F(ParseConfigTest, oneHooksLibrary) {
     ASSERT_TRUE(rcode == 0) << error_text_;
     ASSERT_TRUE(rcode == 0) << error_text_;
 
 
     // Check that the parser recorded a single library.
     // Check that the parser recorded a single library.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     ASSERT_EQ(1, libraries.size());
     ASSERT_EQ(1, libraries.size());
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
 
 
@@ -1355,8 +1354,7 @@ TEST_F(ParseConfigTest, twoHooksLibraries) {
     ASSERT_TRUE(rcode == 0) << error_text_;
     ASSERT_TRUE(rcode == 0) << error_text_;
 
 
     // Check that the parser recorded two libraries in the expected order.
     // Check that the parser recorded two libraries in the expected order.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     ASSERT_EQ(2, libraries.size());
     ASSERT_EQ(2, libraries.size());
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[1].first);
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[1].first);
@@ -1393,8 +1391,7 @@ TEST_F(ParseConfigTest, reconfigureSameHooksLibraries) {
     // The list has not changed between the two parse operations. However,
     // The list has not changed between the two parse operations. However,
     // the paramters (or the files they could point to) could have
     // the paramters (or the files they could point to) could have
     // changed, so the libraries are reloaded anyway.
     // changed, so the libraries are reloaded anyway.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     ASSERT_EQ(2, libraries.size());
     ASSERT_EQ(2, libraries.size());
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[1].first);
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[1].first);
@@ -1432,8 +1429,7 @@ TEST_F(ParseConfigTest, reconfigureReverseHooksLibraries) {
     ASSERT_TRUE(rcode == 0) << error_text_;
     ASSERT_TRUE(rcode == 0) << error_text_;
 
 
     // The list has changed, and this is what we should see.
     // The list has changed, and this is what we should see.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     ASSERT_EQ(2, libraries.size());
     ASSERT_EQ(2, libraries.size());
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[1].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[1].first);
@@ -1469,8 +1465,7 @@ TEST_F(ParseConfigTest, reconfigureZeroHooksLibraries) {
     ASSERT_TRUE(rcode == 0) << error_text_;
     ASSERT_TRUE(rcode == 0) << error_text_;
 
 
     // The list has changed, and this is what we should see.
     // The list has changed, and this is what we should see.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     EXPECT_TRUE(libraries.empty());
     EXPECT_TRUE(libraries.empty());
 
 
     // Check that no libraries are currently loaded
     // Check that no libraries are currently loaded
@@ -1501,8 +1496,7 @@ TEST_F(ParseConfigTest, invalidHooksLibraries) {
 
 
     // Check that the parser recorded the names but, as they were in error,
     // Check that the parser recorded the names but, as they were in error,
     // does not flag them as changed.
     // does not flag them as changed.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     ASSERT_EQ(3, libraries.size());
     ASSERT_EQ(3, libraries.size());
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(NOT_PRESENT_LIBRARY, libraries[1].first);
     EXPECT_EQ(NOT_PRESENT_LIBRARY, libraries[1].first);
@@ -1543,8 +1537,7 @@ TEST_F(ParseConfigTest, reconfigureInvalidHooksLibraries) {
 
 
     // Check that the parser recorded the names but, as the library set was
     // Check that the parser recorded the names but, as the library set was
     // incorrect, did not mark the configuration as changed.
     // incorrect, did not mark the configuration as changed.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     ASSERT_EQ(3, libraries.size());
     ASSERT_EQ(3, libraries.size());
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(NOT_PRESENT_LIBRARY, libraries[1].first);
     EXPECT_EQ(NOT_PRESENT_LIBRARY, libraries[1].first);
@@ -1648,8 +1641,7 @@ TEST_F(ParseConfigTest, HooksLibrariesParameters) {
     ASSERT_EQ(0, rcode);
     ASSERT_EQ(0, rcode);
 
 
     // Check that the parser recorded the names.
     // Check that the parser recorded the names.
-    HookLibsCollection libraries;
-    hooks_libraries_parser_->getLibraries(libraries);
+    isc::hooks::HookLibsCollection libraries = getLibraries();
     ASSERT_EQ(3, libraries.size());
     ASSERT_EQ(3, libraries.size());
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[1].first);
     EXPECT_EQ(CALLOUT_LIBRARY_2, libraries[1].first);
@@ -1866,29 +1858,6 @@ TEST_F(ParseConfigTest, parserDefaultsD2Config) {
 
 
 /// @brief Check various invalid D2 client configurations.
 /// @brief Check various invalid D2 client configurations.
 TEST_F(ParseConfigTest, invalidD2Config) {
 TEST_F(ParseConfigTest, invalidD2Config) {
-    std::string invalid_shortcuts[] = {
-        // Must supply at least enable-updates
-        "{ \"dhcp-ddns\" :"
-        "    {"
-        "    }"
-        "}",
-        // Enable-updates must be a boolean
-        "{ \"dhcp-ddns\" :"
-        "    {"
-        "     \"enable-updates\" : 0"
-        "    }"
-        "}",
-        // stop
-        ""
-    };
-    int i = 0;
-    while (!invalid_shortcuts[i].empty()) {
-        // Verify that the configuration string parsing throws
-        EXPECT_THROW(parseConfiguration(invalid_shortcuts[i]),
-                     DhcpConfigError);
-        i++;
-    }
-
     std::string invalid_configs[] = {
     std::string invalid_configs[] = {
         // Must supply qualifying-suffix when updates are enabled
         // Must supply qualifying-suffix when updates are enabled
         "{ \"dhcp-ddns\" :"
         "{ \"dhcp-ddns\" :"
@@ -2044,7 +2013,7 @@ TEST_F(ParseConfigTest, invalidD2Config) {
     // Iterate through the invalid configuration strings, attempting to
     // Iterate through the invalid configuration strings, attempting to
     // parse each one.  They should fail to parse, but fail gracefully.
     // parse each one.  They should fail to parse, but fail gracefully.
     D2ClientConfigPtr current_config;
     D2ClientConfigPtr current_config;
-    i = 0;
+    int i = 0;
     while (!invalid_configs[i].empty()) {
     while (!invalid_configs[i].empty()) {
         // Verify that the configuration string parses without throwing.
         // Verify that the configuration string parses without throwing.
         int rcode = parseConfiguration(invalid_configs[i]);
         int rcode = parseConfiguration(invalid_configs[i]);

+ 27 - 0
src/lib/dhcpsrv/tests/srv_config_unittest.cc

@@ -400,4 +400,31 @@ TEST_F(SrvConfigTest, equality) {
     EXPECT_FALSE(conf1 != conf2);
     EXPECT_FALSE(conf1 != conf2);
 }
 }
 
 
+// Verifies that we can get and set configured hooks libraries
+TEST_F(SrvConfigTest, hooksLibraries) {
+    SrvConfig conf(32);
+    isc::hooks::HooksConfig& libraries = conf.getHooksConfig();
+
+    // Upon construction configured hooks libraries should be empty.
+    EXPECT_EQ(0, libraries.get().size());
+
+    // Verify we can update it.
+    isc::data::ConstElementPtr elem0;
+    libraries.add("foo", elem0);
+    std::string config = "{ \"library\": \"bar\" }";
+    isc::data::ConstElementPtr elem1 = isc::data::Element::fromJSON(config);
+    libraries.add("bar", elem1);
+    EXPECT_EQ(2, libraries.get().size());
+    EXPECT_EQ(2, conf.getHooksConfig().get().size());
+
+    // Try to copy
+    SrvConfig copied(64);
+    ASSERT_TRUE(conf != copied);
+    ASSERT_NO_THROW(conf.copy(copied));
+    ASSERT_TRUE(conf == copied);
+    EXPECT_EQ(2, copied.getHooksConfig().get().size());
+
+    EXPECT_TRUE(copied.getHooksConfig().equal(conf.getHooksConfig()));
+}
+
 } // end of anonymous namespace
 } // end of anonymous namespace

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

@@ -36,6 +36,7 @@ libkea_hooks_la_SOURCES += callout_manager.cc callout_manager.h
 libkea_hooks_la_SOURCES += hooks.h
 libkea_hooks_la_SOURCES += hooks.h
 libkea_hooks_la_SOURCES += hooks_log.cc hooks_log.h
 libkea_hooks_la_SOURCES += hooks_log.cc hooks_log.h
 libkea_hooks_la_SOURCES += hooks_manager.cc hooks_manager.h
 libkea_hooks_la_SOURCES += hooks_manager.cc hooks_manager.h
+libkea_hooks_la_SOURCES += hooks_config.cc hooks_config.h
 libkea_hooks_la_SOURCES += hooks_parser.cc hooks_parser.h
 libkea_hooks_la_SOURCES += hooks_parser.cc hooks_parser.h
 libkea_hooks_la_SOURCES += libinfo.cc libinfo.h
 libkea_hooks_la_SOURCES += libinfo.cc libinfo.h
 libkea_hooks_la_SOURCES += library_handle.cc library_handle.h
 libkea_hooks_la_SOURCES += library_handle.cc library_handle.h

+ 129 - 0
src/lib/hooks/hooks_config.cc

@@ -0,0 +1,129 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <hooks/hooks_config.h>
+#include <hooks/hooks_manager.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::data;
+
+namespace isc {
+namespace hooks {
+
+void
+HooksConfig::verifyLibraries(const Element::Position& position) const {
+    // The code used to follow this logic:
+    //
+    // Check if the list of libraries has changed.  If not, nothing is done
+    // - the command "DhcpN libreload" is required to reload the same
+    // libraries (this prevents needless reloads when anything else in the
+    // configuration is changed).
+    //
+    // We no longer rely on this. Parameters can change. And even if the
+    // parameters stay the same, they could point to files that could
+    // change. We can skip loading routines only if there were and there still
+    // are no libraries specified.
+    vector<string> current_libraries = HooksManager::getLibraryNames();
+    if (current_libraries.empty() && libraries_.empty()) {
+        return;
+    }
+
+    // Library list has changed, validate each of the libraries specified.
+    vector<string> lib_names = isc::hooks::extractNames(libraries_);
+    vector<string> error_libs = HooksManager::validateLibraries(lib_names);
+    if (!error_libs.empty()) {
+
+        // Construct the list of libraries in error for the message.
+        string error_list = error_libs[0];
+        for (size_t i = 1; i < error_libs.size(); ++i) {
+            error_list += (string(", ") + error_libs[i]);
+        }
+        isc_throw(InvalidHooksLibraries,
+                  "hooks libraries failed to validate - "
+                  "library or libraries in error are: "
+                  << error_list << "(" << position << ")");
+    }
+}
+
+void
+HooksConfig::loadLibraries() const {
+    /// Commits the list of libraries to the configuration manager storage if
+    /// the list of libraries has changed.
+    /// @todo: Delete any stored CalloutHandles before reloading the
+    /// libraries
+    if (!HooksManager::loadLibraries(libraries_)) {
+        isc_throw(InvalidHooksLibraries,
+                  "One or more hook libraries failed to load");
+    }
+}
+
+bool
+HooksConfig::equal(const HooksConfig& other) const {
+
+    /// @todo: This comparision assumes that the library order is not relevant,
+    /// so [ lib1, lib2 ] is equal to [ lib2, lib1 ]. However, this is not strictly
+    /// true, because callouts execution is called in other they're loaded. Therefore
+    /// changing the libraries order may change the server behavior.
+    ///
+    /// We don't have any libraries that are interacting (or would change their behavior
+    /// depending on the order in which their callouts are executed), so the code is
+    /// ok for now.
+    for (isc::hooks::HookLibsCollection::const_iterator this_it = libraries_.begin();
+         this_it != libraries_.end(); ++this_it) {
+        bool match = false;
+        for (isc::hooks::HookLibsCollection::const_iterator other_it =
+                 other.libraries_.begin(); other_it != other.libraries_.end(); ++other_it) {
+            if (this_it->first != other_it->first) {
+                continue;
+            }
+            if (isNull(this_it->second) && isNull(other_it->second)) {
+                match = true;
+                break;
+            }
+            if (isNull(this_it->second) || isNull(other_it->second)) {
+                continue;
+            }
+            if (this_it->second->equals(*other_it->second)) {
+                match = true;
+                break;
+            }
+        }
+        // No match found for the particular hooks library so return false.
+        if (!match) {
+            return (false);
+        }
+    }
+    return (true);
+}
+
+ElementPtr
+HooksConfig::toElement() const {
+    // hooks-libraries is a list of maps
+    ElementPtr result = Element::createList();
+    // Iterate through libraries
+    for (HookLibsCollection::const_iterator hl = libraries_.begin();
+         hl != libraries_.end(); ++hl) {
+        // Entries are maps
+        ElementPtr map = Element::createMap();
+        // Set the library name
+        map->set("library", Element::create(hl->first));
+        // Set parameters
+        if (!isNull(hl->second)) {
+            map->set("parameters", hl->second);
+        } else {
+            map->set("parameters", Element::createMap());
+        }
+        // Push to the list
+        result->add(map);
+    }
+    return (result);
+}
+
+};
+};

+ 108 - 0
src/lib/hooks/hooks_config.h

@@ -0,0 +1,108 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef HOOKS_CONFIG_H
+#define HOOKS_CONFIG_H
+
+#include <exceptions/exceptions.h>
+#include <cc/data.h>
+#include <cc/cfg_to_element.h>
+#include <hooks/libinfo.h>
+
+namespace isc {
+namespace hooks {
+
+/// @brief Exception thrown when a library failed to validate
+class InvalidHooksLibraries : public Exception {
+ public:
+    InvalidHooksLibraries(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Wrapper class that holds hooks libraries configuration
+///
+/// This was moved from HooksLibrariesParser
+///
+/// However, this class does more than just check the list of library names.
+/// It does two other things:
+/// # validate libraries
+/// # load libraries
+/// and it provides a toElement() method to unparse a configuration.
+///
+/// @todo add toElement() unit tests
+class HooksConfig : public isc::data::CfgToElement {
+public:
+    /// @brief Default constructor.
+    ///
+    HooksConfig() : libraries_() { }
+
+    /// @brief Adds additional hooks libraries.
+    ///
+    /// @param libname full filename with path to the library.
+    /// @param parameters map of parameters that configure the library.
+    void add(std::string libname, isc::data::ConstElementPtr parameters) {
+        libraries_.push_back(make_pair(libname, parameters));
+    }
+
+    /// @brief Provides access to the configured hooks libraries.
+    ///
+    /// @note The const reference returned is only valid as long as the
+    /// object that returned it.
+    const isc::hooks::HookLibsCollection& get() const {
+        return libraries_;
+    }
+
+    /// @brief Removes all configured hooks libraries.
+    void clear() {
+        libraries_.clear();
+    }
+
+    /// @brief Compares two Hooks Config classes for equality
+    ///
+    /// @param other other hooksconfig to compare with
+    bool equal(const HooksConfig& other) const;
+
+    /// @brief Verifies that libraries stored in libraries_ are valid.
+    ///
+    /// This method is a smart wrapper around @ref
+    /// isc::hooks::HooksManager::validateLibraries().
+    /// It tries to validate all the libraries stored in libraries_.
+    ///
+    /// @param position position of the hooks-library map for error reporting
+    /// @throw InvalidHooksLibraries if any issue is discovered.
+    void verifyLibraries(const isc::data::Element::Position& position) const;
+
+    /// @brief Commits hooks libraries configuration.
+    ///
+    /// This method calls necessary methods in HooksManager that will unload
+    /// any libraries that may be currently loaded and will load the actual
+    /// libraries. Providing that the specified libraries are valid and are
+    /// different to those already loaded, this method loads the new set of
+    /// libraries (and unloads the existing set).
+    ///
+    /// @throw InvalidHooksLibraries if the call to HooksManager fails.
+    void loadLibraries() const;
+
+    /// @brief Unparse a configuration object
+    ///
+    /// Returns an element which must parse into the same object, i.e.
+    /// @code
+    /// for all valid config C parse(parse(C)->toElement()) == parse(C)
+    /// @endcode
+    ///
+    /// @return a pointer to a configuration which can be parsed into
+    /// the initial configuration object
+    isc::data::ElementPtr toElement() const;
+
+private:
+    /// @brief List of hooks libraries with their configuration parameters
+    isc::hooks::HookLibsCollection libraries_;
+};
+
+};
+};
+
+#endif // HOOKS_CONFIG_H

+ 5 - 55
src/lib/hooks/hooks_parser.cc

@@ -9,7 +9,6 @@
 #include <cc/data.h>
 #include <cc/data.h>
 #include <cc/dhcp_config_error.h>
 #include <cc/dhcp_config_error.h>
 #include <hooks/hooks_parser.h>
 #include <hooks/hooks_parser.h>
-#include <hooks/hooks_manager.h>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/foreach.hpp>
 #include <boost/foreach.hpp>
 #include <util/strutil.h>
 #include <util/strutil.h>
@@ -23,19 +22,17 @@ using namespace isc::dhcp;
 namespace isc {
 namespace isc {
 namespace hooks {
 namespace hooks {
 
 
-// ******************** HooksLibrariesParser *************************
+// @todo use the flat style, split into list and item
+
 void
 void
-HooksLibrariesParser::parse(ConstElementPtr value) {
+HooksLibrariesParser::parse(HooksConfig& libraries, ConstElementPtr value) {
     // Initialize.
     // Initialize.
-    libraries_.clear();
+    libraries.clear();
 
 
     if (!value) {
     if (!value) {
         isc_throw(DhcpConfigError, "Tried to parse null hooks libraries");
         isc_throw(DhcpConfigError, "Tried to parse null hooks libraries");
     }
     }
 
 
-    // Let's store
-    position_ = value->getPosition();
-
     // This is the new syntax.  Iterate through it and get each map.
     // This is the new syntax.  Iterate through it and get each map.
     BOOST_FOREACH(ConstElementPtr library_entry, value->listValue()) {
     BOOST_FOREACH(ConstElementPtr library_entry, value->listValue()) {
         ConstElementPtr parameters;
         ConstElementPtr parameters;
@@ -105,56 +102,9 @@ HooksLibrariesParser::parse(ConstElementPtr value) {
                 " (" << library_entry->getPosition() << ")");
                 " (" << library_entry->getPosition() << ")");
         }
         }
 
 
-        libraries_.push_back(make_pair(libname, parameters));
-    }
-}
-
-void HooksLibrariesParser::verifyLibraries() {
-    // Check if the list of libraries has changed.  If not, nothing is done
-    // - the command "DhcpN libreload" is required to reload the same
-    // libraries (this prevents needless reloads when anything else in the
-    // configuration is changed).
-
-    // We no longer rely on this. Parameters can change. And even if the
-    // parameters stay the same, they could point to files that could
-    // change.
-    vector<string> current_libraries = HooksManager::getLibraryNames();
-    if (current_libraries.empty() && libraries_.empty()) {
-        return;
-    }
-
-    // Library list has changed, validate each of the libraries specified.
-    vector<string> lib_names = isc::hooks::extractNames(libraries_);
-    vector<string> error_libs = HooksManager::validateLibraries(lib_names);
-    if (!error_libs.empty()) {
-
-        // Construct the list of libraries in error for the message.
-        string error_list = error_libs[0];
-        for (size_t i = 1; i < error_libs.size(); ++i) {
-            error_list += (string(", ") + error_libs[i]);
-        }
-        isc_throw(DhcpConfigError, "hooks libraries failed to validate - "
-                  "library or libraries in error are: " << error_list
-                  << "(" << position_ << ")");
-    }
-}
-
-void
-HooksLibrariesParser::loadLibraries() {
-    /// Commits the list of libraries to the configuration manager storage if
-    /// the list of libraries has changed.
-    /// @todo: Delete any stored CalloutHandles before reloading the
-    /// libraries
-    if (!HooksManager::loadLibraries(libraries_)) {
-        isc_throw(DhcpConfigError, "One or more hook libraries failed to load");
+        libraries.add(libname, parameters);
     }
     }
 }
 }
 
 
-// Method for testing
-void
-HooksLibrariesParser::getLibraries(isc::hooks::HookLibsCollection& libraries) {
-    libraries = libraries_;
-}
-
 }
 }
 }
 }

+ 6 - 62
src/lib/hooks/hooks_parser.h

@@ -9,7 +9,7 @@
 
 
 #include <cc/data.h>
 #include <cc/data.h>
 #include <cc/simple_parser.h>
 #include <cc/simple_parser.h>
-#include <hooks/libinfo.h>
+#include <hooks/hooks_config.h>
 
 
 namespace isc {
 namespace isc {
 namespace hooks {
 namespace hooks {
@@ -17,23 +17,7 @@ namespace hooks {
 /// @brief Parser for hooks library list
 /// @brief Parser for hooks library list
 ///
 ///
 /// This parser handles the list of hooks libraries.  This is an optional list,
 /// This parser handles the list of hooks libraries.  This is an optional list,
-/// which may be empty.
-///
-/// However, the parser does more than just check the list of library names.
-/// It does two other things:
-///
-/// -# The problem faced with the hooks libraries is that we wish to avoid
-/// reloading the libraries if they have not changed.  (This would cause the
-/// "unload" and "load" methods to run.  Although libraries should be written
-/// to cope with this, it is feasible that such an action may be costly in
-/// terms of time and resources, or may cause side effects such as clearing
-/// an internal cache.)  To this end, the parser also checks the list against
-/// the list of libraries current loaded and notes if there are changes.
-/// -# If there are, the parser validates the libraries; it opens them and
-/// checks that the "version" function exists and returns the correct value.
-///
-/// Only if the library list has changed and the libraries are valid will the
-/// change be applied.
+/// which may be empty, and is encapsulated into a @ref HooksConfig object.
 class HooksLibrariesParser : public isc::data::SimpleParser {
 class HooksLibrariesParser : public isc::data::SimpleParser {
 public:
 public:
 
 
@@ -68,51 +52,11 @@ public:
     /// -# That there is an optional 'parameters' element.
     /// -# That there is an optional 'parameters' element.
     /// -# That there are no other element.
     /// -# That there are no other element.
     ///
     ///
-    /// If you want to check whether the library is really present (if the file
-    /// is on disk, it is really a library and that it could be loaded), call
-    /// @ref verifyLibraries().
-    ///
-    /// This method stores parsed libraries in libraries_.
-    ///
-    /// @param value pointer to the content of parsed values
-    void parse(isc::data::ConstElementPtr value);
-
-    /// @brief Verifies that libraries stored in libraries_ are valid.
-    ///
-    /// This method is a smart wrapper around @ref
-    /// isc::hooks::HooksManager::validateLibraries().
-    /// It tries to validate all the libraries stored in libraries_.
-    /// @throw DhcpConfigError if any issue is discovered.
-    void verifyLibraries();
-
-    /// @brief Commits hooks libraries data
-    ///
-    /// This method calls necessary methods in HooksManager that will unload
-    /// any libraries that may be currently loaded and will load the actual
-    /// libraries. Providing that the specified libraries are valid and are
-    /// different to those already loaded, this method loads the new set of
-    /// libraries (and unloads the existing set).
-    ///
-    /// @throw DhcpConfigError if the call to HooksManager fails.
-    void loadLibraries();
-
-    /// @brief Returns list of parsed libraries
+    /// This method stores parsed libraries in libraries.
     ///
     ///
-    /// Principally for testing, this returns the list of libraries as well as
-    /// an indication as to whether the list is different from the list of
-    /// libraries already loaded.
-    ///
-    /// @param [out] libraries List of libraries that were specified in the
-    ///        new configuration.
-    void getLibraries(isc::hooks::HookLibsCollection& libraries);
-
-private:
-    /// List of hooks libraries with their configuration parameters
-    isc::hooks::HookLibsCollection libraries_;
-
-    /// Position of the original element is stored in case we need to report an
-    /// error later.
-    isc::data::Element::Position position_;
+    /// @param libraries parsed libraries information will be stored here
+    /// @param value pointer to the content to be parsed
+    void parse(HooksConfig& libraries, isc::data::ConstElementPtr value);
 };
 };
 
 
 }; // namespace isc::hooks
 }; // namespace isc::hooks