]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[65-libyang-control-socket] Filled files, waiting for adaptor merge
authorFrancis Dupont <fdupont@isc.org>
Thu, 13 Sep 2018 13:42:05 +0000 (15:42 +0200)
committerFrancis Dupont <fdupont@isc.org>
Fri, 14 Sep 2018 14:16:56 +0000 (16:16 +0200)
src/lib/yang/Makefile.am
src/lib/yang/tests/Makefile.am
src/lib/yang/tests/translator_control_socket_unittests.cc [new file with mode: 0644]
src/lib/yang/translator_control_socket.cc [new file with mode: 0644]
src/lib/yang/translator_control_socket.h [new file with mode: 0644]

index 01b3a633afbfb8df9ff014a2abcdd6323c8c2823..b8012d5ce41af0d897d9e15d290b9e88718c8de7 100644 (file)
@@ -7,6 +7,8 @@ AM_CXXFLAGS = $(KEA_CXXFLAGS)
 lib_LTLIBRARIES = libkea-yang.la
 libkea_yang_la_SOURCES = sysrepo_error.h
 libkea_yang_la_SOURCES += translator.cc translator.h
+libkea_yang_la_SOURCES += translator_control_socket.cc
+libkea_yang_la_SOURCES += translator_control_socket.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
index f54de8916496de5858c5fadc2a26c0872e7490d0..b9585f0512f8d01f231f375b0220c3f25df3941e 100644 (file)
@@ -18,6 +18,7 @@ TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES  = translator_unittests.cc
+run_unittests_SOURCES += translator_control_socket_unittests.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/yang/tests/translator_control_socket_unittests.cc b/src/lib/yang/tests/translator_control_socket_unittests.cc
new file mode 100644 (file)
index 0000000..12f4a56
--- /dev/null
@@ -0,0 +1,157 @@
+// 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_control_socket.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::data;
+using namespace isc::yang;
+
+namespace {
+
+// Test get empty control socket using the Kea ad hoc model.
+TEST(TranslatorControlSocketTest, getEmpty) {
+    // Get a translator control socket object to play with.
+    S_Connection conn(new Connection("translator control socket unittests"));
+    S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+    boost::scoped_ptr<TranslatorControlSocket> tcs_obj;
+
+    // Use the ad hoc model.
+    const string& model = "kea-dhcp4";
+    EXPECT_NO_THROW(tcs_obj.reset(new TranslatorControlSocket(sess, model)));
+
+    // Get empty.
+    const string& xpath = "/kea-dhcp4:config/control-socket";
+    ConstElementPtr sock;
+    EXPECT_NO_THROW(sock = tcs_obj->getControlSocket(xpath));
+    EXPECT_FALSE(sock);
+}
+    
+// Test get not empty control socket using the Kea ad hoc model.
+TEST(TranslatorControlSocketTest, get) {
+    // Get a translator control socket object to play with.
+    S_Connection conn(new Connection("translator control socket unittests"));
+    S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+    boost::scoped_ptr<TranslatorControlSocket> tcs_obj;
+
+    // Use the ad hoc model.
+    const string& model = "kea-dhcp6";
+    EXPECT_NO_THROW(tcs_obj.reset(new TranslatorControlSocket(sess, model)));
+
+    // Set a value.
+    const string& xpath = "/kea-dhcp6:config/control-socket";
+    const string& xname = xpath + "/socket-name";
+    const string& xtype = xpath + "/socket-type";
+    const string& xcontext = xpath + "/user-context";
+    S_Val s_name(new Val("/tmp/kea.sock"));
+    EXPECT_NO_THROW(sess->set_item(xname.c_str(), s_name));
+    S_Val s_type(new Val("unix", SR_ENUM_T));
+    EXPECT_NO_THROW(sess->set_item(xtype.c_str(), s_type));
+    S_Val s_context(new Val("{ \"foo\": 1 }"));
+    EXPECT_NO_THROW(sess->set_item(xcontext.c_str(), s_context));
+
+    // Get it.
+    ConstElementPtr sock;
+    EXPECT_NO_THROW(sock = tcs_obj->getControlSocket(xpath));
+    ASSERT_TRUE(sock);
+    ASSERT_EQ(Element::map, sock->getType());
+    EXPECT_EQ(3, sock->size());
+    ConstElementPtr type = sock->get("socket-type");
+    ASSERT_TRUE(type);
+    ASSERT_EQ(Element::string, type->getType());
+    EXPECT_EQ("unix", type->stringValue());
+    ConstElementPtr name = sock->get("socket-name");
+    ASSERT_TRUE(name);
+    ASSERT_EQ(Element::string, name->getType());
+    EXPECT_EQ("/tmp/kea.sock", name->stringValue());
+    ConstElementPtr context = sock->get("user-context");
+    ASSERT_TRUE(context);
+    EXPECT_EQ("{ \"foo\": 1 }", context->str());
+}
+
+// Test set not empty control socket using the Kea ad hoc model.
+TEST(TranslatorControlSocketTest, set) {
+    // Get a translator control socket object to play with.
+    S_Connection conn(new Connection("translator control socket unittests"));
+    S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+    boost::scoped_ptr<TranslatorControlSocket> tcs_obj;
+
+    // Use the ad hoc model.
+    const string& model = "kea-control-agent";
+    EXPECT_NO_THROW(tcs_obj.reset(new TranslatorControlSocket(sess, model)));
+
+    // Set a value.
+    const string& xpath =
+        "/kea-control-agent:config/control-sockets/socket[server-type='dhcp4']/control-socket";
+    ElementPtr sock = Element::createMap();
+    sock->set("socket-name", Element::create(string("/tmp/kea.sock")));
+    sock->set("socket-type", Element::create(string("unix")));
+    sock->set("comment", Element::create(string("a comment")));
+    try {
+        tcs_obj->setControlSocket(xpath, sock);
+    } catch (const std::exception& ex) {
+        cerr << "setControlSocket fail with " << ex.what() << endl;
+    }
+    ASSERT_NO_THROW(tcs_obj->setControlSocket(xpath, sock));
+
+    // Get it back.
+    ConstElementPtr got;
+    EXPECT_NO_THROW(got = tcs_obj->getControlSocket(xpath));
+    ASSERT_TRUE(got);
+    ASSERT_EQ(Element::map, got->getType());
+    EXPECT_EQ(3, got->size());
+    ConstElementPtr name = got->get("socket-name");
+    ASSERT_TRUE(name);
+    ASSERT_EQ(Element::string, name->getType());
+    EXPECT_EQ("/tmp/kea.sock", name->stringValue());
+    ConstElementPtr type = got->get("socket-type");
+    ASSERT_TRUE(type);
+    ASSERT_EQ(Element::string, type->getType());
+    EXPECT_EQ("unix", type->stringValue());
+    ConstElementPtr context = got->get("user-context");
+    ASSERT_TRUE(context);
+    EXPECT_EQ("{ \"comment\": \"a comment\" }", context->str());
+}
+
+// Test set empty control socket using the Kea ad hoc model.
+TEST(TranslatorControlSocketTest, setEmpty) {
+    // Get a translator control socket object to play with.
+    S_Connection conn(new Connection("translator control socket unittests"));
+    S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+    boost::scoped_ptr<TranslatorControlSocket> tcs_obj;
+
+    // Use the ad hoc model.
+    const string& model = "kea-dhcp4";
+    EXPECT_NO_THROW(tcs_obj.reset(new TranslatorControlSocket(sess, model)));
+
+    // Set a value.
+    const string& xpath = "/kea-dhcp4:config/control-socket";
+    const string& xname = xpath + "/socket-name";
+    const string& xtype = xpath + "/socket-type";
+    const string& xcontext = xpath + "/user-context";
+    S_Val s_name(new Val("/tmp/kea.sock"));
+    EXPECT_NO_THROW(sess->set_item(xname.c_str(), s_name));
+    S_Val s_type(new Val("unix", SR_ENUM_T));
+    EXPECT_NO_THROW(sess->set_item(xtype.c_str(), s_type));
+    S_Val s_context(new Val("{ \"foo\": 1 }"));
+    EXPECT_NO_THROW(sess->set_item(xcontext.c_str(), s_context));
+
+    // Reset to empty.
+    ASSERT_NO_THROW(tcs_obj->setControlSocket(xpath, ConstElementPtr()));
+
+    // Get it back.
+    ConstElementPtr sock;
+    EXPECT_NO_THROW(sock = tcs_obj->getControlSocket(xpath));
+    EXPECT_FALSE(sock);
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/yang/translator_control_socket.cc b/src/lib/yang/translator_control_socket.cc
new file mode 100644 (file)
index 0000000..6f7f416
--- /dev/null
@@ -0,0 +1,106 @@
+// 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_control_socket.h>
+#include <yang/adaptor.h>
+#include <sstream>
+
+using namespace std;
+using namespace isc::data;
+
+namespace isc {
+namespace yang {
+
+TranslatorControlSocket::TranslatorControlSocket(S_Session session,
+                                                 const string& model)
+    : TranslatorBasic(session), model_(model) {
+}
+
+TranslatorControlSocket::~TranslatorControlSocket() {
+}
+
+ConstElementPtr
+TranslatorControlSocket::getControlSocket(const string& xpath) {
+    try {
+        if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6") ||
+            (model_ == "kea-dhcpddns") || (model_ == "kea-control-agent")) {
+            return (getControlSocketKea(xpath));
+        }
+    } catch (const sysrepo_exception& ex) {
+        isc_throw(SysrepoError,
+                  "sysrepo error getting control socket at '" << xpath
+                  << "': " << ex.what());
+    }
+    isc_throw(NotImplemented,
+              "getControlSocket not implemented for the model: " << model_);
+}
+
+ElementPtr
+TranslatorControlSocket::getControlSocketKea(const string& xpath) {
+    ConstElementPtr name = getItem(xpath + "/socket-name");
+    ConstElementPtr type = getItem(xpath + "/socket-type");
+    if (name && type) {
+        ElementPtr result = Element::createMap();
+        result->set("socket-name", name);
+        result->set("socket-type", type);
+        ConstElementPtr context = getItem(xpath + "/user-context");
+        if (context) {
+            result->set("user-context",
+                        Element::fromJSON(context->stringValue()));
+        }
+        return (result);
+    }
+    return (ElementPtr());
+}
+
+void
+TranslatorControlSocket::setControlSocket(const string& xpath,
+                                          ConstElementPtr elem) {
+    try {
+        if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6") ||
+            (model_ == "kea-dhcpddns") || (model_ == "kea-control-agent")) {
+            setControlSocketKea(xpath, elem);
+        } else {
+          isc_throw(NotImplemented,
+                    "setControlSocket not implemented for the model: "
+                    << model_);
+        }
+    } catch (const sysrepo_exception& ex) {
+        isc_throw(SysrepoError,
+                  "sysrepo error setting control socket '" << elem->str()
+                  << "' at '" << xpath << "': " << ex.what());
+    }
+}
+
+void
+TranslatorControlSocket::setControlSocketKea(const string& xpath,
+                                             ConstElementPtr elem) {
+    if (!elem) {
+        delItem(xpath + "/socket-name");
+        delItem(xpath + "/socket-type");
+        delItem(xpath + "/user-context");
+        delItem(xpath);
+        return;
+    }
+    ConstElementPtr name = elem->get("socket-name");
+    if (!name) {
+        isc_throw(BadValue, "setControlSocket missing socket name");
+    }
+    ConstElementPtr type = elem->get("socket-type");
+    if (!type) {
+        isc_throw(BadValue, "setControlSocket missing socket type");
+    }
+    setItem(xpath + "/socket-name", name, SR_STRING_T);
+    setItem(xpath + "/socket-type", type, SR_ENUM_T);
+    ConstElementPtr context = Adaptor::getContext(elem);
+    if (context) {
+        setItem(xpath + "/user-context", Element::create(context->str()),
+                SR_STRING_T);
+    }
+}
+
+}; // end of namespace isc::yang
+}; // end of namespace isc
diff --git a/src/lib/yang/translator_control_socket.h b/src/lib/yang/translator_control_socket.h
new file mode 100644 (file)
index 0000000..9755845
--- /dev/null
@@ -0,0 +1,84 @@
+// 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/.
+
+#ifndef ISC_TRANSLATOR_CONTROL_SOCKET_H
+#define ISC_TRANSLATOR_CONTROL_SOCKET_H 1
+
+#include <yang/translator.h>
+#include <list>
+
+namespace isc {
+namespace yang {
+
+// @brief Between Yang and JSON translator class for the control socket.
+class TranslatorControlSocket : virtual public TranslatorBasic {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param session Sysrepo session.
+    /// @param model Model name.
+    TranslatorControlSocket(S_Session session, const std::string& model);
+
+    /// @brief Destructor.
+    virtual ~TranslatorControlSocket();
+
+    /// @brief Get and translate a control socket from Yang to JSON.
+    ///
+    /// JSON syntax for all Kea servers with command channel is:
+    /// @code
+    /// "control-socket": {
+    ///     "socket-type": "<socket type>",
+    ///     "socket-name": "<socket name>",
+    ///     "user-context": { <json map> },
+    ///     "comment": "<comment>"
+    /// }
+    /// @endcode
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @return JSON representation of the control socket.
+    /// @throw SysrepoError when sysrepo raises an error.
+    isc::data::ConstElementPtr getControlSocket(const std::string& xpath);
+
+    /// @brief Translate and set control socket from JSON to Yang.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    void setControlSocket(const std::string& xpath,
+                          isc::data::ConstElementPtr elem);
+
+protected:
+    /// @brief getControlSocket JSON for kea models.
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @return JSON representation of the control socket.
+    /// @throw SysrepoError when sysrepo raises an error.
+    isc::data::ElementPtr getControlSocketKea(const std::string& xpath);
+
+    /// @brief setControlSocket for kea models.
+    ///
+    /// Yang syntax is:
+    /// @code
+    ///  +--rw control-socket   container
+    ///    |
+    ///    +--rw socket-name    string
+    ///    +--rw socket-type    enumeration
+    ///    +--rw user-context?  string
+    /// @endcode
+    ///
+    /// @param xpath The xpath of the control socket.
+    /// @param elem The JSON element.
+    void setControlSocketKea(const std::string& xpath,
+                             isc::data::ConstElementPtr elem);
+
+    /// @brief The model.
+    std::string model_;
+};
+
+}; // end of namespace isc::yang
+}; // end of namespace isc
+
+#endif // ISC_TRANSLATOR_CONTROL_SOCKET_H