]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[65-libyang-host_rebased] Updated after pool merge
authorFrancis Dupont <fdupont@isc.org>
Sat, 6 Oct 2018 10:22:07 +0000 (12:22 +0200)
committerFrancis Dupont <fdupont@isc.org>
Sat, 6 Oct 2018 10:22:07 +0000 (12:22 +0200)
1  2 
src/lib/yang/Makefile.am
src/lib/yang/tests/Makefile.am
src/lib/yang/tests/translator_host_unittests.cc
src/lib/yang/translator_host.cc

index bc7d227481b8830a6180724b4951f3ea481c1101,c505bccaeb96606f5805c4db82f6b07efe476a6e..fff4cd24f4f102167a1ce1146620a9af1bd74610
@@@ -12,8 -12,7 +12,9 @@@ libkea_yang_la_SOURCES += translator_op
  libkea_yang_la_SOURCES += translator_option_data.h
  libkea_yang_la_SOURCES += translator_option_def.cc
  libkea_yang_la_SOURCES += translator_option_def.h
 +libkea_yang_la_SOURCES += translator_pool.cc translator_pool.h
+ libkea_yang_la_SOURCES += translator_host.cc translator_host.h
 +libkea_yang_la_SOURCES += yang_models.h
  
  libkea_yang_la_LIBADD =  $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
  libkea_yang_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
@@@ -31,9 -30,9 +32,11 @@@ libkea_yang_include_HEADERS = 
        adaptor.h \
        sysrepo_error.h \
        translator.h \
+       translator_host.h \
        translator_option_data.h \
 -      translator_option_def.h
 +      translator_option_def.h \
-       translator_pool.h
++      translator_pool.h \
++      yang_models.h
  
  EXTRA_DIST = yang.dox
  # Distribute yang models.
index 58018a599b0600a22723208167277bf661f90466,9855e913a4c50ae350eeb80ef07ababe9e2e4922..d562c97a61f4dcc11b63bae7578714f4099e0e27
@@@ -22,7 -22,7 +22,8 @@@ run_unittests_SOURCES += sysrepo_setup.
  run_unittests_SOURCES += translator_unittests.cc
  run_unittests_SOURCES += translator_option_data_unittests.cc
  run_unittests_SOURCES += translator_option_def_unittests.cc
 +run_unittests_SOURCES += translator_pool_unittests.cc
+ run_unittests_SOURCES += translator_host_unittests.cc
  run_unittests_SOURCES += run_unittests.cc
  run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
  run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
index 0000000000000000000000000000000000000000,5adce13a18dd6aea98773950cac8d4edb2ae172b..52efa71bca50255c1c8986b09ccd5952529d6b10
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,181 +1,182 @@@
 -    useModel("kea-dhcp6-server");
