2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 21:45:37 +00:00

[65-libyang-generic] Imported generic stuff

This commit is contained in:
Francis Dupont
2018-08-31 15:57:13 +02:00
parent a9e9e42dcd
commit d21e9059ea
12 changed files with 1394 additions and 0 deletions

33
src/lib/yang/Makefile.am Normal file
View File

@@ -0,0 +1,33 @@
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES) $(SYSREPO_CPPFLAGS)
AM_CXXFLAGS = $(KEA_CXXFLAGS)
lib_LTLIBRARIES = libkea-yang.la
libkea_yang_la_SOURCES = sysrepo_error.h
libkea_yang_la_SOURCES += sysrepo_connection.cc sysrepo_connection.h
libkea_yang_la_SOURCES += translator.cc translator.h
libkea_yang_la_SOURCES += watcher.cc watcher.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
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
libkea_yang_la_LIBADD += $(LOG4CPLUS_LIBS) $(BOOST_LIBS) $(SYSREPO_LIBS)
libkea_yang_la_LDFLAGS = -no-undefined -version-info 0:0:0
# Specify the headers for copying into the installation directory tree.
libkea_yang_includedir = $(pkgincludedir)/yang
libkea_yang_include_HEADERS = \
sysrepo_connection.h \
sysrepo_error.h \
translator.h \
watcher.h
EXTRA_DIST = yang.dox
CLEANFILES = *.gcno *.gcda

View File

@@ -0,0 +1,44 @@
// 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/sysrepo_connection.h>
namespace isc {
namespace yang {
SysrepoConnection::SysrepoConnection() {
}
SysrepoConnection::~SysrepoConnection() {
if (session_) {
session_->discard_changes();
session_->unlock_datastore();
session_->session_stop();
// how to call disconnect?
}
}
void
SysrepoConnection::connect() {
// Get a connection.
S_Connection conn(new Connection("kea-netconf"));
// Get a session.
session_.reset(new Session(conn, SR_DS_CANDIDATE));
// Get a from yang object.
}
void
SysrepoConnection::commit() {
if (!session_) {
isc_throw(SysrepoConnectionError, "session not established");
}
session_->commit();
}
}
}

View File

@@ -0,0 +1,37 @@
// 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 NETCONF_CONNECTION_H
#define NETCONF_CONNECTION_H
#include <exceptions/exceptions.h>
#include <sysrepo-cpp/Session.h>
namespace isc {
namespace yang {
class SysrepoConnectionError : public Exception {
public:
SysrepoConnectionError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
class SysrepoConnection {
public:
SysrepoConnection();
virtual ~SysrepoConnection();
void connect();
void commit();
private:
S_Session session_;
};
} // sysrepo
} // isc
#endif /* NETCONF_CONNECTION_H_ */

View File

@@ -0,0 +1,26 @@
// 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_SYSREPO_ERROR_H
#define ISC_SYSREPO_ERROR_H 1
#include <exceptions/exceptions.h>
namespace isc {
namespace yang {
/// @brief Sysrepo error.
class SysrepoError : public isc::Exception {
public:
SysrepoError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what)
{}
};
}; // end of namespace isc::yang
}; // end of namespace isc
#endif // ISC_SYSREPO_ERROR_H

View File

@@ -0,0 +1,38 @@
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES) $(SYSREPO_CPPFLAGS)
AM_CPPFLAGS += -DCFG_EXAMPLES=\"$(abs_top_srcdir)/doc/examples\"
AM_CXXFLAGS = $(KEA_CXXFLAGS)
if USE_STATIC_LINK
AM_LDFLAGS = -static
endif
CLEANFILES = *.gcno *.gcda
TESTS_ENVIRONMENT = \
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = translator_unittests.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(top_builddir)/src/lib/yang/testutils/libyangtest.la
run_unittests_LDADD += $(top_builddir)/src/lib/yang/libkea-yang.la
run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
run_unittests_LDADD += $(LOG4CPLUS_LIBS) $(BOOST_LIBS)
run_unittests_LDADD += $(SYSREPO_LIBS) $(GTEST_LDADD)
endif
noinst_PROGRAMS = $(TESTS)

View File

@@ -0,0 +1,20 @@
// 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 <gtest/gtest.h>
#include <util/unittests/run_all.h>
#include <log/logger_support.h>
int
main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
isc::log::initLogger();
return (isc::util::unittests::run_all());
}

