From: Francis Dupont Date: Wed, 21 Nov 2018 15:48:20 +0000 (+0100) Subject: [204-move-models-] Code done, tests to do X-Git-Tag: 339-doxygen-errors_base~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=66da4b915ac4aaa6ddca22f833d1cbc7f356bb12;p=thirdparty%2Fkea.git [204-move-models-] Code done, tests to do --- diff --git a/src/bin/netconf/netconf.cc b/src/bin/netconf/netconf.cc index abdcbc0802..c0c92dd436 100644 --- a/src/bin/netconf/netconf.cc +++ b/src/bin/netconf/netconf.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,7 @@ using namespace sysrepo; namespace { -/// @brief Subscription callback. +/// @brief Module change subscription callback. class NetconfAgentCallback : public Callback { public: /// @brief Constructor. @@ -94,6 +95,31 @@ public: } }; +/// @brief Module (un)installation subscription callback. +class NetconfAgentInstallCallback : public Callback { +public: + /// @brief Module (un)installation callback. + /// + /// This callback is called by sysrepo when a module is (un)installed. + /// + /// @param module_name The module name. + /// @param revision The module revision. + /// @param state The new state of the module (ignored). + /// @param private_ctx The private context. + void module_install(const char* module_name, + const char* revision, + sr_module_state_t /*state*/, + void* /*private_ctx*/) { + if (!module_name || !revision) { + // Not for us... + return; + } + LOG_WARN(netconf_logger, NETCONF_MODULE_INSTALL) + .arg(module_name) + .arg(revision); + } +}; + } // end of anonymous namespace namespace isc { @@ -135,6 +161,31 @@ NetconfAgent::init(NetconfCfgMgrPtr cfg_mgr) { return; } + // Check essential modules / revisions. + bool can_start = true; + for (auto pair : *servers) { + can_start = can_start && checkModule(pair.second->getModel()); + if (NetconfProcess::shut_down) { + return; + } + } + if (!can_start) { + cerr << "An essential YNAG module / revision is missing." + << endl + << "The environment is not suitable for running kea-netconf." + << endl; + exit(EXIT_FAILURE); + } + if (NetconfProcess::shut_down) { + return; + } + + // Check modules / revisions. + checkModules(); + if (NetconfProcess::shut_down) { + return; + } + for (auto pair : *servers) { if (NetconfProcess::shut_down) { return; @@ -231,14 +282,107 @@ NetconfAgent::initSysrepo() { } catch (const std::exception& ex) { isc_throw(Unexpected, "Can't connect to sysrepo: " << ex.what()); } + if (NetconfProcess::shut_down) { + return; + } try { startup_sess_.reset(new Session(conn_, SR_DS_STARTUP)); + if (NetconfProcess::shut_down) { + return; + } running_sess_.reset(new Session(conn_, SR_DS_RUNNING)); } catch (const std::exception& ex) { isc_throw(Unexpected, "Can't establish a sysrepo session: " << ex.what()); } + if (NetconfProcess::shut_down) { + return; + } + + try { + S_Yang_Schemas schemas = startup_sess_->list_schemas(); + for (size_t i = 0; i < schemas->schema_cnt(); ++i) { + if (NetconfProcess::shut_down) { + return; + } + if (!schemas->schema(i) || + !schemas->schema(i)->module_name()) { + // Should not happen: skip it. + continue; + } + string module = schemas->schema(i)->module_name(); + if (!schemas->schema(i)->revision() || + !schemas->schema(i)->revision()->revision()) { + // Our modules have revisions: skip it. + continue; + } + string revision = schemas->schema(i)->revision()->revision(); + modules_.insert(make_pair(module, revision)); + } + } catch (const sysrepo_exception& ex) { + isc_throw(Unexpected, "Can't list schemas: " << ex.what()); + } + if (NetconfProcess::shut_down) { + return; + } + + try { + S_Subscribe subs(new Subscribe(startup_sess_)); + S_Callback cb(new NetconfAgentInstallCallback()); + subs->module_install_subscribe(cb); + subscriptions_.insert(make_pair("__install__", subs)); + } catch (const sysrepo_exception& ex) { + isc_throw(Unexpected, "Can't subscribe moduel install: " + << ex.what()); + } +} + +bool +NetconfAgent::checkModule(const string& module_name) const { + if (module_name.empty()) { + return (true); + } + auto module = modules_.find(module_name); + if (module == modules_.end()) { + LOG_ERROR(netconf_logger, METCONF_MODULE_MISSING_ERR) + .arg(module_name); + return (false); + } + auto modrev = YANG_REVISIONS.find(module_name); + if (modrev == YANG_REVISIONS.end()) { + // Can't check revision?! + return (true); + } + if (modrev->second != module->second) { + LOG_ERROR(netconf_logger, METCONF_MODULE_REVISION_ERR) + .arg(module_name) + .arg(modrev->second) + .arg(module->second); + return (false); + } + return (true); +} + +void +NetconfAgent::checkModules() const { + for (auto modrev : YANG_REVISIONS) { + if (NetconfProcess::shut_down) { + return; + } + auto module = modules_.find(modrev.first); + if (module == modules_.end()) { + LOG_WARN(netconf_logger, METCONF_MODULE_MISSING_WARN) + .arg(modrev.first); + continue; + } + if (modrev.second != module->second) { + LOG_WARN(netconf_logger, METCONF_MODULE_REVISION_WARN) + .arg(modrev.first) + .arg(modrev.second) + .arg(module->second); + } + } } void diff --git a/src/bin/netconf/netconf.h b/src/bin/netconf/netconf.h index cd02c6c893..bc5d964607 100644 --- a/src/bin/netconf/netconf.h +++ b/src/bin/netconf/netconf.h @@ -52,11 +52,13 @@ public: /// @brief Initialize sysrepo sessions. /// - /// Must be called before init. + /// Must be called before init. Collect the list of available + /// modules with their revisions. void initSysrepo(); /// @brief Initialization. /// + /// Check available modules / revisions. /// Get and display Kea server configurations. /// Load Kea server configurations from YANG datastore. /// Subscribe configuration changes in YANG datastore. @@ -118,6 +120,22 @@ public: bool cancel_; protected: + /// @brief Check essential module availability. + /// + /// Emit a fatal error if an essential one (i.e. required in + /// a further phase) is missing or does not have the expected revision. + /// The caller (init) will exit(). + /// + /// @param module_name The module name. + /// @return true if available, false if not. + bool checkModule(const std::string& module_name) const; + + /// @brief Check module availability. + /// + /// Emit a warning if a module is missing or does not have + /// the expected revision. + void checkModules() const; + /// @brief Get and display Kea server configuration. /// /// Retrieves current configuration via control socket (unix or http) @@ -166,6 +184,9 @@ protected: S_Session running_sess_; #endif + /// @brief Available modules and revisions in Sysrepo. + std::map modules_; + /// @brief Subscription map. #ifndef HAVE_PRE_0_7_6_SYSREPO std::map subscriptions_; diff --git a/src/bin/netconf/netconf_messages.mes b/src/bin/netconf/netconf_messages.mes index 054543086f..c2f6e84d6f 100644 --- a/src/bin/netconf/netconf_messages.mes +++ b/src/bin/netconf/netconf_messages.mes @@ -52,6 +52,30 @@ configuration from a Kea server. The warning message indicates that the configuration change logging encountered an unexpected condition. Details of it will be logged. +% NETCONF_MODULE_INSTALL Sysrepo (un)installs a module: %1 (revision %2) +This warning message indicates that sysrepo reports the installation +or uninstallation of a module used by Kea. The name and revision of +the module are printed. + +% METCONF_MODULE_MISSING_ERR Missing essential module %1 in sysrepo +This fatal error message indicates that a module required by Netconf +configuration is not available in the sysrepo repository. The name of +the module is printed. + +% METCONF_MODULE_MISSING_WARN Missing module %1 in sysrepo +This warning message indicates that a module used by Kea is not +available in the sysrepo repository. The name of the module is printed. + +% METCONF_MODULE_REVISION_ERR Essential module %1 does have the right revision: expected %2, got %3 +This fatal error message indicates that a module required by Netconf +configuration is not at the right revision in the sysrepo repository. +The name, expected and available revisions of the module are printed. + +% METCONF_MODULE_REVISION_WARN Module %1 does have the right revision: expected %2, got %3 +This warning message indicates that a module used by Kea is not at the +right revision in the sysrepo repository. The name, expected and +available revisions of the module are printed. + % NETCONF_RUN_EXIT application is exiting the event loop This is a debug message issued when the Netconf application exits its event loop. This is a normal step during kea-netconf shutdown. diff --git a/src/bin/netconf/tests/netconf_unittests.cc b/src/bin/netconf/tests/netconf_unittests.cc index e70b9430e7..3ecf29eebf 100644 --- a/src/bin/netconf/tests/netconf_unittests.cc +++ b/src/bin/netconf/tests/netconf_unittests.cc @@ -361,6 +361,7 @@ TEST_F(NetconfAgentTest, initSysrepo) { EXPECT_TRUE(agent_->conn_); EXPECT_TRUE(agent_->startup_sess_); EXPECT_TRUE(agent_->running_sess_); + EXPECT_EQ(1, agent_->subscriptions_.size()); } /// @brief Default change callback (print changes and return OK). @@ -771,8 +772,9 @@ TEST_F(NetconfAgentTest, subscribeConfig) { // Try subscribeConfig. EXPECT_EQ(0, agent_->subscriptions_.size()); ASSERT_NO_THROW(agent_->initSysrepo()); - EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); EXPECT_EQ(1, agent_->subscriptions_.size()); + EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); + EXPECT_EQ(2, agent_->subscriptions_.size()); /// Unsubscribe. EXPECT_NO_THROW(agent_->subscriptions_.clear()); @@ -841,9 +843,9 @@ TEST_F(NetconfAgentTest, update) { CfgServersMapPair service_pair = *servers_map->begin(); // Subscribe YANG changes. - EXPECT_EQ(0, agent_->subscriptions_.size()); - EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); EXPECT_EQ(1, agent_->subscriptions_.size()); + EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); + EXPECT_EQ(2, agent_->subscriptions_.size()); // Launch server. thread_.reset(new Thread([this]() { fakeServer(); signalStopped(); })); @@ -973,9 +975,9 @@ TEST_F(NetconfAgentTest, validate) { CfgServersMapPair service_pair = *servers_map->begin(); // Subscribe YANG changes. - EXPECT_EQ(0, agent_->subscriptions_.size()); - EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); EXPECT_EQ(1, agent_->subscriptions_.size()); + EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); + EXPECT_EQ(2, agent_->subscriptions_.size()); // Launch server twice. thread_.reset(new Thread([this]() @@ -1136,9 +1138,9 @@ TEST_F(NetconfAgentTest, noValidate) { CfgServersMapPair service_pair = *servers_map->begin(); // Subscribe YANG changes. - EXPECT_EQ(0, agent_->subscriptions_.size()); - EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); EXPECT_EQ(1, agent_->subscriptions_.size()); + EXPECT_NO_THROW(agent_->subscribeConfig(service_pair)); + EXPECT_EQ(2, agent_->subscriptions_.size()); // Change configuration (add invalid user context). const YRTree tree1 = { diff --git a/src/lib/yang/pretests/sysrepo_setup_tests.cc b/src/lib/yang/pretests/sysrepo_setup_tests.cc index 140966ca3a..6956671464 100644 --- a/src/lib/yang/pretests/sysrepo_setup_tests.cc +++ b/src/lib/yang/pretests/sysrepo_setup_tests.cc @@ -6,6 +6,7 @@ #include +#define KEATEST_MODULE #include #ifndef HAVE_PRE_0_7_6_SYSREPO diff --git a/src/lib/yang/yang_revisions.h b/src/lib/yang/yang_revisions.h index e0f50965e6..d3b7b12065 100644 --- a/src/lib/yang/yang_revisions.h +++ b/src/lib/yang/yang_revisions.h @@ -15,19 +15,19 @@ namespace yang { // Table of module name / revision. static const std::map YANG_REVISIONS = { -// Should be generated automatically. -// cf src/share/yang/modules/README -{ "ietf-dhcpv6-types", "2018-09-04" }, -{ "ietf-dhcpv6-options", "2018-09-04" }, -{ "ietf-dhcpv6-server", "2018-09-04" }, -{ "kea-types", "2018-11-20" }, -{ "kea-logging", "2018-11-20" }, -{ "kea-dhcp-types", "2018-11-20" }, -{ "kea-dhcp4-server", "2018-11-20" }, -{ "kea-dhcp6-server", "2018-11-20" }, -{ "kea-ctrl-agent", "2018-11-20" }, -{ "kea-dhcp-ddns", "2018-11-20" }, -{ "keatest-module", "2018-11-20" } +#ifdef KEATEST_MODULE + { "keatest-module", "2018-11-20" }, +#endif // KEATEST_MODULE + { "ietf-dhcpv6-types", "2018-09-04" }, + { "ietf-dhcpv6-options", "2018-09-04" }, + { "ietf-dhcpv6-server", "2018-09-04" }, + { "kea-types", "2018-11-20" }, + { "kea-logging", "2018-11-20" }, + { "kea-dhcp-types", "2018-11-20" }, + { "kea-dhcp4-server", "2018-11-20" }, + { "kea-dhcp6-server", "2018-11-20" }, + { "kea-ctrl-agent", "2018-11-20" }, + { "kea-dhcp-ddns", "2018-11-20" } }; }; // end of namespace isc::yang diff --git a/src/lib/yang/yang_revisions.h.skel b/src/lib/yang/yang_revisions.h.skel new file mode 100644 index 0000000000..200b0bb422 --- /dev/null +++ b/src/lib/yang/yang_revisions.h.skel @@ -0,0 +1,27 @@ +// 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_YANG_REVISIONS_H +#define ISC_YANG_REVISIONS_H 1 + +#include +#include + +namespace isc { +namespace yang { + +// Table of module name / revision. +static const std::map YANG_REVISIONS = { +// Fill this by: +// cd .../src/share/yang/modules +// sh utils/gen-revisions.sh > r +// insert the r file here +}; + +}; // end of namespace isc::yang +}; // end of namespace isc + +#endif // ISC_YANG_REVISIONS_H diff --git a/src/share/yang/modules/README b/src/share/yang/modules/README deleted file mode 100644 index 590034f97a..0000000000 --- a/src/share/yang/modules/README +++ /dev/null @@ -1,74 +0,0 @@ -Developer tools: - -Get revision from file content: - -yanglint -f yin xxx | grep '