Commit e25a9005 authored by Francis Dupont's avatar Francis Dupont

[65-libyang-logger_rebased] Addressed rebase conflicts

parents ccfc51db ab9641bf
......@@ -11,6 +11,7 @@ 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_database.cc translator_database.h
libkea_yang_la_SOURCES += translator_logger.cc translator_logger.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
......@@ -37,6 +38,7 @@ libkea_yang_include_HEADERS = \
translator.h \
translator_control_socket.h \
translator_database.h \
translator_logger.h \
translator_option_data.h \
translator_option_def.h \
translator_pool.h \
......
......@@ -22,6 +22,7 @@ run_unittests_SOURCES += sysrepo_setup.h
run_unittests_SOURCES += translator_unittests.cc
run_unittests_SOURCES += translator_control_socket_unittests.cc
run_unittests_SOURCES += translator_database_unittests.cc
run_unittests_SOURCES += translator_logger_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_logger.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 logger_list[] = "logger list";
/// @brief Test fixture class for @ref TranslatorLoggers.
class TranslatorLoggersTest :
public GenericTranslatorTest<logger_list, TranslatorLoggers> {
public:
/// Constructor.
TranslatorLoggersTest() { }
/// Destructor (does nothing).
virtual ~TranslatorLoggersTest() { }
};
// This test verifies that an empty logger list can be properly
// translated from YANG to JSON.
TEST_F(TranslatorLoggersTest, getEmpty) {
useModel(KEA_DHCP4_SERVER);
// Get empty.
const string& xpath = "/kea-dhcp4-server:logging/loggers";
ConstElementPtr loggers;
EXPECT_NO_THROW(loggers = t_obj_->getLoggers(xpath));
ASSERT_TRUE(loggers);
EXPECT_EQ(0, loggers->size());
}
// This test verifies that one logger can be properly
// translated from YANG to JSON.
TEST_F(TranslatorLoggersTest, get) {
useModel(KEA_DHCP6_SERVER);
// Set a value.
const string& xpath = "/kea-dhcp6-server:logging/loggers";
const string& xlogger = xpath + "/logger[name='foo']";
const string& xseverity = xlogger + "/severity";
const string& xoption = xlogger + "/output-options/option[output='/bar']";
const string& xmaxver = xoption + "/maxver";
S_Val s_severity(new Val("WARN", SR_ENUM_T));
EXPECT_NO_THROW(sess_->set_item(xseverity.c_str(), s_severity));
uint32_t max_ver = 10;
S_Val s_maxver(new Val(max_ver, SR_UINT32_T));
EXPECT_NO_THROW(sess_->set_item(xmaxver.c_str(), s_maxver));
// Get empty.
ConstElementPtr loggers;
EXPECT_NO_THROW(loggers = t_obj_->getLoggers(xpath));
ASSERT_TRUE(loggers);
ASSERT_EQ(1, loggers->size());
ConstElementPtr logger = loggers->get(0);
ASSERT_TRUE(logger);
EXPECT_EQ(3, logger->size());
ConstElementPtr name = logger->get("name");
ASSERT_TRUE(name);
ASSERT_EQ(Element::string, name->getType());
EXPECT_EQ("foo", name->stringValue());
ConstElementPtr severity = logger->get("severity");
ASSERT_TRUE(severity);
ASSERT_EQ(Element::string, severity->getType());
EXPECT_EQ("WARN", severity->stringValue());
ConstElementPtr options = logger->get("output_options");
ASSERT_TRUE(options);
ASSERT_EQ(1, options->size());
ConstElementPtr option = options->get(0);
ASSERT_TRUE(option);
EXPECT_EQ(2, option->size());
ConstElementPtr output = option->get("output");
ASSERT_TRUE(output);
ASSERT_EQ(Element::string, output->getType());
EXPECT_EQ("/bar", output->stringValue());
ConstElementPtr maxver = option->get("maxver");
ASSERT_TRUE(maxver);
ASSERT_EQ(Element::integer, maxver->getType());
EXPECT_EQ(max_ver, maxver->intValue());
}
// This test verifies that one logger can be properly
// translated from JSON to YANG.
TEST_F(TranslatorLoggersTest, set) {
useModel(KEA_DHCP4_SERVER);
// Set a value.
const string& xpath = "/kea-dhcp4-server:logging/loggers";
ElementPtr option = Element::createMap();
option->set("output", Element::create(string("/bar")));
option->set("maxver", Element::create(10));
ElementPtr options = Element::createList();
options->add(option);
ElementPtr logger = Element::createMap();
logger->set("name", Element::create(string("foo")));
logger->set("severity", Element::create(string("WARN")));
logger->set("output_options", options);
ElementPtr loggers = Element::createList();
loggers->add(logger);
ASSERT_NO_THROW(t_obj_->setLoggers(xpath, loggers));
// Get it back.
ConstElementPtr gots;
EXPECT_NO_THROW(gots = t_obj_->getLoggers(xpath));
ASSERT_TRUE(gots);
ASSERT_EQ(1, gots->size());
ConstElementPtr got = gots->get(0);
ASSERT_TRUE(got);
EXPECT_EQ(3, got->size());
ConstElementPtr name = got->get("name");
ASSERT_TRUE(name);
ASSERT_EQ(Element::string, name->getType());
EXPECT_EQ("foo", name->stringValue());
ConstElementPtr severity = logger->get("severity");
ASSERT_TRUE(severity);
ASSERT_EQ(Element::string, severity->getType());
EXPECT_EQ("WARN", severity->stringValue());
ConstElementPtr got_os = logger->get("output_options");
ASSERT_TRUE(got_os);
ASSERT_EQ(1, got_os->size());
ConstElementPtr got_o = got_os->get(0);
ASSERT_TRUE(got_o);
EXPECT_EQ(2, got_o->size());
ConstElementPtr output = got_o->get("output");
ASSERT_TRUE(output);
ASSERT_EQ(Element::string, output->getType());
EXPECT_EQ("/bar", output->stringValue());
ConstElementPtr maxver = got_o->get("maxver");
ASSERT_TRUE(maxver);
ASSERT_EQ(Element::integer, maxver->getType());
EXPECT_EQ(10, maxver->intValue());
// Check the tree representation.
S_Tree tree;
EXPECT_NO_THROW(tree = sess_->get_subtree("/kea-dhcp4-server:logging"));
ASSERT_TRUE(tree);
string expected =
"kea-dhcp4-server:logging (container)\n"
" |\n"
" -- loggers (container)\n"
" |\n"
" -- logger (list instance)\n"
" |\n"
" -- name = foo\n"
" |\n"
" -- output-options (container)\n"
" | |\n"
" | -- option (list instance)\n"
" | |\n"
" | -- output = /bar\n"
" | |\n"
" | -- maxver = 10\n"
" |\n"
" -- severity = WARN\n";
EXPECT_EQ(expected, tree->to_string(100));
// Check it validates.
EXPECT_NO_THROW(sess_->validate());
}
}; // 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_logger.h>
#include <yang/adaptor.h>
#include <yang/yang_models.h>
#include <sstream>
using namespace std;
using namespace isc::data;
namespace isc {
namespace yang {
TranslatorLogger::TranslatorLogger(S_Session session, const string& model)
: TranslatorBasic(session), model_(model) {
}
TranslatorLogger::~TranslatorLogger() {
}
ElementPtr
TranslatorLogger::getLogger(const string& xpath) {
try {
if ((model_ == KEA_DHCP4_SERVER) ||
(model_ == KEA_DHCP6_SERVER) ||
(model_ == KEA_DHCP_DDNS) ||
(model_ == KEA_CTRL_AGENT)) {
return (getLoggerKea(xpath));
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error getting logger at '" << xpath
<< "': " << ex.what());
}
isc_throw(NotImplemented,
"getLogger not implemented for the model: " << model_);
}
ElementPtr
TranslatorLogger::getLoggerKea(const string& xpath) {
ConstElementPtr name = getItem(xpath + "/name");
if (!name) {
// Can't happen as name is the key.
isc_throw(Unexpected, "getLoggerKea requires name: " << xpath);
}
ElementPtr result = Element::createMap();
result->set("name", name);
ConstElementPtr options = getOutputOptions(xpath + "/output-options");
if (options && (options->size() > 0)) {
result->set("output_options", options);
}
ConstElementPtr severity = getItem(xpath + "/severity");
if (severity) {
result->set("severity", severity);
}
ConstElementPtr debuglevel = getItem(xpath + "/debuglevel");
if (debuglevel) {
result->set("debuglevel", debuglevel);
}
ConstElementPtr context = getItem(xpath + "/user-context");
if (context) {
result->set("user-context", Element::fromJSON(context->stringValue()));
}
return (result);
}
ElementPtr
TranslatorLogger::getOutputOption(const string& xpath) {
ConstElementPtr output = getItem(xpath + "/output");
if (!output) {
// Can't happen as output is the key.
isc_throw(Unexpected, "getOutputOption requires (!output): " << xpath);
}
ElementPtr result = Element::createMap();
result->set("output", output);
ConstElementPtr maxver = getItem(xpath + "/maxver");
if (maxver) {
result->set("maxver", maxver);
}
ConstElementPtr maxsize = getItem(xpath + "/maxsize");
if (maxsize) {
result->set("maxsize", maxsize);
}
ConstElementPtr flush = getItem(xpath + "/flush");
if (flush) {
result->set("flush", flush);
}
return (result);
}
ElementPtr
TranslatorLogger::getOutputOptions(const string& xpath) {
S_Iter_Value iter = getIter(xpath + "/*");
if (!iter) {
// Can't happen.
isc_throw(Unexpected, "getOutputOptions: can't get iterator: "
<< xpath);
}
ElementPtr result = Element::createList();
for (;;) {
const string& option = getNext(iter);
if (option.empty()) {
break;
}
result->add(getOutputOption(option));
}
return (result);
}
void
TranslatorLogger::setLogger(const string& xpath, ConstElementPtr elem) {
try {
if ((model_ == KEA_DHCP4_SERVER) ||
(model_ == KEA_DHCP6_SERVER) ||
(model_ == KEA_DHCP_DDNS) ||
(model_ == KEA_CTRL_AGENT)) {
setLoggerKea(xpath, elem);
} else {
isc_throw(NotImplemented,
"setLogger not implemented for the model: " << model_);
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error setting logger '" << elem->str()
<< "' at '" << xpath << "': " << ex.what());
}
}
void
TranslatorLogger::setLoggerKea(const string& xpath, ConstElementPtr elem) {
// Skip name as it is the key.
ConstElementPtr options = elem->get("output_options");
if (options && (options->size() > 0)) {
setOutputOptions(xpath + "/output-options", options);
}
ConstElementPtr debuglevel = elem->get("debuglevel");
if (debuglevel) {
setItem(xpath + "/debuglevel", debuglevel, SR_UINT8_T);
}
ConstElementPtr severity = elem->get("severity");
if (severity) {
setItem(xpath + "/severity", severity, SR_ENUM_T);
}
ConstElementPtr context = Adaptor::getContext(elem);
if (context) {
setItem(xpath + "/user-context", Element::create(context->str()),
SR_STRING_T);
}
}
void
TranslatorLogger::setOutputOption(const string& xpath, ConstElementPtr elem) {
bool created = false;
// Skip output as it is the key.
ConstElementPtr maxver = elem->get("maxver");
if (maxver) {
setItem(xpath + "/maxver", maxver, SR_UINT32_T);
created = true;
}
ConstElementPtr maxsize = elem->get("maxsize");
if (maxsize) {
setItem(xpath + "/maxsize", maxsize, SR_UINT32_T);
created = true;
}
ConstElementPtr flush = elem->get("flush");
if (flush) {
setItem(xpath + "/flush", flush, SR_BOOL_T);
created = true;
}
// There is no mandatory fields outside the key so force creation.
if (!created) {
ConstElementPtr list = Element::createList();
setItem(xpath, list, SR_LIST_T);
}
}
void
TranslatorLogger::setOutputOptions(const string& xpath, ConstElementPtr elem) {
for (size_t i = 0; i < elem->size(); ++i) {
ConstElementPtr option = elem->get(i);
if (!option->contains("output")) {
isc_throw(BadValue, "output-options without output: "
<< option->str());
}
string output = option->get("output")->stringValue();
ostringstream key;
key << xpath << "/option[output='" << output << "']";
setOutputOption(key.str(), option);
}
}
TranslatorLoggers::TranslatorLoggers(S_Session session, const string& model)
: TranslatorBasic(session),
TranslatorLogger(session, model),
model_(model) {
}
TranslatorLoggers::~TranslatorLoggers() {
}
ConstElementPtr
TranslatorLoggers::getLoggers(const string& xpath) {
try {
if ((model_ == KEA_DHCP4_SERVER) ||
(model_ == KEA_DHCP6_SERVER) ||
(model_ == KEA_DHCP_DDNS) ||
(model_ == KEA_CTRL_AGENT)) {
return (getLoggersKea(xpath));
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error getting loggeres at '" << xpath
<< "': " << ex.what());
}
isc_throw(NotImplemented,
"getLoggers not implemented for the model: " << model_);
}
ElementPtr
TranslatorLoggers::getLoggersKea(const string& xpath) {
S_Iter_Value iter = getIter(xpath + "/*");
if (!iter) {
// Can't happen.
isc_throw(Unexpected, "getLoggersKea: can't get iterator: " << xpath);
}
ElementPtr result = Element::createList();
for (;;) {
const string& logger = getNext(iter);
if (logger.empty()) {
break;
}
result->add(getLogger(logger));
}
return (result);
}
void
TranslatorLoggers::setLoggers(const string& xpath, ConstElementPtr elem) {
try {
if ((model_ == KEA_DHCP4_SERVER) ||
(model_ == KEA_DHCP6_SERVER) ||
(model_ == KEA_DHCP_DDNS) ||
(model_ == KEA_CTRL_AGENT)) {
setLoggersKea(xpath, elem);
} else {
isc_throw(NotImplemented,
"setLoggers not implemented for the model: " << model_);
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error setting loggeres '" << elem->str()
<< "' at '" << xpath << "': " << ex.what());
}
}
void
TranslatorLoggers::setLoggersKea(const string& xpath, ConstElementPtr elem) {
for (size_t i = 0; i < elem->size(); ++i) {
ConstElementPtr logger = elem->get(i);
if (!logger->contains("name")) {
isc_throw(BadValue, "logger without name: " << logger->str());
}
string name = logger->get("name")->stringValue();
ostringstream key;
key << xpath << "/logger[name='" << name << "']";
setLogger(key.str(), logger);
}
}
}; // 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_LOGGER_H
#define ISC_TRANSLATOR_LOGGER_H 1
#include <yang/translator.h>
#include <list>
namespace isc {
namespace yang {
/// Logger translation between YANG and JSON
///
/// JSON syntax for all Kea servers with loggers is:
/// @code
/// {
/// "name": <name>,
/// "output_options": [ <output options> ],
/// "severity": <severity>,
/// "debuglevel": <debug level>,
/// "user-context": { <json map> },
/// "comment": <comment>
/// }
/// @endcode
///
/// JSON syntax for all Kea server for output options is:
/// @code
/// {
/// "output": <output, e.g. log file name>,
/// "maxver": <maximum file version>,
/// "maxsize": <maxium file size>,
/// "flush": <flush flag>
/// }
/// @endcode
///
/// YANG syntax for kea-logging is with name as the logger list key and
/// output as the output option list key.
/// @code
/// +--rw logger container
/// |
/// +--rw name? string
/// +--rw output-options container
/// | +--rw option* [output]
/// | +--rw output string
/// | +--rw maxver? uint32
/// | +--rw maxsize? uint32
/// | +--rw flush? boolean
/// +--rw debuglevel? uint8
/// +--rw severity? enumeration
/// +--rw user-context? string
/// @endcode
///
/// An example in JSON and YANG formats:
/// @code
/// [
/// {
/// "name": "foo",
/// "severity": "WARN",
/// "output_options":
/// [
/// {
/// "output": "/bar",
/// "maxver": 10
/// }
/// ]
/// }
/// ]
/// @endcode
/// @code
/// /kea-dhcp4-server:logging (container)
/// /kea-dhcp4-server:logging/loggers (container)
/// /kea-dhcp4-server:logging/loggers/logger[name='foo'] (list instance)
/// /kea-dhcp4-server:logging/loggers/logger[name='foo']/name = foo
/// /kea-dhcp4-server:logging/loggers/logger[name='foo']/
/// output-options (container)
/// /kea-dhcp4-server:logging/loggers/logger[name='foo']/output-options/
/// option[output='/bar'] (list instance)
/// /kea-dhcp4-server:logging/loggers/logger[name='foo']/output-options/
/// option[output='/bar']/option = /bar
/// /kea-dhcp4-server:logging/loggers/logger[name='foo']/output-options/
/// option[output='/bar']/maxver = 10
/// /kea-dhcp4-server:logging/loggers/logger[name='foo']/severity = WARN
/// @endcode
/// @brief A translator class for converting a logger between
/// YANG and JSON.
///
/// Currently supports all kea servers and agents. Speficic to Kea.
class TranslatorLogger : virtual public TranslatorBasic {
public:
/// @brief Constructor.
///
/// @param session Sysrepo session.
/// @param model Model name.
TranslatorLogger(S_Session session, const std::string& model);
/// @brief Destructor.
virtual ~TranslatorLogger();
/// @brief Get and translate a logger from YANG to JSON.
///
/// @param xpath The xpath of the logger.
/// @return JSON representation of the logger.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ElementPtr getLogger(const std::string& xpath);
/// @brief Translate and set logger from JSON to YANG.
///
/// @param xpath The xpath of the logger.
/// @param elem The JSON element.
void setLogger(const std::string& xpath, isc::data::ConstElementPtr elem);
protected:
/// @brief Get and translate an output option from YANG to JSON.
///
/// @param xpath The xpath of the output option.
/// @return JSON representation of the output option.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ElementPtr getOutputOption(const std::string& xpath);
/// @brief Get and translate output options from YANG to JSON.
///
/// @param xpath The xpath of output options.
/// @return JSON representation of output options.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ElementPtr getOutputOptions(const std::string& xpath);
/// @brief Translate and set an output option from JSON to YANG.
///
/// @param xpath The xpath of the output option.
/// @param elem The JSON element.
void setOutputOption(const std::string& xpath,
isc::data::ConstElementPtr elem);
/// @brief Translate and set output options from JSON to YANG.
///
/// @param xpath The xpath of the output options.
/// @param elem The JSON element.
/// @throw BadValue on an output option without output.
void setOutputOptions(const std::string& xpath,
isc::data::ConstElementPtr elem);
/// @brief getLogger JSON for kea-logging.
///
/// @param xpath The xpath of the logger.
/// @return JSON representation of the logger.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ElementPtr getLoggerKea(const std::string& xpath);
/// @brief setLogger for kea-logging.
///
/// @param xpath The xpath of the logger.