View File

@@ -0,0 +1,681 @@
// 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.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 constructor.
TEST(TranslatorBasicTest, constructor) {
// Get a connection.
S_Connection conn(new Connection("translator unittests"));
// Get a session.
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
// Get a translator object.
boost::scoped_ptr<TranslatorBasic> t_obj;
EXPECT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
}
// Test basic yang value to JSON using the static method.
TEST(TranslatorBasicTest, valueFrom) {
S_Val s_val;
ConstElementPtr elem;
// Null.
EXPECT_THROW(TranslatorBasic::value(s_val), BadValue);
// No easy and direct way to build a container or a list...
// String.
string str("foo");
s_val.reset(new Val(str.c_str(), SR_STRING_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ(str, elem->stringValue());
elem.reset();
// Bool.
s_val.reset(new Val(false, SR_BOOL_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::boolean, elem->getType());
EXPECT_FALSE(elem->boolValue());
elem.reset();
// Unsigned 8 bit integer.
uint8_t u8(123);
s_val.reset(new Val(u8, SR_UINT8_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(u8, elem->intValue());
elem.reset();
// Unsigned 16 bit integer.
uint16_t u16(12345);
s_val.reset(new Val(u16, SR_UINT16_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(u16, elem->intValue());
elem.reset();
// Unsigned 32 bit integer.
uint32_t u32(123456789);
s_val.reset(new Val(u32, SR_UINT32_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(u32, elem->intValue());
elem.reset();
// Signed 8 bit integer.
int8_t s8(-123);
s_val.reset(new Val(s8, SR_INT8_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(s8, elem->intValue());
elem.reset();
// Signed 16 bit integer.
int16_t s16(-12345);
s_val.reset(new Val(s16, SR_INT16_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(s16, elem->intValue());
elem.reset();
// Signed 32 bit integer.
int32_t s32(-123456789);
s_val.reset(new Val(s32, SR_INT32_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(s32, elem->intValue());
elem.reset();
// Identity reference.
s_val.reset(new Val(str.c_str(), SR_IDENTITYREF_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ(str, elem->stringValue());
elem.reset();
// Enumeration item.
s_val.reset(new Val(str.c_str(), SR_ENUM_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ(str, elem->stringValue());
elem.reset();
// Binary.
string binary("Zm9vYmFy");
s_val.reset(new Val(binary.c_str(), SR_BINARY_T));
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ("foobar", elem->stringValue());
elem.reset();
// Unknown / unsupported.
double d64(.1234);
s_val.reset(new Val(d64));
EXPECT_THROW(TranslatorBasic::value(s_val), NotImplemented);
}
// Test basic yang value to JSON using sysrepo test models.
TEST(TranslatorBasicTest, getItem) {
// Get a translator object to play with.
S_Connection conn(new Connection("translator unittests"));
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
boost::scoped_ptr<TranslatorBasic> t_obj;
ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
// Container.
string xpath = "/example-module:container/list";
S_Val s_val;
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
ConstElementPtr elem;
EXPECT_NO_THROW(elem = t_obj->getItem("/example-module:container"));
EXPECT_FALSE(elem);
elem.reset();
// List.
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::list, elem->getType());
EXPECT_EQ(0, elem->size());
elem.reset();
// String.
xpath = "/test-module:main/string";
s_val.reset(new Val("str", SR_STRING_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ("str", elem->stringValue());
elem.reset();
// Bool.
xpath = "/test-module:main/boolean";
s_val.reset(new Val(true, SR_BOOL_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::boolean, elem->getType());
EXPECT_TRUE(elem->boolValue());
elem.reset();
// Unsigned 8 bit integer.
xpath = "/test-module:main/ui8";
uint8_t u8(8);
s_val.reset(new Val(u8, SR_UINT8_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(8, elem->intValue());
elem.reset();
// Unsigned 16 bit integer.
xpath = "/test-module:main/ui16";
uint16_t u16(16);
s_val.reset(new Val(u16, SR_UINT16_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(16, elem->intValue());
elem.reset();
// Unsigned 32 bit integer.
xpath = "/test-module:main/ui32";
uint32_t u32(32);
s_val.reset(new Val(u32, SR_UINT32_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(32, elem->intValue());
elem.reset();
// Signed 8 bit integer.
xpath = "/test-module:main/i8";
int8_t s8(8);
s_val.reset(new Val(s8, SR_INT8_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(8, elem->intValue());
elem.reset();
// Signed 16 bit integer.
xpath = "/test-module:main/i16";
int16_t s16(16);
s_val.reset(new Val(s16, SR_INT16_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(16, elem->intValue());
elem.reset();
// Signed 32 bit integer.
xpath = "/test-module:main/i32";
int32_t s32(32);
s_val.reset(new Val(s32, SR_INT32_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::integer, elem->getType());
EXPECT_EQ(32, elem->intValue());
elem.reset();
// Identity reference.
xpath = "/test-module:main/id_ref";
s_val.reset(new Val("id_1", SR_IDENTITYREF_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ("id_1", elem->stringValue());
elem.reset();
// Enumeration item.
xpath = "/test-module:main/enum";
s_val.reset(new Val("maybe", SR_ENUM_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ("maybe", elem->stringValue());
elem.reset();
// Binary.
xpath = "/test-module:main/raw";
s_val.reset(new Val("Zm9vYmFy", SR_BINARY_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::string, elem->getType());
EXPECT_EQ("foobar", elem->stringValue());
elem.reset();
// Leaf-list: not yet exist.
xpath = "/test-module:main/numbers";
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
EXPECT_FALSE(elem);
elem.reset();
// No easy way to create it empty.
// Leaf-list: 1, 2 and 3.
u8 = 1;
s_val.reset(new Val(u8, SR_UINT8_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
u8 = 2;
s_val.reset(new Val(u8, SR_UINT8_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
u8 = 3;
s_val.reset(new Val(u8, SR_UINT8_T));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(elem = t_obj->getItems(xpath));
ASSERT_TRUE(elem);
ASSERT_EQ(Element::list, elem->getType());
EXPECT_EQ(3, elem->size());
EXPECT_EQ("[ 1, 2, 3 ]", elem->str());
elem.reset();
// Unknown / unsupported.
xpath = "/test-module:main/dec64";
s_val.reset(new Val(9.85));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_THROW(elem = t_obj->getItem(xpath), NotImplemented);
elem.reset();
// Not found.
xpath = "/test-module:main/no_such_string";
EXPECT_NO_THROW(sess->delete_item(xpath.c_str()));
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
EXPECT_FALSE(elem);
elem.reset();
// Check error.
xpath = "null";
try {
elem = t_obj->getItem(xpath);
ADD_FAILURE() << "expected exception";
} catch (const SysrepoError& ex) {
EXPECT_EQ("sysrepo error getting item at 'null': Invalid argument",
string(ex.what()));
} catch (const std::exception& ex) {
ADD_FAILURE() << "unexpected exception with: " << ex.what();
}
}
// Test JSON to basic yang value using the static method.
TEST(TranslatorBasicTest, valueTo) {
// Null.
ConstElementPtr elem;
EXPECT_THROW(TranslatorBasic::value(elem, SR_STRING_T), BadValue);
// Container.
elem = Element::createMap();
EXPECT_THROW(TranslatorBasic::value(elem, SR_CONTAINER_T), NotImplemented);
EXPECT_THROW(TranslatorBasic::value(elem, SR_CONTAINER_PRESENCE_T), NotImplemented);
// List.
elem = Element::createList();
S_Val s_val;
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_LIST_T));
EXPECT_FALSE(s_val);
s_val.reset();
// String.
string str("foo");
elem = Element::create(str);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_STRING_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_STRING_T, s_val->type());
EXPECT_EQ(str, string(s_val->data()->get_string()));
s_val.reset();
// Bool.
elem = Element::create(false);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_BOOL_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_BOOL_T, s_val->type());
EXPECT_FALSE(s_val->data()->get_bool());
s_val.reset();
// Unsigned 8 bit integer.
elem = Element::create(123);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT8_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_UINT8_T, s_val->type());
EXPECT_EQ(123, s_val->data()->get_uint8());
elem.reset();
// Unsigned 16 bit integer.
elem = Element::create(12345);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT16_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_UINT16_T, s_val->type());
EXPECT_EQ(12345, s_val->data()->get_uint16());
elem.reset();
// Unsigned 32 bit integer.
elem = Element::create(123456789);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT32_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_UINT32_T, s_val->type());
EXPECT_EQ(123456789, s_val->data()->get_uint32());
elem.reset();
// Signed 8 bit integer.
elem = Element::create(-123);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT8_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_INT8_T, s_val->type());
EXPECT_EQ(-123, s_val->data()->get_int8());
elem.reset();
// Signed 16 bit integer.
elem = Element::create(-12345);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT16_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_INT16_T, s_val->type());
EXPECT_EQ(-12345, s_val->data()->get_int16());
elem.reset();
// Signed 32 bit integer.
elem = Element::create(-123456789);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT32_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_INT32_T, s_val->type());
EXPECT_EQ(-123456789, s_val->data()->get_int32());
elem.reset();
// Identity reference.
elem = Element::create(str);
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_IDENTITYREF_T));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_IDENTITYREF_T, s_val->type());
EXPECT_EQ(str, string(s_val->data()->get_identityref()));
s_val.reset();
// Enumeration item.
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_ENUM_T));
ASSERT_TRUE(s_val);
EXPECT_EQ(str, string(s_val->data()->get_enum()));
s_val.reset();
// Binary.
elem = Element::create(string("foobar"));
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_BINARY_T));
ASSERT_TRUE(s_val);
EXPECT_EQ("Zm9vYmFy", string(s_val->data()->get_binary()));
s_val.reset();
// Unknown / unsupported.
elem = Element::create(.1234);
EXPECT_THROW(TranslatorBasic::value(elem, SR_DECIMAL64_T), NotImplemented);
}
// Test JSON to basic yang value using sysrepo test models.
TEST(TranslatorBasicTest, setItem) {
// Get a translator object to play with.
S_Connection conn(new Connection("translator unittests"));
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
boost::scoped_ptr<TranslatorBasic> t_obj;
ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
// Container.
string xpath = "/example-module:container";
ConstElementPtr elem = Element::createMap();
EXPECT_THROW(t_obj->setItem(xpath, elem, SR_CONTAINER_T), NotImplemented);
EXPECT_THROW(t_obj->setItem(xpath, elem, SR_CONTAINER_PRESENCE_T),
NotImplemented);
// List.
xpath = "/example-module:container/list";
elem = Element::createList();
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_LIST_T));
S_Val s_val;
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_LIST_T, s_val->type());
s_val.reset();
// String.
xpath = "/test-module:main/string";
elem = Element::create(string("str"));
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_STRING_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_STRING_T, s_val->type());
EXPECT_EQ("str", string(s_val->data()->get_string()));
s_val.reset();
// Bool.
xpath = "/test-module:main/boolean";
elem = Element::create(true);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_BOOL_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_BOOL_T, s_val->type());
EXPECT_TRUE(s_val->data()->get_bool());
s_val.reset();
// Unsigned 8 bit integer.
xpath = "/test-module:main/ui8";
elem = Element::create(8);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_UINT8_T, s_val->type());
EXPECT_EQ(8, s_val->data()->get_uint8());
s_val.reset();
// Unsigned 16 bit integer.
xpath = "/test-module:main/ui16";
elem = Element::create(16);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT16_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_UINT16_T, s_val->type());
EXPECT_EQ(16, s_val->data()->get_uint16());
s_val.reset();
// Unsigned 32 bit integer.
xpath = "/test-module:main/ui32";
elem = Element::create(32);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT32_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_UINT32_T, s_val->type());
EXPECT_EQ(32, s_val->data()->get_uint32());
s_val.reset();
// Signed 8 bit integer.
xpath = "/test-module:main/i8";
elem = Element::create(8);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT8_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_INT8_T, s_val->type());
EXPECT_EQ(8, s_val->data()->get_int8());
s_val.reset();
// Signed 16 bit integer.
xpath = "/test-module:main/i16";
elem = Element::create(16);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT16_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_INT16_T, s_val->type());
EXPECT_EQ(16, s_val->data()->get_int16());
s_val.reset();
// Signed 32 bit integer.
xpath = "/test-module:main/i32";
elem = Element::create(32);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT32_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_INT32_T, s_val->type());
EXPECT_EQ(32, s_val->data()->get_int32());
s_val.reset();
// Identity reference.
xpath = "/test-module:main/id_ref";
elem = Element::create(string("id_1"));
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_IDENTITYREF_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_IDENTITYREF_T, s_val->type());
EXPECT_EQ("id_1", string(s_val->data()->get_identityref()));
s_val.reset();
// Enumeration item.
xpath = "/test-module:main/enum";
elem = Element::create(string("maybe"));
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_ENUM_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_ENUM_T, s_val->type());
EXPECT_EQ("maybe", string(s_val->data()->get_enum()));
s_val.reset();
// Binary.
xpath = "/test-module:main/raw";
elem = Element::create(string("foobar"));
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_BINARY_T));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
ASSERT_TRUE(s_val);
ASSERT_EQ(SR_BINARY_T, s_val->type());
EXPECT_EQ("Zm9vYmFy", string(s_val->data()->get_binary()));
s_val.reset();
// Leaf-list.
xpath = "/test-module:main/numbers";
S_Vals s_vals;
EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
EXPECT_FALSE(s_vals);
s_vals.reset();
// Fill it.
elem = Element::create(1);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
elem = Element::create(2);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
elem = Element::create(3);
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
ASSERT_TRUE(s_vals);
EXPECT_EQ(3, s_vals->val_cnt());
s_vals.reset();
// Clean it.
EXPECT_NO_THROW(t_obj->delItem(xpath));
EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
EXPECT_FALSE(s_vals);
s_vals.reset();
// Unknown / unsupported.
xpath = "/test-module:main/dec64";
elem = Element::create(9.85);
EXPECT_THROW(t_obj->setItem(xpath, elem, SR_DECIMAL64_T), NotImplemented);
// Bad xpath.
xpath = "/test-module:main/no_such_string";
elem = Element::create(string("str"));
try {
t_obj->setItem(xpath, elem, SR_STRING_T);
ADD_FAILURE() << "expected exception";
} catch (const SysrepoError& ex) {
string expected = "sysrepo error setting item '\"str\"' at '" +
xpath + "': Request contains unknown element";
EXPECT_EQ(expected, string(ex.what()));
} catch (const std::exception& ex) {
ADD_FAILURE() << "unexpected exception with: " << ex.what();
}
// Bad type.
xpath = "/test-module:main/string";
elem = Element::create(true);
try {
t_obj->setItem(xpath, elem, SR_BOOL_T);
ADD_FAILURE() << "expected exception";
} catch (const SysrepoError& ex) {
string expected = "sysrepo error setting item 'true' at '" +
xpath + "': Invalid argument";
EXPECT_EQ(expected, string(ex.what()));
} catch (const std::exception& ex) {
ADD_FAILURE() << "unexpected exception with: " << ex.what();
}
// Delete (twice).
xpath = "/test-module:main/string";
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
EXPECT_TRUE(s_val);
s_val.reset();
EXPECT_NO_THROW(t_obj->delItem(xpath));
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
EXPECT_FALSE(s_val);
EXPECT_NO_THROW(t_obj->delItem(xpath));
}
// Test yang list iteration.
TEST(TranslatorBasicTest, list) {
// Get a translator object to play with.
S_Connection conn(new Connection("translator unittests"));
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
boost::scoped_ptr<TranslatorBasic> t_obj;
ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
// Empty list.
S_Iter_Value iter;
EXPECT_NO_THROW(iter = t_obj->getIter("/example-module:container/list"));
ASSERT_TRUE(iter);
string xpath;
EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
EXPECT_TRUE(xpath.empty());
// Retried with a filled list.
xpath = "/example-module:container/list[key1='key1'][key2='key2']/leaf";
S_Val s_val(new Val("Leaf value"));
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
EXPECT_NO_THROW(iter = t_obj->getIter("/example-module:container/list"));
ASSERT_TRUE(iter);
EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
EXPECT_EQ("/example-module:container/list[key1='key1'][key2='key2']", xpath);
EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
EXPECT_TRUE(xpath.empty());
// Not found: same than empty because sr_get_items_iter() translates
// SR_ERR_NOT_FOUND by SR_ERR_OK...
}
}; // end of anonymous namespace

276
src/lib/yang/translator.cc Normal file
View File

@@ -0,0 +1,276 @@
// 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.h>
#include <util/encode/base64.h>
#include <cstring>
using namespace std;
using namespace isc::data;
using namespace isc::util::encode;
namespace {
string encode64(const string& input) {
vector<uint8_t> binary;
binary.resize(input.size());
memmove(&binary[0], input.c_str(), binary.size());
return (encodeBase64(binary));
}
string decode64(const string& input) {
vector<uint8_t> binary;
decodeBase64(input, binary);
string result;
result.resize(binary.size());
memmove(&result[0], &binary[0], result.size());
return (result);
}
} // end of anonymous namespace
namespace isc {
namespace yang {
TranslatorBasic::TranslatorBasic(S_Session session) : session_(session) {
}
TranslatorBasic::~TranslatorBasic() {
}
ElementPtr
TranslatorBasic::value(S_Val s_val) {
if (!s_val) {
isc_throw(BadValue, "value called with null");
}
switch (s_val->type()) {
case SR_CONTAINER_T:
case SR_CONTAINER_PRESENCE_T:
// Internal node.
return (ElementPtr());
case SR_LIST_T:
return (Element::createList());
case SR_STRING_T:
return (Element::create(string(s_val->data()->get_string())));
case SR_BOOL_T:
return (Element::create(s_val->data()->get_bool() ? true : false));
case SR_UINT8_T:
return (Element::create(static_cast<long long>(s_val->data()->get_uint8())));
case SR_UINT16_T:
return (Element::create(static_cast<long long>(s_val->data()->get_uint16())));
case SR_UINT32_T:
return (Element::create(static_cast<long long>(s_val->data()->get_uint32())));
case SR_INT8_T:
return (Element::create(static_cast<long long>(s_val->data()->get_int8())));
case SR_INT16_T:
return (Element::create(static_cast<long long>(s_val->data()->get_int16())));
case SR_INT32_T:
return (Element::create(static_cast<long long>(s_val->data()->get_int32())));
case SR_IDENTITYREF_T:
return (Element::create(string(s_val->data()->get_identityref())));
case SR_ENUM_T:
return (Element::create(string(s_val->data()->get_enum())));
case SR_BINARY_T:
return (Element::create(decode64(s_val->data()->get_binary())));
default:
isc_throw(NotImplemented,
"value called with unupported type: " << s_val->type());
}
}
ElementPtr
TranslatorBasic::getItem(const string& xpath) {
S_Val s_val;
try {
s_val = session_->get_item(xpath.c_str());
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error getting item at '" << xpath
<< "': " << ex.what());
}
if (!s_val) {
return (ElementPtr());
}
return (value(s_val));
}
ElementPtr
TranslatorBasic::getItems(const string& xpath) {
S_Vals s_vals;
try {
s_vals = session_->get_items(xpath.c_str());
if (!s_vals) {
return (ElementPtr());
}
ElementPtr result = Element::createList();
for (size_t i = 0; i < s_vals->val_cnt(); ++i) {
S_Val s_val = s_vals->val(i);
result->add(value(s_val));
}
return (result);
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error getting item at '" << xpath
<< "': " << ex.what());
}
}
S_Val
TranslatorBasic::value(ConstElementPtr elem, sr_type_t type) {
if (!elem) {
isc_throw(BadValue, "value called with null");
}
S_Val s_val;
switch (type) {
case SR_CONTAINER_T:
case SR_CONTAINER_PRESENCE_T:
isc_throw(NotImplemented, "value called for a container");
case SR_LIST_T:
if (elem->getType() != Element::list) {
isc_throw(BadValue, "value for a list called with not a list");
}
// Return null.
break;
case SR_STRING_T:
case SR_IDENTITYREF_T:
case SR_ENUM_T:
if (elem->getType() != Element::string) {
isc_throw(BadValue, "value for a string called with not a string");
}
s_val.reset(new Val(elem->stringValue().c_str(), type));
break;
case SR_BOOL_T:
if (elem->getType() != Element::boolean) {
isc_throw(BadValue, "value for a boolean called with not a boolean");
}
s_val.reset(new Val(elem->boolValue(), type));
break;
case SR_UINT8_T:
if (elem->getType() != Element::integer) {
isc_throw(BadValue, "value for an integer called with not an integer");
}
s_val.reset(new Val(static_cast<uint8_t>(elem->intValue()), type));
break;
case SR_UINT16_T:
if (elem->getType() != Element::integer) {
isc_throw(BadValue, "value for an integer called with not an integer");
}
s_val.reset(new Val(static_cast<uint16_t>(elem->intValue()), type));
break;
case SR_UINT32_T:
if (elem->getType() != Element::integer) {
isc_throw(BadValue, "value for an integer called with not an integer");
}
s_val.reset(new Val(static_cast<uint32_t>(elem->intValue()), type));
break;
case SR_INT8_T:
if (elem->getType() != Element::integer) {
isc_throw(BadValue, "value for an integer called with not an integer");
}
s_val.reset(new Val(static_cast<int8_t>(elem->intValue()), type));
break;
case SR_INT16_T:
if (elem->getType() != Element::integer) {
isc_throw(BadValue, "value for an integer called with not an integer");
}
s_val.reset(new Val(static_cast<int16_t>(elem->intValue()), type));
break;
case SR_INT32_T:
if (elem->getType() != Element::integer) {
isc_throw(BadValue, "value for an integer called with not an integer");
}
s_val.reset(new Val(static_cast<int32_t>(elem->intValue()), type));
break;
case SR_BINARY_T:
if (elem->getType() != Element::string) {
isc_throw(BadValue, "value for a base64 called with not a string");
}
s_val.reset(new Val(encode64(elem->stringValue()).c_str(), type));
break;
default:
isc_throw(NotImplemented,
"value called with unupported type: " << type);
}
return (s_val);
}
void
TranslatorBasic::setItem(const string& xpath, ConstElementPtr elem,
sr_type_t type) {
S_Val s_val = value(elem, type);
if (!s_val && (type != SR_LIST_T)) {
return;
}
try {
session_->set_item(xpath.c_str(), s_val);
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error setting item '" << elem->str()
<< "' at '" << xpath << "': " << ex.what());
}
}
void
TranslatorBasic::delItem(const std::string& xpath) {
try {
session_->delete_item(xpath.c_str());
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error deleting item at '"
<< xpath << "': " << ex.what());
}
}
S_Iter_Value
TranslatorBasic::getIter(const std::string& xpath) {
return (session_->get_items_iter(xpath.c_str()));
}
string
TranslatorBasic::getNext(S_Iter_Value iter) {
if (!iter) {
isc_throw(BadValue, "getNext called with null");
}
S_Val s_val;
try {
s_val = session_->get_item_next(iter);
} catch (const sysrepo_exception&) {
// Should not happen according to the doc but still happen?
return ("");
}
if (!s_val) {
return ("");
}
return (s_val->xpath());
}
}; // end of namespace isc::yang
}; // end of namespace isc

99
src/lib/yang/translator.h Normal file
View File

@@ -0,0 +1,99 @@
// 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_H
#define ISC_TRANSLATOR_H 1
#include <cc/data.h>
#include <yang/sysrepo_error.h>
#include <sysrepo-cpp/Session.h>
namespace isc {
namespace yang {
/// @brief Between Yang and JSON translator class for basic values.
class TranslatorBasic {
public:
/// @brief Constructor.
///
/// @param session Sysrepo session.
TranslatorBasic(S_Session session);
/// @brief Destructor.
virtual ~TranslatorBasic();
/// @brief Translate basic value from Yang to JSON.
///
/// @note Please don't use this outside tests.
///
/// @param s_val The value.
/// @return The Element representing the sysrepo value.
/// @throw NotImplemented when the value type is not supported.
static isc::data::ElementPtr value(S_Val s_val);
/// @brief Get and translate basic value from Yang to JSON.
///
/// @note Should be const as it is read only...
///
/// @param xpath The xpath of the basic value.
/// @return The Element representing the item at xpath or null when not found.
/// @throw SysrepoError when sysrepo raises an error.
/// @throw NotImplemented when the value type is not supported.
isc::data::ElementPtr getItem(const std::string& xpath);
/// @brief Get and translate a list of basic values from Yang to JSON.
///
/// @param xpath The xpath of the list of basic values.
/// @return The ListElement representing the leaf-list at xpath or
/// null when not found.
isc::data::ElementPtr getItems(const std::string& xpath);
/// @brief Translate basic value from JSON to Yang.
///
/// @note Please don't use this outside tests.
///
/// @param elem The JSON element.
/// @param type The sysrepo type.
static S_Val value(isc::data::ConstElementPtr elem, sr_type_t type);
/// @brief Translate and set basic value from JSON to Yang.
///
/// @param xpath The xpath of the basic value.
/// @param elem The JSON element.
/// @param type The sysrepo type.
void setItem(const std::string& xpath, isc::data::ConstElementPtr elem,
sr_type_t type);
/// @brief Delete basic value from Yang.
///
/// @param xpath The xpath of the basic value.
void delItem(const std::string& xpath);
/// List iterator methods keeping the session private.
/// @brief Get iterator over a Yang list.
///
/// @param xpath The xpath of the list.
/// @return An S_Iter_Value pointer. Null is the list does not exist.
S_Iter_Value getIter(const std::string& xpath);
/// @brief Get xpath of the next Yang list item.
///
/// @param iter The iterator.
/// @return The xpath of the next element. Null when at the end of the list.
std::string getNext(S_Iter_Value iter);
protected:
/// @brief The sysrepo session.
S_Session session_;
};
}; // end of namespace isc::yang
}; // end of namespace isc
#endif // ISC_TRANSLATOR_H

35
src/lib/yang/watcher.cc Normal file
View File

@@ -0,0 +1,35 @@
// 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/watcher.h>
using namespace std;
using namespace isc::data;
namespace isc {
namespace yang {
Watcher::Watcher(SysrepoConnection &connection, const string &xpath)
: xpath_(xpath), netconf_data_(0), connection_(connection) {
};
Watcher::~Watcher() {
}
string
Watcher::getXPath() {
return (xpath_);
}
ElementPtr
Watcher::getJSON() {
return (json_);
}
} // namespace netconf
} // namespace isc

59
src/lib/yang/watcher.h Normal file
View File

@@ -0,0 +1,59 @@
// 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_WATCHER_H
#define ISC_WATCHER_H
#include <config.h>
#include <boost/shared_ptr.hpp>
#include <cc/data.h>
#include <yang/sysrepo_connection.h>
namespace isc {
namespace yang {
/// @brief This represents a base class for all watchers.
///
/// Isc_Watcher is an object that receives callback notification
/// from sysrepo (in YANG format) and converts it to appropriate
/// JSON that can be sent over control channel and understood by Kea.
class Watcher {
public:
// Constructor (requires xpath to install a callback)
Watcher(SysrepoConnection &connection, const std::string &xpath);
virtual ~Watcher();
virtual std::string getXPath();
// This method will be called when the callback returns.
// Need to figure out the type used.
void setYangData(void *data);
// This method translates Netconf data to JSON format
// understood by Kea.
virtual void translate() = 0;
// Once setYangData is called,
isc::data::ElementPtr getJSON();
protected:
std::string xpath_;
void *netconf_data_;
isc::data::ElementPtr json_;
SysrepoConnection &connection_;
};
typedef boost::shared_ptr<Watcher> WatcherPtr;
} // namespace isc::yang
} // namespace isc
#endif /* ISC_WATCHER_H */

46
src/lib/yang/yang.dox Normal file
View File

@@ -0,0 +1,46 @@
// 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/.
/**
@page libyang libkea-yang - Kea Yang Utilities Library
All translators take a seesion in constructors and derive from
the basic / base class and recursively of translators for
embedded parts.
@section yangTranslator between Yang and JSON Translator
@c isc::yang::TranslatorBasic provides some methods:
- getItem() gets and translates basic value from Yang to JSON
- getItems() gets and translates a leaf-list from Yang to JSON
(for a list please use an iterator)
- setItem() translates and sets a basic value from JSON to Yang
- delItem() deletes a value
- getIter() gets an iterator over a Yang list
- getNext() returns the xpath of the next item
@section yangTranslatorPool between Yang and JSON Translator for pool
@c isc::yang::TranslatorPool is the standard example of a translator
for a structured value. Its constructor takes a model name: the code
implements some variants to accommodate the model with shared code
moved into a common private routine.
@c isc::yang::TranslatorPools deals with a list of pools. The getPools
method iterates over thr lidt in both ways. Loot at examples in unit
tests to understand how can be filled.
Note pools show two shortcomings in IETF models:
- option sets make to track changes nearly impossible: the only easy
code is to translate the whole configuration.
- prefix and start - end forms of pool ranges are both mandatory.
@section yangTranslatorSubnet between Yang and JSON Translator for subnet
The new thing here is the use of adaptors to move timers from subnets
to pools and back.
*/