+ // Copyright (C) 2018 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 <yang/translator_host.h>
++#include <yang/yang_models.h>
+ #include <yang/tests/sysrepo_setup.h>
+ #include <gtest/gtest.h>
+ #include <sstream>
+ using namespace std;
+ using namespace isc;
+ using namespace isc::data;
+ using namespace isc::yang;
+ using namespace isc::yang::test;
+ namespace {
+ /// @brief Translator name.
+ extern char const host_reservations[] = "host reservations";
+ /// @brief Test fixture class for @ref TranslatorHosts.
+ class TranslatorHostsTest :
+     public GenericTranslatorTest<host_reservations, TranslatorHosts> {
+ public:
+     /// Constructor.
+     TranslatorHostsTest() { }
+     /// Destructor (does nothing).
+     virtual ~TranslatorHostsTest() { }
+ };
+ // This test verifies that an empty host reservation list can be properly
+ // translated from YANG to JSON.
+ TEST_F(TranslatorHostsTest, getEmpty) {
 -    useModel("kea-dhcp6-server");
++    useModel(KEA_DHCP6_SERVER);
+     // Get the host reservation list and checks it is empty.
+     const string& xpath =
+         "/kea-dhcp6-server:config/subnet6/subnet6[id='111']/reservations";
+     ConstElementPtr hosts;
+     EXPECT_NO_THROW(hosts = t_obj_->getHosts(xpath));
+     ASSERT_TRUE(hosts);
+     ASSERT_EQ(Element::list, hosts->getType());
+     EXPECT_EQ(0, hosts->size());
+ }
+ // This test verifies that one host reservation can be properly
+ // translated from YANG to JSON.
+ TEST_F(TranslatorHostsTest, get) {
 -    useModel("kea-dhcp6-server");
++    useModel(KEA_DHCP6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/kea-dhcp6-server:config/subnet6/subnet6[id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& xsubnet = subnet + "/subnet";
+     EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
+     // Create the host reservation for 2001:db8::1.
+     const string& xpath = subnet + "/reservations";
+     ostringstream shost;
+     shost << xpath + "/host[identifier-type='hw-address']"
+           << "[identifier='00:01:02:03:04:05']";
+     const string& xaddr = shost.str() + "/ip-addresses";
+     S_Val s_addr(new Val("2001:db8::1"));
+     EXPECT_NO_THROW(sess_->set_item(xaddr.c_str(), s_addr));
+     // Get the host.
+     ConstElementPtr host;
+     EXPECT_NO_THROW(host = t_obj_->getHost(shost.str()));
+     ASSERT_TRUE(host);
+     ElementPtr expected = Element::createMap();
+     ElementPtr addresses = Element::createList();
+     addresses->add(Element::create(string("2001:db8::1")));
+     expected->set("hw-address", Element::create(string("00:01:02:03:04:05")));
+     expected->set("ip-addresses", addresses);
+     EXPECT_TRUE(expected->equals(*host));
+     // Get the host reservation list and checks the host reservation is in it.
+     ConstElementPtr hosts;
+     EXPECT_NO_THROW(hosts = t_obj_->getHosts(xpath));
+     ASSERT_TRUE(hosts);
+     ASSERT_EQ(Element::list, hosts->getType());
+     ASSERT_EQ(1, hosts->size());
+     EXPECT_TRUE(host->equals(*hosts->get(0)));
+ }
+ // This test verifies that an empty host reservation list can be properly
+ // translated from JSON to YANG.
+ TEST_F(TranslatorHostsTest, setEmpty) {
 -    useModel("kea-dhcp4-server");
++    useModel(KEA_DHCP6_SERVER);
+     // Create the subnet 2001:db8::/48 #111.
+     const string& subnet =
+         "/kea-dhcp6-server:config/subnet6/subnet6[id='111']";
+     S_Val v_subnet(new Val("2001:db8::/48", SR_STRING_T));
+     const string& xsubnet = subnet + "/subnet";
+     EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
+     // Set empty list.
+     const string& xpath = subnet + "/reservations";
+     ConstElementPtr hosts = Element::createList();
+     EXPECT_NO_THROW(t_obj_->setHosts(xpath, hosts));
+     // Get it back.
+     hosts.reset();
+     EXPECT_NO_THROW(hosts = t_obj_->getHosts(xpath));
+     ASSERT_TRUE(hosts);
+     ASSERT_EQ(Element::list, hosts->getType());
+     EXPECT_EQ(0, hosts->size());
+ }
+ // This test verifies that one host reservation can be properly
+ // translated from JSON to YANG.
+ TEST_F(TranslatorHostsTest, set) {
++    useModel(KEA_DHCP4_SERVER);
+     // Create the subnet 10.0.0.0/14 #111.
+     const string& subnet =
+         "/kea-dhcp4-server:config/subnet4/subnet4[id='111']";
+     S_Val v_subnet(new Val("10.0.0.0/24", SR_STRING_T));
+     const string& xsubnet = subnet + "/subnet";
+     EXPECT_NO_THROW(sess_->set_item(xsubnet.c_str(), v_subnet));
+     // Set one host.
+     const string& xpath = subnet + "/reservations";
+     ElementPtr hosts = Element::createList();
+     ElementPtr host = Element::createMap();
+     host->set("flex-id", Element::create(string("00:ff")));
+     host->set("ip-address", Element::create(string("10.0.0.1")));
+     host->set("hostname", Element::create(string("foo")));
+     hosts->add(host);
+     EXPECT_NO_THROW(t_obj_->setHosts(xpath, hosts));
+     // Get it back.
+     hosts.reset();
+     EXPECT_NO_THROW(hosts = t_obj_->getHosts(xpath));
+     ASSERT_TRUE(hosts);
+     ASSERT_EQ(Element::list, hosts->getType());
+     ASSERT_EQ(1, hosts->size());
+     EXPECT_TRUE(host->equals(*hosts->get(0)));
+     // Check the tree representation.
+     S_Tree tree;
+     EXPECT_NO_THROW(tree = sess_->get_subtree("/kea-dhcp4-server:config"));
+     ASSERT_TRUE(tree);
+     string expected =
+         "kea-dhcp4-server:config (container)\n"
+         " |\n"
+         " -- subnet4 (container)\n"
+         "     |\n"
+         "     -- subnet4 (list instance)\n"
+         "         |\n"
+         "         -- id = 111\n"
+         "         |\n"
+         "         -- subnet = 10.0.0.0/24\n"
+         "         |\n"
+         "         -- reservations (container)\n"
+         "             |\n"
+         "             -- host (list instance)\n"
+         "                 |\n"
+         "                 -- identifier-type = flex-id\n"
+         "                 |\n"
+         "                 -- identifier = 00:ff\n"
+         "                 |\n"
+         "                 -- hostname = foo\n"
+         "                 |\n"
+         "                 -- ip-address = 10.0.0.1\n";
+     EXPECT_EQ(expected, tree->to_string(100));
+     // Check it validates.
+     EXPECT_NO_THROW(sess_->validate());
+ }
+ }; // end of anonymous namespace
index 0000000000000000000000000000000000000000,e13366be7d8e7ae64d5baf017d08643992667333..96fc7a51c7b096f16cb042b7f8b2d777189c5c98
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,273 +1,274 @@@
 -        if ((model_ == "kea-dhcp4-server") ||
 -            (model_ == "kea-dhcp6-server")) {
+ // Copyright (C) 2018 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 <yang/translator_host.h>
+ #include <yang/adaptor.h>
++#include <yang/yang_models.h>
+ #include <sstream>
+ using namespace std;
+ using namespace isc::data;
+ namespace isc {
+ namespace yang {
+ TranslatorHost::TranslatorHost(S_Session session, const string& model)
+     : TranslatorBasic(session),
+       TranslatorOptionData(session, model),
+       TranslatorOptionDataList(session, model),
+       model_(model) {
+ }
+ TranslatorHost::~TranslatorHost() {
+ }
+ ElementPtr
+     TranslatorHost::getHost(const string& xpath) {
+     try {
 -    if (model_ == "kea-dhcp4-server") {
++        if ((model_ == KEA_DHCP4_SERVER) ||
++            (model_ == KEA_DHCP6_SERVER)) {
+             return (getHostKea(xpath));
+         }
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error getting host reservation at '" << xpath
+                   << "': " << ex.what());
+     }
+     isc_throw(NotImplemented,
+               "getHost not implemented for the model: " << model_);
+ }
+ ElementPtr
+ TranslatorHost::getHostKea(const string& xpath) {
+     ConstElementPtr id_type = getItem(xpath + "/identifier-type");
+     ConstElementPtr id = getItem(xpath + "/identifier");
+     if (!id_type || !id) {
+         isc_throw(Unexpected, "getHostKea requires both identifier and "
+                   "identifier-type");
+     }
+     ElementPtr result = Element::createMap();
+     result->set(id_type->stringValue(), id);
+     ConstElementPtr hostname = getItem(xpath + "/hostname");
+     if (hostname) {
+         result->set("hostname", hostname);
+     }
 -    if (model_ == "kea-dhcp4-server") {
++    if (model_ == KEA_DHCP4_SERVER) {
+         ConstElementPtr address = getItem(xpath + "/ip-address");
+         if (address) {
+             result->set("ip-address", address);
+         }
+     } else {
+         ConstElementPtr addresses = getItems(xpath + "/ip-addresses");
+         if (addresses && (addresses->size() > 0)) {
+             result->set("ip-addresses", addresses);
+         }
+         ConstElementPtr prefixes = getItems(xpath + "/prefixes");
+         if (prefixes && (prefixes->size() > 0)) {
+             result->set("prefixes", prefixes);
+         }
+     }
+     ConstElementPtr options = getOptionDataList(xpath + "/option-data-list");
+     if (options && (options->size() > 0)) {
+         result->set("option-data", options);
+     }
+     ConstElementPtr classes = getItems(xpath + "/client-classes");
+     if (classes) {
+         result->set("client-classes", classes);
+     }
 -        if ((model_ == "kea-dhcp4-server") ||
 -            (model_ == "kea-dhcp6-server")) {
++    if (model_ == KEA_DHCP4_SERVER) {
+         ConstElementPtr next = getItem(xpath + "/next-server");
+         if (next) {
+             result->set("next-server", next);
+         }
+         ConstElementPtr hostname = getItem(xpath + "/server-hostname");
+         if (hostname) {
+             result->set("server-hostname", hostname);
+         }
+         ConstElementPtr boot = getItem(xpath + "/boot-file-name");
+         if (boot) {
+             result->set("boot-file-name", boot);
+         }
+     }
+     ConstElementPtr context = getItem(xpath + "/user-context");
+     if (context) {
+         result->set("user-context", Element::fromJSON(context->stringValue()));
+     }
+     return (result);
+ }
+ void
+ TranslatorHost::setHost(const string& xpath, ConstElementPtr elem) {
+     try {
 -    if (model_ == "kea-dhcp4-server") {
++        if ((model_ == KEA_DHCP4_SERVER) ||
++            (model_ == KEA_DHCP6_SERVER)) {
+             setHostKea(xpath, elem);
+         } else {
+             isc_throw(NotImplemented,
+                       "setHost not implemented for the model: " << model_);
+         }
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error setting host reservation '" << elem->str()
+                   << "' at '" << xpath << "': " << ex.what());
+     }
+ }
+ void
+ TranslatorHost::setHostKea(const string& xpath, ConstElementPtr elem) {
+     ConstElementPtr hostname = elem->get("hostname");
+     // Skip identifier and identifier type as they are keys.
+     if (hostname) {
+         setItem(xpath + "/hostname", hostname, SR_STRING_T);
+     }
 -    if (model_ == "kea-dhcp4-server") {
++    if (model_ == KEA_DHCP4_SERVER) {
+         ConstElementPtr address = elem->get("ip-address");
+         if (address) {
+             setItem(xpath + "/ip-address", address, SR_STRING_T);
+         }
+     } else {
+         ConstElementPtr addresses = elem->get("ip-addresses");
+         if (addresses && (addresses->size() > 0)) {
+             for (ConstElementPtr address : addresses->listValue()) {
+                 setItem(xpath + "/ip-addresses", address, SR_STRING_T);
+             }
+         }
+         ConstElementPtr prefixes = elem->get("prefixes");
+         if (prefixes && (prefixes->size() > 0)) {
+             for (ConstElementPtr prefix : prefixes->listValue()) {
+                 setItem(xpath + "/prefixes", prefix, SR_STRING_T);
+             }
+         }
+     }
+     ConstElementPtr options = elem->get("option-data");
+     if (options && (options->size() > 0)) {
+         setOptionDataList(xpath + "/option-data-list", options);
+     }
+     ConstElementPtr classes = elem->get("client-classes");
+     if (classes && (classes->size() > 0)) {
+         for (ConstElementPtr cclass : classes->listValue()) {
+             setItem(xpath + "/client-classes", cclass, SR_STRING_T);
+         }
+     }
 -        if ((model_ == "kea-dhcp4-server") ||
 -            (model_ == "kea-dhcp6-server")) {
++    if (model_ == KEA_DHCP4_SERVER) {
+         ConstElementPtr next = elem->get("next-server");
+         if (next) {
+             setItem(xpath + "/next-server", next, SR_STRING_T);
+         }
+         ConstElementPtr hostname = elem->get("server-hostname");
+         if (hostname) {
+             setItem(xpath + "/server-hostname", hostname, SR_STRING_T);
+         }
+         ConstElementPtr boot = elem->get("boot-file-name");
+         if (boot) {
+             setItem(xpath + "/boot-file-name", boot, SR_STRING_T);
+         }
+     }
+     ConstElementPtr context = Adaptor::getContext(elem);
+     if (context) {
+         setItem(xpath + "/user-context", Element::create(context->str()),
+                 SR_STRING_T);
+     }
+ }
+ TranslatorHosts::TranslatorHosts(S_Session session, const string& model)
+     : TranslatorBasic(session),
+       TranslatorOptionData(session, model),
+       TranslatorOptionDataList(session, model),
+       TranslatorHost(session, model),
+       model_(model) {
+ }
+ TranslatorHosts::~TranslatorHosts() {
+ }
+ ElementPtr
+ TranslatorHosts::getHosts(const string& xpath) {
+     try {
+         ElementPtr result = Element::createList();
+         S_Iter_Value iter = getIter(xpath + "/*");
+         if (!iter) {
+             // Can't happen.
+             isc_throw(Unexpected, "getHosts can't get iterator: " << xpath);
+         }
+         for (;;) {
+             const string& host = getNext(iter);
+             if (host.empty()) {
+                 break;
+             }
+             result->add(getHost(host));
+         }
+         return (result);
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error getting host reservations at '" << xpath
+                   << "': " << ex.what());
+     }
+ }
+ void
+ TranslatorHosts::setHosts(const string& xpath, ConstElementPtr elem) {
+     try {
 -        if (model_ == "kea-dhcp4-server") {
++        if ((model_ == KEA_DHCP4_SERVER) ||
++            (model_ == KEA_DHCP6_SERVER)) {
+             setHostsKea(xpath, elem);
+         } else {
+             isc_throw(NotImplemented,
+                       "setHosts not implemented for the model: " << model_);
+         }
+     } catch (const sysrepo_exception& ex) {
+         isc_throw(SysrepoError,
+                   "sysrepo error setting host reservations '" << elem->str()
+                   << "' at '" << xpath << "': " << ex.what());
+     }
+ }
+ void
+ TranslatorHosts::setHostsKea(const string& xpath, ConstElementPtr elem) {
+     for (size_t i = 0; i < elem->size(); ++i) {
+         string id_type = "unknown";
+         ConstElementPtr host = elem->get(i);
+         ConstElementPtr id = host->get("hw-address");
+         if (id) {
+             id_type = "hw-address";
+             goto found;
+         }
+         id = host->get("duid");
+         if (id) {
+             id_type = "duid";
+             goto found;
+         }
++        if (model_ == KEA_DHCP4_SERVER) {
+             id = host->get("circuit-id");
+             if (id) {
+                 id_type = "circuit-id";
+                 goto found;
+             }
+             id = host->get("client-id");
+             if (id) {
+                 id_type = "client-id";
+                 goto found;
+             }
+         }
+         id = host->get("flex-id");
+         if (id) {
+             id_type = "flex-id";
+             goto found;
+         }
+     found:
+         if (id_type == "unknown") {
+             isc_throw(BadValue, "getHosts: can't find the identifier type in "
+                       << host->str());
+         }
+         ostringstream key;
+         key << xpath << "/host[identifier-type='" << id_type
+             << "'][identifier='" << id->stringValue() << "']";
+         setHost(key.str(), host);
+     }
+ }
+ }; // end of namespace isc::yang
+ }; // end of namespace isc