Commit 7b07d014 authored by Francis Dupont's avatar Francis Dupont

[65-libyang-control-socket_rebase] Rebasing before merge

parents 8fb5a295 352ae06e
......@@ -8,6 +8,8 @@ lib_LTLIBRARIES = libkea-yang.la
libkea_yang_la_SOURCES = adaptor.cc adaptor.h
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_SOURCES += translator_option_data.cc
libkea_yang_la_SOURCES += translator_option_data.h
libkea_yang_la_SOURCES += translator_option_def.cc
......@@ -31,6 +33,7 @@ libkea_yang_include_HEADERS = \
adaptor.h \
sysrepo_error.h \
translator.h \
translator_control_socket.h \
translator_option_data.h \
translator_option_def.h \
translator_pool.h \
......
......@@ -20,6 +20,7 @@ TESTS += run_unittests
run_unittests_SOURCES = adaptor_unittests.cc
run_unittests_SOURCES += sysrepo_setup.h
run_unittests_SOURCES += translator_unittests.cc
run_unittests_SOURCES += translator_control_socket_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
......
// 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 <yang/yang_models.h>
#include <yang/tests/sysrepo_setup.h>
#include <gtest/gtest.h>
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 control_socket[] = "control socket";
/// @brief Test fixture class for @ref TranslatorControlSocket.
class TranslatorControlSocketTest :
public GenericTranslatorTest<control_socket, TranslatorControlSocket> {
public:
/// Constructor.
TranslatorControlSocketTest() { }
/// Destructor (does nothing).
virtual ~TranslatorControlSocketTest() { }
};
// This test verifies that an empty control socket can be properly
// translated from YANG to JSON.
TEST_F(TranslatorControlSocketTest, getEmpty) {
useModel(KEA_DHCP4_SERVER);
// Get empty.
const string& xpath = "/kea-dhcp4-server:config/control-socket";
ConstElementPtr sock;
EXPECT_NO_THROW(sock = t_obj_->getControlSocket(xpath));
EXPECT_FALSE(sock);
}
// This test verifies that a not empty control socket can be properly
// translated from YANG to JSON.
TEST_F(TranslatorControlSocketTest, get) {
useModel(KEA_DHCP6_SERVER);
// Set a value.
const string& xpath = "/kea-dhcp6-server: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 = t_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());
}
// This test verifies that a not empty control socket can be properly
// translated from JSON to YANG.
TEST_F(TranslatorControlSocketTest, set) {
useModel(KEA_CTRL_AGENT);
// Set a value.
const string& xpath =
"/kea-ctrl-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 {
t_obj_->setControlSocket(xpath, sock);
} catch (const std::exception& ex) {
cerr << "setControlSocket fail with " << ex.what() << endl;
}
ASSERT_NO_THROW(t_obj_->setControlSocket(xpath, sock));
// Get it back.
ConstElementPtr got;
EXPECT_NO_THROW(got = t_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());
// Check it validates.
EXPECT_NO_THROW(sess_->validate());
}
// This test verifies that an empty control socket can be properly
// translated from JSON to YANG.
TEST_F(TranslatorControlSocketTest, setEmpty) {
useModel(KEA_DHCP4_SERVER);
// Set a value.
const string& xpath = "/kea-dhcp4-server: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(t_obj_->setControlSocket(xpath, ConstElementPtr()));
// Get it back.
ConstElementPtr sock;
EXPECT_NO_THROW(sock = t_obj_->getControlSocket(xpath));
EXPECT_FALSE(sock);
}
}; // end of anonymous namespace
// 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 <yang/yang_models.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_SERVER) ||
(model_ == KEA_DHCP6_SERVER) ||
(model_ == KEA_DHCP_DDNS) ||
(model_ == KEA_CTRL_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_SERVER) ||
(model_ == KEA_DHCP6_SERVER) ||
(model_ == KEA_DHCP_DDNS) ||
(model_ == KEA_CTRL_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
// 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 {
/// Control socket translation between YANG and 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
///
/// YANG syntax is:
/// @code
/// +--rw control-socket container
/// |
/// +--rw socket-name string
/// +--rw socket-type enumeration
/// +--rw user-context? string
/// @endcode
///
/// An example in JSON and YANG formats:
/// @code
/// {
/// "socket-name": "/tmp/kea.sock",
/// "socket-type": "unix",
/// "user-context": { "foo": 1 }
/// }
/// @endcode
/// @code
/// /kea-ctrl-agent:config (container)
/// /kea-ctrl-agent:config/control-sockets (container)
/// /kea-ctrl-agent:config/control-sockets/
/// socket[server-type='dhcp4'] (list instance)
/// /kea-ctrl-agent:config/control-sockets/socket[server-type='dhcp4']/
/// server-type = dhcp4
/// /kea-ctrl-agent:config/control-sockets/socket[server-type='dhcp4']/
/// control-socket (container)
/// /kea-ctrl-agent:config/control-sockets/socket[server-type='dhcp4']/
/// control-socket/socket-name = /tmp/kea.sock
/// /kea-ctrl-agent:config/control-sockets/socket[server-type='dhcp4']/
/// control-socket/socket-type = unix
/// /kea-ctrl-agent:config/control-sockets/socket[server-type='dhcp4']/
/// control-socket/user-context = { \"foo\": 1 }
/// @endcode
/// @brief A translator class for converting a control socket between
/// YANG and JSON.
///
/// Supports the following models:
/// - kea-dhcp4-server
/// - kea-dhcp6-server
/// - kea-dhcp-ddns (not yet supported by the server itself)
/// - kea-ctrl-agent
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.
///
/// @param xpath The xpath of the control socket.
/// @return JSON representation of the control socket or null.
/// @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.
///
/// Null elem argument removes the container.
/// Required parameters passed in elem are: socket-name, socket-type.
/// Optional parameters are: user-context.
///
/// @param xpath The xpath of the control socket.
/// @param elem The JSON element.
/// @throw BadValue on control socket without socket type or name.
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment