From: Francis Dupont Date: Thu, 13 Sep 2018 13:42:05 +0000 (+0200) Subject: [65-libyang-control-socket] Filled files, waiting for adaptor merge X-Git-Tag: 165-netbsd-8-fixes_base^2~3^2^2~1^2~6^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=321cd12606b728005231bf1d832b5d7eaf4f6197;p=thirdparty%2Fkea.git [65-libyang-control-socket] Filled files, waiting for adaptor merge --- diff --git a/src/lib/yang/Makefile.am b/src/lib/yang/Makefile.am index 01b3a633af..b8012d5ce4 100644 --- a/src/lib/yang/Makefile.am +++ b/src/lib/yang/Makefile.am @@ -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 diff --git a/src/lib/yang/tests/Makefile.am b/src/lib/yang/tests/Makefile.am index f54de89164..b9585f0512 100644 --- a/src/lib/yang/tests/Makefile.am +++ b/src/lib/yang/tests/Makefile.am @@ -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 index 0000000000..12f4a56356 --- /dev/null +++ b/src/lib/yang/tests/translator_control_socket_unittests.cc @@ -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 + +#include + +#include +#include + +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 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 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 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 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 index 0000000000..6f7f416a46 --- /dev/null +++ b/src/lib/yang/translator_control_socket.cc @@ -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 +#include +#include + +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 index 0000000000..9755845018 --- /dev/null +++ b/src/lib/yang/translator_control_socket.h @@ -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 +#include + +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-name": "", + /// "user-context": { }, + /// "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