]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5351] Checkpoint: todo servers, doc, host including DB
authorFrancis Dupont <fdupont@isc.org>
Fri, 1 Dec 2017 15:19:33 +0000 (16:19 +0100)
committerFrancis Dupont <fdupont@isc.org>
Fri, 1 Dec 2017 15:19:33 +0000 (16:19 +0100)
29 files changed:
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/lib/dhcpsrv/cfg_db_access.cc
src/lib/dhcpsrv/cfg_db_access.h
src/lib/dhcpsrv/cfg_duid.cc
src/lib/dhcpsrv/cfg_duid.h
src/lib/dhcpsrv/cfg_iface.cc
src/lib/dhcpsrv/cfg_iface.h
src/lib/dhcpsrv/d2_client_cfg.cc
src/lib/dhcpsrv/d2_client_cfg.h
src/lib/dhcpsrv/host.cc
src/lib/dhcpsrv/host.h
src/lib/dhcpsrv/logging.cc
src/lib/dhcpsrv/logging_info.cc
src/lib/dhcpsrv/logging_info.h
src/lib/dhcpsrv/parsers/dbaccess_parser.cc
src/lib/dhcpsrv/parsers/dhcp_parsers.cc
src/lib/dhcpsrv/parsers/duid_config_parser.cc
src/lib/dhcpsrv/parsers/ifaces_config_parser.cc
src/lib/dhcpsrv/tests/cfg_db_access_unittest.cc
src/lib/dhcpsrv/tests/cfg_duid_unittest.cc
src/lib/dhcpsrv/tests/cfg_iface_unittest.cc
src/lib/dhcpsrv/tests/d2_client_unittest.cc
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
src/lib/dhcpsrv/tests/ifaces_config_parser_unittest.cc
src/lib/dhcpsrv/tests/logging_info_unittest.cc
src/lib/testutils/user_context_utils.cc

index 82bd35ead65fdebb550e188a9730b31ab6ec465b..3f9027a4d6b7484e96bc9c109bc1f0011668313f 100644 (file)
@@ -582,7 +582,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser4Context::INTERFACES_CONFIG:
     case isc::dhcp::Parser4Context::LEASE_DATABASE:
     case isc::dhcp::Parser4Context::HOSTS_DATABASE:
-    case isc::dhcp::Parser4Context::HOOKS_LIBRARIES:
     case isc::dhcp::Parser4Context::SUBNET4:
     case isc::dhcp::Parser4Context::POOLS:
     case isc::dhcp::Parser4Context::SHARED_NETWORK:
@@ -604,7 +603,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser4Context::INTERFACES_CONFIG:
     case isc::dhcp::Parser4Context::LEASE_DATABASE:
     case isc::dhcp::Parser4Context::HOSTS_DATABASE:
-    case isc::dhcp::Parser4Context::HOOKS_LIBRARIES:
     case isc::dhcp::Parser4Context::SUBNET4:
     case isc::dhcp::Parser4Context::POOLS:
     case isc::dhcp::Parser4Context::SHARED_NETWORK:
index 4a8d54b0f9c04fe4287ed3155929ba50d563d58d..e31f1570cf4802a8a7ceffa34257e231fcfc2da5 100644 (file)
@@ -760,13 +760,11 @@ sub_hooks_library: LCURLY_BRACKET {
 
 hooks_params: hooks_param
             | hooks_params COMMA hooks_param
+            | unknown_map_entry
             ;
 
 hooks_param: library
            | parameters
-           | user_context
-           | comment
-           | unknown_map_entry
            ;
 
 library: LIBRARY {
index b89595fa8beef044cc058e82cf51c4f9dec430f9..c83ae0328513437f4492485f23e1d65374e7cd0b 100644 (file)
@@ -812,7 +812,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser6Context::INTERFACES_CONFIG:
     case isc::dhcp::Parser6Context::LEASE_DATABASE:
     case isc::dhcp::Parser6Context::HOSTS_DATABASE:
-    case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
     case isc::dhcp::Parser6Context::SUBNET6:
     case isc::dhcp::Parser6Context::SHARED_NETWORK:
     case isc::dhcp::Parser6Context::OPTION_DEF:
@@ -836,7 +835,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser6Context::INTERFACES_CONFIG:
     case isc::dhcp::Parser6Context::LEASE_DATABASE:
     case isc::dhcp::Parser6Context::HOSTS_DATABASE:
-    case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
     case isc::dhcp::Parser6Context::SUBNET6:
     case isc::dhcp::Parser6Context::SHARED_NETWORK:
     case isc::dhcp::Parser6Context::OPTION_DEF:
index de8a416ea6261814fb4090e1a285fc3516af8402..3b8bef3e2a7c0a959664c55f280b11c9558b4d10 100644 (file)
@@ -753,13 +753,11 @@ sub_hooks_library: LCURLY_BRACKET {
 
 hooks_params: hooks_param
             | hooks_params COMMA hooks_param
+            | unknown_map_entry
             ;
 
 hooks_param: library
            | parameters
-           | user_context
-           | comment
-           | unknown_map_entry
            ;
 
 library: LIBRARY {
index e93631dc7b6cd1c9803903703f3e53c6d3409eb5..53ae5001c4ea0b9e971d921f05ede90b091ce9de 100644 (file)
@@ -65,12 +65,12 @@ CfgDbAccess::getAccessString(const std::string& access_string) const {
     return (s.str());
 }
 
-ElementPtr
-CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
-    ElementPtr result = Element::createMap();
+void
+CfgDbAccess::toElementDbAccessString(const std::string& dbaccess,
+                                     ElementPtr map) {
     // Code from DatabaseConnection::parse
     if (dbaccess.empty()) {
-        return (result);
+        return;
     }
     std::vector<std::string> tokens;
     boost::split(tokens, dbaccess, boost::is_any_of(std::string("\t ")));
@@ -86,7 +86,7 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
                 int64_t int_value;
                 try {
                     int_value = boost::lexical_cast<int64_t>(value);
-                    result->set(keyword, Element::create(int_value));
+                    map->set(keyword, Element::create(int_value));
                 } catch (...) {
                     isc_throw(ToElementError, "invalid DB access "
                               << "integer parameter: "
@@ -95,9 +95,9 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
             } else if ((keyword == "persist") ||
                        (keyword == "readonly")) {
                 if (value == "true") {
-                    result->set(keyword, Element::create(true));
+                    map->set(keyword, Element::create(true));
                 } else if (value == "false") {
-                    result->set(keyword, Element::create(false));
+                    map->set(keyword, Element::create(false));
                 } else {
                     isc_throw(ToElementError, "invalid DB access "
                               << "boolean parameter: "
@@ -110,7 +110,7 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
                        (keyword == "name") ||
                        (keyword == "contact_points") ||
                        (keyword == "keyspace")) {
-                result->set(keyword, Element::create(value));
+                map->set(keyword, Element::create(value));
             } else {
                 isc_throw(ToElementError, "unknown DB access parameter: "
                           << keyword << "=" << value);
@@ -120,6 +120,23 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
                       << ", expected format is name=value");
         }
     }
+}
+
+ElementPtr
+CfgLeaseDbAccess::toElement() const {
+    ElementPtr result = Element::createMap();
+    // Add user context
+    contextToElement(result);
+    CfgDbAccess::toElementDbAccessString(lease_db_access_, result);
+    return (result);
+}
+
+ElementPtr
+CfgHostDbAccess::toElement() const {
+    ElementPtr result = Element::createMap();
+    // Add user context
+    contextToElement(result);
+    CfgDbAccess::toElementDbAccessString(host_db_access_, result);
     return (result);
 }
 
index 2c87e4dafce22a384f14b4a553988360ee1a5b83..b74e94cc7f4b9f7e1468bf532aa8b258531722f7 100644 (file)
@@ -8,6 +8,7 @@
 #define CFG_DBACCESS_H
 
 #include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
 #include <boost/shared_ptr.hpp>
 #include <string>
 
@@ -19,7 +20,7 @@ namespace dhcp {
 ///
 /// The database access strings use the same format as the strings
 /// passed to the @ref isc::dhcp::LeaseMgrFactory::create function.
-class CfgDbAccess {
+class CfgDbAccess : public UserContext {
 public:
 
     /// @brief Constructor.
@@ -67,9 +68,10 @@ public:
     /// @brief Unparse an access string
     ///
     /// @param dbaccess the database access string
-    /// @return a pointer to configuration
-    static
-    isc::data::ElementPtr toElementDbAccessString(const std::string& dbaccess);
+    /// @param map the element map where the access string is unparse
+    static void
+    toElementDbAccessString(const std::string& dbaccess,
+                            isc::data::ElementPtr map);
 
 protected:
 
@@ -106,9 +108,7 @@ struct CfgLeaseDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
     /// @ref isc::data::CfgToElement::toElement
     ///
     /// @result a pointer to a configuration
-    virtual isc::data::ElementPtr toElement() const {
-        return (CfgDbAccess::toElementDbAccessString(lease_db_access_));
-    }
+    virtual isc::data::ElementPtr toElement() const;
 };
 
 struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
@@ -120,12 +120,9 @@ struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
     /// @ref isc::data::CfgToElement::toElement
     ///
     /// @result a pointer to a configuration
-    virtual isc::data::ElementPtr toElement() const {
-        return (CfgDbAccess::toElementDbAccessString(host_db_access_));
-    }
+    virtual isc::data::ElementPtr toElement() const;
 };
 
 }
 }
-
 #endif // CFG_DBACCESS_H
index fffae1aa7ee0016c500b70ff1e827410e097adf1..4eebc10e094c61c915848a85da36d5f960dab8e4 100644 (file)
@@ -77,6 +77,8 @@ CfgDUID::create(const std::string& duid_file_path) const {
 ElementPtr
 CfgDUID::toElement() const {
     ElementPtr result = Element::createMap();
+    // Set user context
+    contextToElement(result);
     // The type item is required
     std::string duid_type = "LLT";
     switch (type_) {
index dec70221f5fd717f8b569242a941713e67a77a69..e93738eb04852369d64f032a4680f67bc53e62ce 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <dhcp/duid.h>
 #include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
 #include <boost/shared_ptr.hpp>
 #include <stdint.h>
 #include <vector>
@@ -26,7 +27,7 @@ namespace dhcp {
 /// generate. It also allows for overriding entire default DUID or parts of
 /// it via configuration file. This class holds the DUID configuration
 /// specified in the server configuration file.
-class CfgDUID : public isc::data::CfgToElement {
+class CfgDUID : public UserContext, public isc::data::CfgToElement {
 public:
 
     /// @brief Constructor.
index 8aad5eca52302e4eb905ff128394b846c9a31814..ebb64f2dc859a2973803ab8073879e52592fb144 100644 (file)
@@ -441,6 +441,9 @@ ElementPtr
 CfgIface::toElement() const {
     ElementPtr result = Element::createMap();
 
+    // Set user context
+    contextToElement(result);
+
     // Set interfaces
     ElementPtr ifaces = Element::createList();
     if (wildcard_used_) {
index 57344c2911ceafa9fbfb6e3497dcc1d2ba795938..6b36045d43f3bbb8bffaa83074a4e392bc636857 100644 (file)
@@ -10,6 +10,7 @@
 #include <asiolink/io_address.h>
 #include <dhcp/iface_mgr.h>
 #include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
 #include <boost/shared_ptr.hpp>
 #include <map>
 #include <set>
@@ -126,7 +127,7 @@ public:
 /// to which it is bound. It is allowed to select multiple addresses on the
 /// particular interface explicitly, e.g. "eth0/192.168.8.1",
 /// "eth0/192.168.8.2".
-class CfgIface : public isc::data::CfgToElement {
+class CfgIface : public UserContext, public isc::data::CfgToElement {
 public:
 
     /// @brief Socket type used by the DHCPv4 server.
index 14c45a5bc30dee8efc75483df7a4db1c177e6a83..12718cf7ade1721523dec00636c0227f881e4b1c 100644 (file)
@@ -222,6 +222,8 @@ D2ClientConfig::toText() const {
 ElementPtr
 D2ClientConfig::toElement() const {
     ElementPtr result = Element::createMap();
+    // Set user context
+    contextToElement(result);
     // Set enable-updates
     result->set("enable-updates", Element::create(enable_updates_));
     // Set qualifying-suffix
index 99a357ca197d494a7f30934668553ef9fc52ffdf..b9e3b8a7a2fc29b16c2f5bb1a4dfebecdb29d4c4 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <asiolink/io_address.h>
 #include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
 #include <dhcp_ddns/ncr_io.h>
 #include <exceptions/exceptions.h>
 
@@ -48,7 +49,7 @@ public:
 /// parameters associated with DHCP-DDNS and acting as a client of D2.
 /// Instances of this class may be constructed through configuration parsing.
 ///
-class D2ClientConfig : public isc::data::CfgToElement {
+class D2ClientConfig : public UserContext, public isc::data::CfgToElement {
 public:
     /// @brief Default configuration constants.
     /// @todo For now these are hard-coded as configuration layer cannot
index 573047bdaf8fe4688210109f43113a21a09365bc..0df727130f6feaf624c174200ac56dd963533d2f 100644 (file)
@@ -409,6 +409,8 @@ Host::toElement4() const {
 
     // Prepare the map
     ElementPtr map = Element::createMap();
+    // Set the user context
+    contextToElement(map);
     // Set the identifier
     Host::IdentifierType id_type = getIdentifierType();
     if (id_type == Host::IDENT_HWADDR) {
index 1b3552429bf089e9b5f57c9ff5f82ea816b6f886..f4e99af17cbe436740ff0d15f703a4ee0162801d 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <asiolink/io_address.h>
 #include <cc/data.h>
+#include <cc/user_context.h>
 #include <dhcp/classify.h>
 #include <dhcp/duid.h>
 #include <dhcp/hwaddr.h>
@@ -171,7 +172,7 @@ typedef std::pair<IPv6ResrvIterator, IPv6ResrvIterator> IPv6ResrvRange;
 /// - disable IPv4 reservation without a need to set it to the 0.0.0.0 address
 /// Note that the last three operations are mainly required for managing
 /// host reservations which will be implemented later.
-class Host {
+class Host : public UserContext {
 public:
 
     /// @brief Type of the host identifier.
index d072bf8e980a2e0ac029242b4a64e4fb5df6e8ee..6fad9354b5287547ff52c448c5dedd8f4f9076c0 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-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
@@ -52,6 +52,12 @@ void LogConfigParser::parseConfigEntry(isc::data::ConstElementPtr entry) {
     // Remove default destinations as we are going to replace them.
     info.clearDestinations();
 
+    // Get user context
+    isc::data::ConstElementPtr user_context = entry->get("user-context");
+    if (user_context) {
+        info.setContext(user_context);
+    }
+
     // Get a name
     isc::data::ConstElementPtr name_ptr = entry->get("name");
     if (!name_ptr) {
index d052273c25fe79ffe26ff83f81a2a13132ed77e8..ff39f3a8864f4c811df8290e8fe34aaac51be143 100644 (file)
@@ -159,6 +159,8 @@ LoggingInfo::toSpec() const {
 ElementPtr
 LoggingInfo::toElement() const {
     ElementPtr result = Element::createMap();
+    // Set user context
+    contextToElement(result);
     // Set name
     result->set("name", Element::create(name_));
     // Set output_options if not empty
index 5dd5a1125773d1b18d9cc728ee56dc024905c3b9..d74fb4f16d3c09aae6afaeb0c194f179476656ba 100644 (file)
@@ -10,6 +10,7 @@
 #include <log/logger_level.h>
 #include <log/logger_specification.h>
 #include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
 #include <stdint.h>
 #include <vector>
 
@@ -20,6 +21,7 @@ namespace dhcp {
 ///
 /// This structure is used to keep log4cplus configuration parameters.
 struct LoggingDestination : public isc::data::CfgToElement {
+public:
 
     /// @brief defines logging destination output
     ///
@@ -71,7 +73,8 @@ struct LoggingDestination : public isc::data::CfgToElement {
 ///            "severity": "WARN",
 ///            "debuglevel": 99
 ///        },
-struct LoggingInfo : public isc::data::CfgToElement {
+class LoggingInfo : public UserContext, public isc::data::CfgToElement {
+public:
 
     /// @brief logging name
     std::string name_;
index e4231dc1e28b54e2c370b77342b13760391cf2a4..db54bbd137df00d6278a8a83d5f350b18349bc32 100644 (file)
@@ -56,6 +56,7 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
     int64_t lfc_interval = 0;
     int64_t timeout = 0;
     int64_t port = 0;
+    ConstElementPtr user_context;
     // 2. Update the copy with the passed keywords.
     BOOST_FOREACH(ConfigPair param, database_config->mapValue()) {
         try {
@@ -78,6 +79,9 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
                 values_copy[param.first] =
                     boost::lexical_cast<std::string>(port);
 
+            } else if (param.first == "user-context") {
+                user_context = param.second;
+
             } else {
                 values_copy[param.first] = param.second->stringValue();
             }
@@ -158,6 +162,9 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
         cfg_db->setHostDbAccessString(getDbAccessString());
     }
 
+    if (user_context) {
+        cfg_db->setContext(user_context);
+    }
 }
 
 // Create the database access string
index 06b97e4858b963bfe64c7bbdfaa7299eedd2d0fe..4f5c5f8fdd4bf2c634dc41ed1be8515f6fb62679 100644 (file)
@@ -1246,6 +1246,12 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
                   << client_config->getPosition() << ")");
     }
 
+    // Add user context
+    ConstElementPtr user_context = client_config->get("user-context");
+    if (user_context) {
+        new_config->setContext(user_context);
+    }
+
     return(new_config);
 }
 
index 4e0674b358d6e5dd514a9626ff9a1a0f413c9a0d..5817bafe7e8ad49be752e8186e90745d99a0f5cf 100644 (file)
@@ -74,6 +74,12 @@ DUIDConfigParser::parse(const CfgDUIDPtr& cfg,
         if (duid_configuration->contains(param)) {
             cfg->setPersist(getBoolean(duid_configuration, param));
         }
+
+        param = "user-context";
+        ConstElementPtr user_context = duid_configuration->get("user-context");
+        if (user_context) {
+            cfg->setContext(user_context);
+        }
     } catch (const DhcpConfigError&) {
         throw;
     } catch (const std::exception& ex) {
index bfa50a199ccd557b40621f9c498b44664bd7b883..c5559d810d9fb3c2fa6fb8ba9f12f89fc337e46c 100644 (file)
@@ -88,6 +88,11 @@ IfacesConfigParser::parse(const CfgIfacePtr& cfg,
                 }
             }
 
+            if (element.first == "user-context") {
+                cfg->setContext(element.second);
+                continue;
+            }
+
             // This should never happen as the input produced by the parser
             // see (src/bin/dhcpX/dhcpX_parser.yy) should not produce any
             // other parameter, so this case is only to catch bugs in
index cc8361ae500635d0e63ac7d0c4999714e0c4d993..4b86a32fd4547f1234f37b0c95ecd3b481bfa4b8 100644 (file)
@@ -19,6 +19,7 @@ using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::test;
+using namespace isc::data;
 
 namespace {
 
@@ -51,6 +52,12 @@ TEST(CfgDbAccessTest, setLeaseDbAccessString) {
     // Additional parameters are not in lease_db_access_
     runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
 
+    // Add and check user context
+    std::string user_context = "{ \"foo\": \"bar\" }";
+    cfg.setContext(Element::fromJSON(user_context));
+    expected = "{ \"user-context\": { \"foo\": \"bar\" }, \"type\": \"mysql\" }";
+    runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
+
     // If access string is empty, no parameters will be appended.
     ASSERT_NO_THROW(cfg.setLeaseDbAccessString(""));
     EXPECT_TRUE(cfg.getLeaseDbAccessString().empty());
@@ -75,6 +82,12 @@ TEST(CfgDbAccessTest, setHostDbAccessString) {
     // Additional parameters are not in host_db_access_
     runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
 
+    // Add and check user context
+    std::string user_context = "{ \"foo\": \"bar\" }";
+    cfg.setContext(Element::fromJSON(user_context));
+    expected = "{ \"user-context\": { \"foo\": \"bar\" }, \"type\": \"mysql\" }";
+    runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
+
     // If access string is empty, no parameters will be appended.
     ASSERT_NO_THROW(cfg.setHostDbAccessString(""));
     EXPECT_TRUE(cfg.getHostDbAccessString().empty());
index df9c7daf77a115c498ebbf45dd39f5802ad8bd08..d0109333a143747a8424787e0ba9663f1329c31e 100644 (file)
@@ -22,6 +22,7 @@
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::test;
+using namespace isc::data;
 
 namespace {
 
@@ -94,6 +95,7 @@ TEST_F(CfgDUIDTest, defaults) {
     EXPECT_EQ(0, cfg_duid.getTime());
     EXPECT_EQ(0, cfg_duid.getEnterpriseId());
     EXPECT_TRUE(cfg_duid.persist());
+    EXPECT_FALSE(cfg_duid.getContext());
 
     std::string expected = "{ \"type\": \"LLT\",\n"
         "\"identifier\": \"\",\n"
@@ -114,6 +116,8 @@ TEST_F(CfgDUIDTest, setValues) {
     ASSERT_NO_THROW(cfg_duid.setTime(32100));
     ASSERT_NO_THROW(cfg_duid.setEnterpriseId(10));
     ASSERT_NO_THROW(cfg_duid.setPersist(false));
+    std::string user_context = "{ \"comment\": \"foo\" }";
+    ASSERT_NO_THROW(cfg_duid.setContext(Element::fromJSON(user_context)));
 
     // Check that values have been set correctly.
     EXPECT_EQ(DUID::DUID_EN, cfg_duid.getType());
@@ -122,8 +126,12 @@ TEST_F(CfgDUIDTest, setValues) {
     EXPECT_EQ(32100, cfg_duid.getTime());
     EXPECT_EQ(10, cfg_duid.getEnterpriseId());
     EXPECT_FALSE(cfg_duid.persist());
+    ASSERT_TRUE(cfg_duid.getContext());
+    EXPECT_EQ(user_context, cfg_duid.getContext()->str());
 
-    std::string expected = "{ \"type\": \"EN\",\n"
+    std::string expected = "{\n"
+        " \"comment\": \"foo\",\n"
+        " \"type\": \"EN\",\n"
         " \"identifier\": \"ABCDEF\",\n"
         " \"htype\": 100,\n"
         " \"time\": 32100,\n"
index efea58bedab6b408803591acd1f777512cff6ee0..de68db8b86ef117e85986204087bd50ebd9c76ea 100644 (file)
@@ -15,6 +15,7 @@ using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::test;
+using namespace isc::data;
 
 namespace {
 
@@ -368,10 +369,13 @@ TEST_F(CfgIfaceTest, unparse) {
     EXPECT_NO_THROW(cfg4.use(AF_INET, "*"));
     EXPECT_NO_THROW(cfg4.use(AF_INET, "eth0"));
     EXPECT_NO_THROW(cfg4.use(AF_INET, "eth1/192.0.2.3"));
+    std::string comment = "{ \"comment\": \"foo\" }";
+    EXPECT_NO_THROW(cfg4.setContext(Element::fromJSON(comment)));
     
     // Check unparse
     std::string expected =
-        "{ \"interfaces\": [ \"*\", \"eth0\", \"eth1/192.0.2.3\" ], "
+        "{ \"comment\": \"foo\", "
+        "\"interfaces\": [ \"*\", \"eth0\", \"eth1/192.0.2.3\" ], "
         "\"re-detect\": false }";
     runToElementTest<CfgIface>(expected, cfg4);
 
@@ -380,9 +384,12 @@ TEST_F(CfgIfaceTest, unparse) {
     EXPECT_NO_THROW(cfg6.use(AF_INET6, "*"));
     EXPECT_NO_THROW(cfg6.use(AF_INET6, "eth1"));
     EXPECT_NO_THROW(cfg6.use(AF_INET6, "eth0/2001:db8:1::1"));
+    comment = "{ \"comment\": \"bar\" }";
+    EXPECT_NO_THROW(cfg6.setContext(Element::fromJSON(comment)));
 
     expected =
-        "{ \"interfaces\": [ \"*\", \"eth1\", \"eth0/2001:db8:1::1\" ], "
+        "{ \"comment\": \"bar\", "
+        "\"interfaces\": [ \"*\", \"eth1\", \"eth0/2001:db8:1::1\" ], "
         "\"re-detect\": false }";
     runToElementTest<CfgIface>(expected, cfg6);
 }
index 8bf3d4a86fe692f967ca0427160145fb99321583..856f4f775d45c279af9ea02ca32b55c1fb2f2501 100644 (file)
@@ -18,6 +18,7 @@ using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::util;
 using namespace isc::test;
+using namespace isc::data;
 using namespace isc;
 
 namespace {
@@ -101,6 +102,11 @@ TEST(D2ClientConfigTest, constructorsAndAccessors) {
 
     ASSERT_TRUE(d2_client_config);
 
+    // Add user context
+    std::string user_context = "{ \"comment\": \"foo\" }";
+    EXPECT_FALSE(d2_client_config->getContext());
+    d2_client_config->setContext(Element::fromJSON(user_context));
+
     // Verify that the accessors return the expected values.
     EXPECT_EQ(d2_client_config->getEnableUpdates(), enable_updates);
 
@@ -119,12 +125,16 @@ TEST(D2ClientConfigTest, constructorsAndAccessors) {
     EXPECT_EQ(d2_client_config->getGeneratedPrefix(), generated_prefix);
     EXPECT_EQ(d2_client_config->getQualifyingSuffix(), qualifying_suffix);
 
+    ASSERT_TRUE(d2_client_config->getContext());
+    EXPECT_EQ(d2_client_config->getContext()->str(), user_context);
+
     // Verify that toText called by << operator doesn't bomb.
     ASSERT_NO_THROW(std::cout << "toText test:" << std::endl <<
                     *d2_client_config << std::endl);
 
     // Verify what toElement returns.
     std::string expected = "{\n"
+        "\"comment\": \"foo\",\n"
         "\"enable-updates\": true,\n"
         "\"server-ip\": \"127.0.0.1\",\n"
         "\"server-port\": 477,\n"
index bbcb7edb7da57b7b3288b0779939404235068ee8..9ce068d667494606b8018684c7fb39d7364102f0 100644 (file)
@@ -1819,7 +1819,8 @@ TEST_F(ParseConfigTest, validD2Config) {
         "     \"override-client-update\" : true, "
         "     \"replace-client-name\" : \"when-present\", "
         "     \"generated-prefix\" : \"test.prefix\", "
-        "     \"qualifying-suffix\" : \"test.suffix.\" "
+        "     \"qualifying-suffix\" : \"test.suffix.\", "
+        "     \"user-context\": { \"foo\": \"bar\" } "
         "    }"
         "}";
 
@@ -1845,6 +1846,8 @@ TEST_F(ParseConfigTest, validD2Config) {
     EXPECT_EQ(D2ClientConfig::RCM_WHEN_PRESENT, d2_client_config->getReplaceClientNameMode());
     EXPECT_EQ("test.prefix", d2_client_config->getGeneratedPrefix());
     EXPECT_EQ("test.suffix.", d2_client_config->getQualifyingSuffix());
+    ASSERT_TRUE(d2_client_config->getContext());
+    EXPECT_EQ("{ \"foo\": \"bar\" }", d2_client_config->getContext()->str());
 
     // Verify that the configuration object unparses.
     ConstElementPtr expected;
@@ -1871,7 +1874,8 @@ TEST_F(ParseConfigTest, validD2Config) {
         "     \"override-client-update\" : false, "
         "     \"replace-client-name\" : \"never\", "
         "     \"generated-prefix\" : \"\", "
-        "     \"qualifying-suffix\" : \"\" "
+        "     \"qualifying-suffix\" : \"\", "
+        "     \"user-context\": { \"foo\": \"bar\" } "
         "    }"
         "}";
 
@@ -1896,6 +1900,8 @@ TEST_F(ParseConfigTest, validD2Config) {
     EXPECT_EQ(D2ClientConfig::RCM_NEVER, d2_client_config->getReplaceClientNameMode());
     EXPECT_EQ("", d2_client_config->getGeneratedPrefix());
     EXPECT_EQ("", d2_client_config->getQualifyingSuffix());
+    ASSERT_TRUE(d2_client_config->getContext());
+    EXPECT_EQ("{ \"foo\": \"bar\" }", d2_client_config->getContext()->str());
 
     ASSERT_NO_THROW(expected = Element::fromJSON(config_str2)->get("dhcp-ddns"));
     ASSERT_TRUE(expected);
index dff3a84c52772e0c642bf0d7a2290be2b244fc22..bd17b032fadbe426618fb7661f2c4a29266af97f 100644 (file)
@@ -107,7 +107,8 @@ TEST_F(IfacesConfigParserTest, toElement) {
 
     // Configuration with one interface.
     std::string config =
-        "{ \"interfaces\": [ \"eth0\" ], "
+        "{ \"user-context\": { \"foo\": \"bar\" }, "
+        "  \"interfaces\": [ \"eth0\" ], "
         "  \"dhcp-socket-type\": \"udp\","
         "  \"outbound-interface\": \"use-routing\", "
         "  \"re-detect\": false }";
index f7474c94ee519303ec7be90a3e7e68674805ea81..f7787650663ad3510aeb35261bb1e2e41f00f0f6 100644 (file)
@@ -12,6 +12,7 @@
 
 using namespace isc::dhcp;
 using namespace isc::test;
+using namespace isc::data;
 
 namespace {
 
@@ -71,7 +72,8 @@ TEST_F(LoggingInfoTest, defaults) {
     ASSERT_EQ(1, info_non_verbose.destinations_.size());
     EXPECT_EQ("stdout", info_non_verbose.destinations_[0].output_);
 
-    std::string header = "{\n"
+    std::string header = "{\n";
+    std::string begin =
         "\"name\": \"kea\",\n"
         "\"output_options\": [ {\n"
         " \"output\": \"stdout\",\n \"maxsize\": 10240000,\n"
@@ -79,7 +81,17 @@ TEST_F(LoggingInfoTest, defaults) {
         "\"severity\": \"";
     std::string dbglvl = "\",\n\"debuglevel\": ";
     std::string trailer = "\n}\n";
-    std::string expected = header + "INFO" + dbglvl + "0" + trailer;
+    std::string expected = header + begin + "INFO" + dbglvl + "0" + trailer;
+    runToElementTest<LoggingInfo>(expected, info_non_verbose);
+
+    // Add a user context
+    std::string comment = "\"comment\": \"foo\"";
+    std::string user_context = "{ " + comment + " }";
+    EXPECT_FALSE(info_non_verbose.getContext());
+    info_non_verbose.setContext(Element::fromJSON(user_context));
+    ASSERT_TRUE(info_non_verbose.getContext());
+    EXPECT_EQ(user_context, info_non_verbose.getContext()->str());
+    expected = header + comment + ",\n" + begin + "INFO" + dbglvl + "0" + trailer;
     runToElementTest<LoggingInfo>(expected, info_non_verbose);
 
     CfgMgr::instance().setVerbose(true);
@@ -94,7 +106,15 @@ TEST_F(LoggingInfoTest, defaults) {
     EXPECT_EQ(10240000, info_verbose.destinations_[0].maxsize_);
     EXPECT_EQ(1, info_verbose.destinations_[0].maxver_);
 
-    expected = header + "DEBUG" + dbglvl + "99" + trailer;
+    expected = header + begin + "DEBUG" + dbglvl + "99" + trailer;
+    runToElementTest<LoggingInfo>(expected, info_verbose);
+
+    // User comment again
+    EXPECT_FALSE(info_verbose.getContext());
+    info_verbose.setContext(Element::fromJSON(user_context));
+    ASSERT_TRUE(info_verbose.getContext());
+    EXPECT_EQ(user_context, info_verbose.getContext()->str());
+    expected = header + comment + ",\n" + begin + "DEBUG" + dbglvl + "99" + trailer;
     runToElementTest<LoggingInfo>(expected, info_verbose);
 }
 
index fc01075cd755b57f96a9f32a203f1c878dc80fa9..e6eb52b334b685f7574285792ded7334f83d50eb 100644 (file)
@@ -211,7 +211,7 @@ EP extractComments1(EP element) {
         if (user_context->size() > 0) {
             result->set("user-context", user_context);
         }
-        result->combine_set("comment", comment);
+        result->combine_set("comment", copy(comment, 0));
     }
 
     return (result);