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:
33
src/lib/yang/Makefile.am
Normal file
33
src/lib/yang/Makefile.am
Normal 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
|
44
src/lib/yang/sysrepo_connection.cc
Normal file
44
src/lib/yang/sysrepo_connection.cc
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
37
src/lib/yang/sysrepo_connection.h
Normal file
37
src/lib/yang/sysrepo_connection.h
Normal 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_ */
|
26
src/lib/yang/sysrepo_error.h
Normal file
26
src/lib/yang/sysrepo_error.h
Normal 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
|
38
src/lib/yang/tests/Makefile.am
Normal file
38
src/lib/yang/tests/Makefile.am
Normal 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)
|
20
src/lib/yang/tests/run_unittests.cc
Normal file
20
src/lib/yang/tests/run_unittests.cc
Normal 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());
|
||||
}
|
681
src/lib/yang/tests/translator_unittests.cc
Normal file
681
src/lib/yang/tests/translator_unittests.cc
Normal 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
276
src/lib/yang/translator.cc
Normal 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
99
src/lib/yang/translator.h
Normal 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
35
src/lib/yang/watcher.cc
Normal 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
59
src/lib/yang/watcher.h
Normal 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
46
src/lib/yang/yang.dox
Normal 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.
|
||||
|
||||
*/
|
Reference in New Issue
Block a user