From: Francis Dupont Date: Thu, 13 Sep 2018 13:46:54 +0000 (+0200) Subject: [65-libyang-database] Filled files, waiting for adaptor merge X-Git-Tag: 171-keactrl-tests-not-posix_base~7^2~1^2^2~2^2~6^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8aaecbde5dd2e8ac57f3dde47c1d5f70d0d442e8;p=thirdparty%2Fkea.git [65-libyang-database] Filled files, waiting for adaptor merge --- diff --git a/src/lib/yang/Makefile.am b/src/lib/yang/Makefile.am index 01b3a633af..a9830c3deb 100644 --- a/src/lib/yang/Makefile.am +++ b/src/lib/yang/Makefile.am @@ -7,6 +7,7 @@ AM_CXXFLAGS = $(KEA_CXXFLAGS) lib_LTLIBRARIES = libkea-yang.la libkea_yang_la_SOURCES = sysrepo_error.h libkea_yang_la_SOURCES += translator.cc translator.h +libkea_yang_la_SOURCES += translator_database.cc translator_database.h libkea_yang_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la libkea_yang_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la diff --git a/src/lib/yang/tests/Makefile.am b/src/lib/yang/tests/Makefile.am index f54de89164..471f984fb8 100644 --- a/src/lib/yang/tests/Makefile.am +++ b/src/lib/yang/tests/Makefile.am @@ -18,6 +18,7 @@ TESTS = if HAVE_GTEST TESTS += run_unittests run_unittests_SOURCES = translator_unittests.cc +run_unittests_SOURCES += translator_database_unittests.cc run_unittests_SOURCES += run_unittests.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) diff --git a/src/lib/yang/tests/translator_database_unittests.cc b/src/lib/yang/tests/translator_database_unittests.cc new file mode 100644 index 0000000000..9001d4dee2 --- /dev/null +++ b/src/lib/yang/tests/translator_database_unittests.cc @@ -0,0 +1,347 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include + +#include +#include + +using namespace std; +using namespace isc; +using namespace isc::data; +using namespace isc::yang; + +namespace { + +// Test get empty database using the ad hoc model. +TEST(TranslatorDatabaseTest, getEmpty) { + // Get a translator database object to play with. + S_Connection conn(new Connection("translator database access unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr td_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp4"; + EXPECT_NO_THROW(td_obj.reset(new TranslatorDatabase(sess, model))); + + // Get empty. + const string& xpath = "/kea-dhcp4:config/lease-database"; + ConstElementPtr database; + EXPECT_NO_THROW(database = td_obj->getDatabase(xpath)); + EXPECT_FALSE(database); +} + +// Test get a database using the ad hoc model. +TEST(TranslatorDatabaseTest, get) { + // Get a translator database object to play with. + S_Connection conn(new Connection("translator database access unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr td_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp4"; + EXPECT_NO_THROW(td_obj.reset(new TranslatorDatabase(sess, model))); + + // Set a value. + const string& xpath = "/kea-dhcp4:config/lease-database"; + const string& xtype = xpath + "/database-type"; + const string& xinterval = xpath + "/lfc-interval"; + S_Val s_type(new Val("memfile")); + EXPECT_NO_THROW(sess->set_item(xtype.c_str(), s_type)); + uint32_t li = 3600; + S_Val s_interval(new Val(li, SR_UINT32_T)); + EXPECT_NO_THROW(sess->set_item(xinterval.c_str(), s_interval)); + + // Get empty. + ConstElementPtr database; + EXPECT_NO_THROW(database = td_obj->getDatabase(xpath)); + ASSERT_TRUE(database); + EXPECT_EQ(2, database->size()); + ConstElementPtr type = database->get("type"); + ASSERT_TRUE(type); + ASSERT_EQ(Element::string, type->getType()); + EXPECT_EQ("memfile", type->stringValue()); + ConstElementPtr interval = database->get("lfc-interval"); + ASSERT_TRUE(interval); + ASSERT_EQ(Element::integer, interval->getType()); + EXPECT_EQ(li, interval->intValue()); +} + +// Test set a database using the ad hoc model. +TEST(TranslatorDatabaseTest, set) { + // Get a translator database object to play with. + S_Connection conn(new Connection("translator database access unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr td_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp4"; + EXPECT_NO_THROW(td_obj.reset(new TranslatorDatabase(sess, model))); + + // Set a value. + const string& xpath = "/kea-dhcp4:config/lease-database"; + ElementPtr database = Element::createMap(); + database->set("type", Element::create(string("memfile"))); + database->set("lfc-interval", Element::create(3600)); + ASSERT_NO_THROW(td_obj->setDatabase(xpath, database)); + + // Get it back. + ConstElementPtr got; + EXPECT_NO_THROW(got = td_obj->getDatabase(xpath)); + ASSERT_TRUE(got); + ASSERT_EQ(Element::map, got->getType()); + EXPECT_EQ(2, got->size()); + ConstElementPtr type = got->get("type"); + ASSERT_TRUE(type); + ASSERT_EQ(Element::string, type->getType()); + EXPECT_EQ("memfile", type->stringValue()); + ConstElementPtr interval = database->get("lfc-interval"); + ASSERT_TRUE(interval); + ASSERT_EQ(Element::integer, interval->getType()); + EXPECT_EQ(3600, interval->intValue()); +} + +// Test set empty database using the ad hoc model. +TEST(TranslatorDatabaseTest, setEmpty) { + // Get a translator database object to play with. + S_Connection conn(new Connection("translator database access unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr td_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp4"; + EXPECT_NO_THROW(td_obj.reset(new TranslatorDatabase(sess, model))); + + // Set a value. + const string& xpath = "/kea-dhcp4:config/lease-database"; + const string& xtype = xpath + "/database-type"; + const string& xinterval = xpath + "/lfc-interval"; + S_Val s_type(new Val("memfile")); + EXPECT_NO_THROW(sess->set_item(xtype.c_str(), s_type)); + uint32_t li = 3600; + S_Val s_interval(new Val(li, SR_UINT32_T)); + EXPECT_NO_THROW(sess->set_item(xinterval.c_str(), s_interval)); + + // Reset to empty. + ASSERT_NO_THROW(td_obj->setDatabase(xpath, ConstElementPtr())); + + // Get it back. + ConstElementPtr database; + EXPECT_NO_THROW(database = td_obj->getDatabase(xpath)); + EXPECT_FALSE(database); +} + +// Test get empty databases. +TEST(TranslatorDatabasesTest, getEmpty) { + // Get a translator databases object to play with. + S_Connection conn(new Connection("translator database accesses unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr tds_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp6"; + EXPECT_NO_THROW(tds_obj.reset(new TranslatorDatabases(sess, model))); + + // Get empty. + const string& xpath = "/kea-dhcp6:config/hosts-databases"; + ConstElementPtr databases; + EXPECT_NO_THROW(databases = tds_obj->getDatabases(xpath)); + EXPECT_FALSE(databases); +} + +// Test get databases. +TEST(TranslatorDatabasesTest, get) { + // Get a translator databases object to play with. + S_Connection conn(new Connection("translator database accesses unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr tds_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp4"; + EXPECT_NO_THROW(tds_obj.reset(new TranslatorDatabases(sess, model))); + + // Set a value. + const string& xpath = "/kea-dhcp4:config/hosts-databases"; + const string& xdatabase = + xpath + "/hosts-database[database-type='mysql']"; + const string& xname = xdatabase + "/name"; + const string& xuser = xdatabase + "/user"; + const string& xpassword = xdatabase + "/password"; + const string& xhost = xdatabase + "/host"; + const string& xport = xdatabase + "/port"; + S_Val s_name(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xname.c_str(), s_name)); + S_Val s_user(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xuser.c_str(), s_user)); + S_Val s_password(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xpassword.c_str(), s_password)); + S_Val s_host(new Val("localhost")); + EXPECT_NO_THROW(sess->set_item(xhost.c_str(), s_host)); + uint16_t mport = 3306; + S_Val s_port(new Val(mport, SR_UINT16_T)); + EXPECT_NO_THROW(sess->set_item(xport.c_str(), s_port)); + + // Get empty. + ConstElementPtr databases; + EXPECT_NO_THROW(databases = tds_obj->getDatabases(xpath)); + ASSERT_TRUE(databases); + ASSERT_EQ(1, databases->size()); + ConstElementPtr database = databases->get(0); + ASSERT_TRUE(database); + EXPECT_EQ(6, database->size()); + ConstElementPtr type = database->get("type"); + ASSERT_TRUE(type); + ASSERT_EQ(Element::string, type->getType()); + EXPECT_EQ("mysql", type->stringValue()); + ConstElementPtr name = database->get("name"); + ASSERT_TRUE(name); + ASSERT_EQ(Element::string, name->getType()); + EXPECT_EQ("kea", name->stringValue()); + ConstElementPtr user = database->get("user"); + ASSERT_TRUE(user); + ASSERT_EQ(Element::string, user->getType()); + EXPECT_EQ("kea", user->stringValue()); + ConstElementPtr password = database->get("password"); + ASSERT_TRUE(password); + ASSERT_EQ(Element::string, password->getType()); + EXPECT_EQ("kea", password->stringValue()); + ConstElementPtr host = database->get("host"); + ASSERT_TRUE(host); + ASSERT_EQ(Element::string, host->getType()); + EXPECT_EQ("localhost", host->stringValue()); + ConstElementPtr port = database->get("port"); + ASSERT_TRUE(port); + ASSERT_EQ(Element::integer, port->getType()); + EXPECT_EQ(mport, port->intValue()); +} + +// Test set databases. +TEST(TranslatorDatabasesTest, set) { + // Get a translator databases object to play with. + S_Connection conn(new Connection("translator database accesses unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr tds_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp6"; + EXPECT_NO_THROW(tds_obj.reset(new TranslatorDatabases(sess, model))); + + // Set a value. + const string& xpath = "/kea-dhcp6:config/hosts-databases"; + ElementPtr database = Element::createMap(); + database->set("type", Element::create(string("memfile"))); + database->set("lfc-interval", Element::create(3600)); + ElementPtr databases = Element::createList(); + databases->add(database); + ASSERT_NO_THROW(tds_obj->setDatabases(xpath, databases)); + + // Get it back. + ConstElementPtr gots; + EXPECT_NO_THROW(gots = tds_obj->getDatabases(xpath)); + ASSERT_TRUE(gots); + ASSERT_EQ(Element::list, gots->getType()); + ASSERT_EQ(1, gots->size()); + ConstElementPtr got = gots->get(0); + ASSERT_TRUE(got); + ASSERT_EQ(Element::map, got->getType()); + EXPECT_EQ(2, got->size()); + ConstElementPtr type = got->get("type"); + ASSERT_TRUE(type); + ASSERT_EQ(Element::string, type->getType()); + EXPECT_EQ("memfile", type->stringValue()); + ConstElementPtr interval = database->get("lfc-interval"); + ASSERT_TRUE(interval); + ASSERT_EQ(Element::integer, interval->getType()); + EXPECT_EQ(3600, interval->intValue()); +} + +// Test set empty database. +TEST(TranslatorDatabasesTest, setEmpty) { + // Get a translator databases object to play with. + S_Connection conn(new Connection("translator database accesses unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr tds_obj; + boost::scoped_ptr td_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp4"; + EXPECT_NO_THROW(tds_obj.reset(new TranslatorDatabases(sess, model))); + EXPECT_NO_THROW(td_obj.reset(new TranslatorDatabase(sess, model))); + + // Set a value. + const string& xpath = "/kea-dhcp4:config/hosts-databases"; + const string& xdatabase = + xpath + "/hosts-database[database-type='mysql']"; + const string& xname = xdatabase + "/name"; + const string& xuser = xdatabase + "/user"; + const string& xpassword = xdatabase + "/password"; + const string& xhost = xdatabase + "/host"; + const string& xport = xdatabase + "/port"; + S_Val s_name(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xname.c_str(), s_name)); + S_Val s_user(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xuser.c_str(), s_user)); + S_Val s_password(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xpassword.c_str(), s_password)); + S_Val s_host(new Val("localhost")); + EXPECT_NO_THROW(sess->set_item(xhost.c_str(), s_host)); + uint16_t mport = 3306; + S_Val s_port(new Val(mport, SR_UINT16_T)); + EXPECT_NO_THROW(sess->set_item(xport.c_str(), s_port)); + + // Reset to empty. + ASSERT_NO_THROW(td_obj->setDatabase(xdatabase, ConstElementPtr())); + + // Get empty. + ConstElementPtr databases; + EXPECT_NO_THROW(databases = tds_obj->getDatabases(xpath)); + EXPECT_FALSE(databases); +} + +// Test set empty databases. +TEST(TranslatorDatabasesTest, setEmpties) { + // Get a translator databases object to play with. + S_Connection conn(new Connection("translator database accesses unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + boost::scoped_ptr tds_obj; + + // Use the ad hoc model. + const string& model = "kea-dhcp4"; + EXPECT_NO_THROW(tds_obj.reset(new TranslatorDatabases(sess, model))); + + // Set a value. + const string& xpath = "/kea-dhcp4:config/hosts-databases"; + const string& xdatabase = + xpath + "/hosts-database[database-type='mysql']"; + const string& xname = xdatabase + "/name"; + const string& xuser = xdatabase + "/user"; + const string& xpassword = xdatabase + "/password"; + const string& xhost = xdatabase + "/host"; + const string& xport = xdatabase + "/port"; + S_Val s_name(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xname.c_str(), s_name)); + S_Val s_user(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xuser.c_str(), s_user)); + S_Val s_password(new Val("kea")); + EXPECT_NO_THROW(sess->set_item(xpassword.c_str(), s_password)); + S_Val s_host(new Val("localhost")); + EXPECT_NO_THROW(sess->set_item(xhost.c_str(), s_host)); + uint16_t mport = 3306; + S_Val s_port(new Val(mport, SR_UINT16_T)); + EXPECT_NO_THROW(sess->set_item(xport.c_str(), s_port)); + + // Reset to empty. + ASSERT_NO_THROW(tds_obj->setDatabases(xdatabase, ConstElementPtr())); + + // Get empty. + ConstElementPtr databases; + EXPECT_NO_THROW(databases = tds_obj->getDatabases(xpath)); + EXPECT_FALSE(databases); +} + +}; // end of anonymous namespace diff --git a/src/lib/yang/translator_database.cc b/src/lib/yang/translator_database.cc new file mode 100644 index 0000000000..102c328ee2 --- /dev/null +++ b/src/lib/yang/translator_database.cc @@ -0,0 +1,306 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include + +using namespace std; +using namespace isc::data; + +namespace isc { +namespace yang { + +TranslatorDatabase::TranslatorDatabase(S_Session session, const string& model) + : TranslatorBasic(session), model_(model) { +} + +TranslatorDatabase::~TranslatorDatabase() { +} + +ElementPtr +TranslatorDatabase::getDatabase(const string& xpath) { + try { + if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) { + return (getDatabaseKea(xpath)); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error getting database access at '" << xpath + << "': " << ex.what()); + } + isc_throw(NotImplemented, + "getDatabase not implemented for the model: " << model_); +} + +ElementPtr +TranslatorDatabase::getDatabaseKea(const string& xpath) { + ConstElementPtr type = getItem(xpath + "/database-type"); + if (!type) { + return (ElementPtr()); + } + ElementPtr result = Element::createMap(); + result->set("type", type); + ConstElementPtr user = getItem(xpath + "/user"); + if (user) { + result->set("user", user); + } + ConstElementPtr password = getItem(xpath + "/password"); + if (password) { + result->set("password", password); + } + ConstElementPtr host = getItem(xpath + "/host"); + if (host) { + result->set("host", host); + } + ConstElementPtr name = getItem(xpath + "/name"); + if (name) { + result->set("name", name); + } + ConstElementPtr persist = getItem(xpath + "/persist"); + if (persist) { + result->set("persist", persist); + } + ConstElementPtr port = getItem(xpath + "/port"); + if (port) { + result->set("port", port); + } + ConstElementPtr lfc_interval = getItem(xpath + "/lfc-interval"); + if (lfc_interval) { + result->set("lfc-interval", lfc_interval); + } + ConstElementPtr readonly = getItem(xpath + "/readonly"); + if (readonly) { + result->set("readonly", readonly); + } + ConstElementPtr connect_timeout = getItem(xpath + "/connect-timeout"); + if (connect_timeout) { + result->set("connect-timeout", connect_timeout); + } + ConstElementPtr contact_points = getItem(xpath + "/contact-points"); + if (contact_points) { + result->set("contact-points", contact_points); + } + ConstElementPtr keyspace = getItem(xpath + "/keyspace"); + if (keyspace) { + result->set("keyspace", keyspace); + } + ConstElementPtr max_reconnect = getItem(xpath + "/max-reconnect-tries"); + if (max_reconnect) { + result->set("max-reconnect-tries", max_reconnect); + } + ConstElementPtr reconnect_time = getItem(xpath + "/reconnect-wait-time"); + if (reconnect_time) { + result->set("reconnect-wait-time", reconnect_time); + } + ConstElementPtr request_timeout = getItem(xpath + "/request-timeout"); + if (request_timeout) { + result->set("request-timeout", request_timeout); + } + ConstElementPtr keepalive = getItem(xpath + "/tcp-keepalive"); + if (keepalive) { + result->set("tcp-keepalive", keepalive); + } + ConstElementPtr nodelay = getItem(xpath + "/tcp-nodelay"); + if (nodelay) { + result->set("tcp-nodelay", nodelay); + } + ConstElementPtr context = getItem(xpath + "/user-context"); + if (context) { + result->set("user-context", Element::fromJSON(context->stringValue())); + } + return (result); +} + +void +TranslatorDatabase::setDatabase(const string& xpath, + ConstElementPtr elem, + bool skip) { + try { + if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) { + setDatabaseKea(xpath, elem, skip); + } else { + isc_throw(NotImplemented, + "setDatabase not implemented for the model: " << model_); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error setting database access '" << elem->str() + << "' at '" << xpath << "': " << ex.what()); + } +} + +void +TranslatorDatabase::setDatabaseKea(const string& xpath, + ConstElementPtr elem, + bool skip) { + if (!elem) { + delItem(xpath); + return; + } + if (!skip) { + ConstElementPtr type = elem->get("type"); + if (!type) { + isc_throw(BadValue, "setDatabase missing database type"); + } + setItem(xpath + "/database-type", type, SR_STRING_T); + } + ConstElementPtr user = elem->get("user"); + if (user) { + setItem(xpath + "/user", user, SR_STRING_T); + } + ConstElementPtr password = elem->get("password"); + if (password) { + setItem(xpath + "/password", password, SR_STRING_T); + } + ConstElementPtr host = elem->get("host"); + if (host) { + setItem(xpath + "/host", host, SR_STRING_T); + } + ConstElementPtr name = elem->get("name"); + if (name) { + setItem(xpath + "/name", name, SR_STRING_T); + } + ConstElementPtr persist = elem->get("persist"); + if (persist) { + setItem(xpath + "/persist", persist, SR_BOOL_T); + } + ConstElementPtr port = elem->get("port"); + if (port) { + setItem(xpath + "/port", port, SR_UINT16_T); + } + ConstElementPtr lfc_interval = elem->get("lfc-interval"); + if (lfc_interval) { + setItem(xpath + "/lfc-interval", lfc_interval, SR_UINT32_T); + } + ConstElementPtr readonly = elem->get("readonly"); + if (readonly) { + setItem(xpath + "/readonly", readonly, SR_BOOL_T); + } + ConstElementPtr connect_timeout = elem->get("connect-timeout"); + if (connect_timeout) { + setItem(xpath + "/connect-timeout", connect_timeout, SR_UINT32_T); + } + ConstElementPtr contact_points = elem->get("contact-points"); + if (contact_points) { + setItem(xpath + "/contact-points", contact_points, SR_STRING_T); + } + ConstElementPtr keyspace = elem->get("keyspace"); + if (keyspace) { + setItem(xpath + "/keyspace", keyspace, SR_STRING_T); + } + ConstElementPtr max_reconnect = elem->get("max-reconnect-tries"); + if (max_reconnect) { + setItem(xpath + "/max-reconnect-tries", max_reconnect, SR_UINT32_T); + } + ConstElementPtr reconnect_wait = elem->get("reconnect-wait-time"); + if (reconnect_wait) { + setItem(xpath + "/reconnect-wait-time", reconnect_wait, SR_UINT32_T); + } + ConstElementPtr request_timeout = elem->get("request-timeout"); + if (request_timeout) { + setItem(xpath + "/request-timeout", request_timeout, SR_UINT32_T); + } + ConstElementPtr keepalive = elem->get("tcp-keepalive"); + if (keepalive) { + setItem(xpath + "/tcp-keepalive", keepalive, SR_UINT32_T); + } + ConstElementPtr nodelay = elem->get("tcp-nodelay"); + if (nodelay) { + setItem(xpath + "/tcp-nodelay", nodelay, SR_BOOL_T); + } + ConstElementPtr context = Adaptor::getContext(elem); + if (context) { + setItem(xpath + "/user-context", Element::create(context->str()), + SR_STRING_T); + } +} + +TranslatorDatabases::TranslatorDatabases(S_Session session, + const string& model) + : TranslatorBasic(session), + TranslatorDatabase(session, model), + model_(model) { +} + +TranslatorDatabases::~TranslatorDatabases() { +} + +ConstElementPtr +TranslatorDatabases::getDatabases(const string& xpath) { + try { + if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) { + return (getDatabasesKea(xpath)); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error getting database accesses at '" << xpath + << "': " << ex.what()); + } + isc_throw(NotImplemented, + "getDatabases not implemented for the model: " << model_); +} + +ElementPtr +TranslatorDatabases::getDatabasesKea(const string& xpath) { + S_Iter_Value iter = getIter(xpath + "/*"); + if (!iter) { + return (ElementPtr()); + } + ElementPtr result = Element::createList(); + for (;;) { + const string& database = getNext(iter); + if (database.empty()) { + break; + } + result->add(getDatabase(database)); + } + if (result->size() > 0) { + return (result); + } else { + return (ElementPtr()); + } +} + +void +TranslatorDatabases::setDatabases(const string& xpath, ConstElementPtr elem) { + try { + if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) { + setDatabasesKea(xpath, elem); + } else { + isc_throw(NotImplemented, + "setDatabases not implemented for the model: " + << model_); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error setting database accesses '" << elem->str() + << "' at '" << xpath << "': " << ex.what()); + } +} + +void +TranslatorDatabases::setDatabasesKea(const string& xpath, + ConstElementPtr elem) { + if (!elem) { + delItem(xpath + "/hosts-database"); + delItem(xpath); + return; + } + for (size_t i = 0; i < elem->size(); ++i) { + ConstElementPtr database = elem->get(i); + if (!database->contains("type")) { + isc_throw(BadValue, "database without type: " << database->str()); + } + string type = database->get("type")->stringValue(); + ostringstream key; + key << xpath << "/hosts-database[database-type='" << type << "']"; + setDatabase(key.str(), database, true); + } +} + +}; // end of namespace isc::yang +}; // end of namespace isc diff --git a/src/lib/yang/translator_database.h b/src/lib/yang/translator_database.h new file mode 100644 index 0000000000..7caaf814c6 --- /dev/null +++ b/src/lib/yang/translator_database.h @@ -0,0 +1,166 @@ +// 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_DATABASE_H +#define ISC_TRANSLATOR_DATABASE_H 1 + +#include +#include + +namespace isc { +namespace yang { + +// @brief Between Yang and JSON translator class for a database access. +class TranslatorDatabase : virtual public TranslatorBasic { +public: + + /// @brief Constructor. + /// + /// @param session Sysrepo session. + /// @param model Model name. + TranslatorDatabase(S_Session session, const std::string& model); + + /// @brief Destructor. + virtual ~TranslatorDatabase(); + + /// @brief Get and translate a database access from Yang to JSON. + /// + /// JSON syntax for all Kea servers with database access is: + /// @code + /// { + /// "type": , // required + /// "user": , + /// "password": , + /// "host": , + /// "name": , + /// "persist": , + /// "port": , + /// "lfc-interval": , + /// "readonly": , + /// "connect-timeout": , + /// "contact-points": , + /// "keyspace": , + /// "max-reconnect-tries": , + /// "reconnect-wait-time": , + /// "request-timeout": , + /// "tcp-keepalive": , + /// "tcp-nodelay": , + /// "user-context": { }, + /// "comment": + /// } + /// @endcode + /// + /// @param xpath The xpath of the database. + /// @return JSON representation of the database. + /// @throw SysrepoError when sysrepo raises an error. + isc::data::ElementPtr getDatabase(const std::string& xpath); + + /// @brief Translate and set database access from JSON to Yang. + /// + /// @param xpath The xpath of the database access. + /// @param elem The JSON element. + /// @param skip The skip type field flag. + void setDatabase(const std::string& xpath, + isc::data::ConstElementPtr elem, + bool skip = false); + +protected: + /// @brief getDatabase JSON for kea-dhcp[46]. + /// + /// @param xpath The xpath of the database. + /// @return JSON representation of the database. + /// @throw SysrepoError when sysrepo raises an error. + isc::data::ElementPtr getDatabaseKea(const std::string& xpath); + + /// @brief setDatabase for kea-dhcp[46]. + /// + /// Yang syntax for kea-dhcp[46] is: + /// @code + /// +--rw database container + /// | + /// +--rw datanase=type? string + /// +--rw user? string + /// +--rw password? string + /// +--rw host? string + /// +--rw name? string + /// +--rw persist? boolean + /// +--rw port? uint16 + /// +--rw lfc-interval? uint32 + /// +--rw readonly? boolean + /// +--rw connect-timeout? uint32 + /// +--rw contact-points? string + /// +--rw keyspace? string + /// +--rw max-reconnect-tries? uint32 + /// +--rw reconnect-wait-time? uint32 + /// +--rw request-timeout? uint32 + /// +--rw tcp-keepalive? uint32 + /// +--rw tcp-nodelay? boolean + /// +--rw user-context? string + /// @endcode + /// + /// @param xpath The xpath of the database access. + /// @param elem The JSON element. + /// @param skip The skip type field flag. + void setDatabaseKea(const std::string& xpath, + isc::data::ConstElementPtr elem, + bool skip); + + /// @brief The model. + std::string model_; +}; + +// @brief Between Yang and JSON translator class for database accesses. +class TranslatorDatabases : virtual public TranslatorDatabase { +public: + + /// @brief Constructor. + /// + /// @param session Sysrepo session. + /// @param model Model name. + TranslatorDatabases(S_Session session, const std::string& model); + + /// @brief Destructor. + virtual ~TranslatorDatabases(); + + /// @brief Get and translate database accesses from Yang to JSON. + /// + /// @param xpath The xpath of databases. + /// @return JSON representation of databases. + /// @throw SysrepoError when sysrepo raises an error. + isc::data::ConstElementPtr getDatabases(const std::string& xpath); + + /// @brief Translate and set database accesses from JSON to Yang. + /// + /// @param xpath The xpath of databases. + /// @param elem The JSON element. + void setDatabases(const std::string& xpath, + isc::data::ConstElementPtr elem); + +protected: + /// @brief getDatabases JSON for kea-dhcp[46]. + /// + /// @param xpath The xpath of databases. + /// @return JSON representation of databases. + /// @throw SysrepoError when sysrepo raises an error. + isc::data::ElementPtr getDatabasesKea(const std::string& xpath); + + /// @brief setDatabases for kea-dhcp[46]. + /// + /// Key is the database-type. + /// + /// @param xpath The xpath of databases. + /// @param elem The JSON element. + void setDatabasesKea(const std::string& xpath, + isc::data::ConstElementPtr elem); + + /// @brief The model. + std::string model_; +}; + +}; // end of namespace isc::yang +}; // end of namespace isc + +#endif // ISC_TRANSLATOR_DATABASE_H