19#include <boost/algorithm/string.hpp>
28using namespace sysrepo;
30using libyang::S_Context;
31using libyang::S_Module;
36class NetconfAgentCallback {
42 : service_pair_(service_pair) {
58 sr_error_t module_change(S_Session sess,
59 const char* module_name,
63 ostringstream event_type;
68 event_type <<
"SR_EV_UPDATE";
71 event_type <<
"SR_EV_CHANGE";
74 event_type <<
"SR_EV_DONE";
77 event_type <<
"SR_EV_ABORT";
80 event_type <<
"SR_EV_ENABLED";
83 event_type <<
"SR_EV_RPC";
86 event_type <<
"UNKNOWN (" <<
event <<
")";
90 .arg(event_type.str());
91 NetconfAgent::logChanges(sess, module_name);
94 return (NetconfAgent::change(sess, service_pair_));
96 return (NetconfAgent::done(sess, service_pair_));
102 void event_notif(sysrepo::S_Session ,
103 sr_ev_notif_type_t
const notification_type,
105 sysrepo::S_Vals
const vals,
109 switch (notification_type) {
110 case SR_EV_NOTIF_REALTIME:
111 n =
"SR_EV_NOTIF_REALTIME";
113 case SR_EV_NOTIF_REPLAY:
114 n =
"SR_EV_NOTIF_REPLAY";
116 case SR_EV_NOTIF_REPLAY_COMPLETE:
117 n =
"SR_EV_NOTIF_REPLAY_COMPLETE";
119 case SR_EV_NOTIF_STOP:
120 n =
"SR_EV_NOTIF_STOP";
122 case SR_EV_NOTIF_SUSPENDED:
123 n =
"SR_EV_NOTIF_SUSPENDED";
125 case SR_EV_NOTIF_RESUMED:
126 n =
"SR_EV_NOTIF_RESUMED";
131 for (
size_t i(0); i < vals->val_cnt(); ++i) {
135 s << vals->val(i)->to_string();
140 .arg(service_pair_.first)
164 cfg_mgr->getNetconfConfig()->getCfgServersMap();
165 for (
auto const& pair : *servers) {
175 for (
auto const& pair : *servers) {
196 if (!service_pair.second->getBootUpdate()) {
206 }
catch (
const std::exception& ex) {
208 msg <<
"createControlSocket failed with " << ex.what();
210 .arg(service_pair.first)
218 .arg(service_pair.first);
220 answer = comm->configGet(service_pair.first);
222 }
catch (
const std::exception& ex) {
224 msg <<
"config-get command failed with " << ex.what();
226 .arg(service_pair.first)
232 msg <<
"config-get command returned " <<
answerToText(answer);
234 .arg(service_pair.first)
240 .arg(service_pair.first)
241 .arg(
"config-get command returned an empty configuration");
246 .arg(service_pair.first)
253 conn_ = make_shared<Connection>();
254 }
catch (
const std::exception& ex) {
261 }
catch (
const std::exception& ex) {
271 vector<S_Module> modules;
274 modules = context->get_module_iter();
275 }
catch (
const sysrepo_exception& ex) {
279 for (S_Module
const& module : modules) {
280 if (!module->name()) {
283 string const name(module->name());
284 if (!module->rev() || !module->rev()->date()) {
286 "could not retrieve module revision for module " << name);
288 string const revision(module->rev()->date());
295 auto module =
modules_.find(module_name);
301 auto modrev = YANG_REVISIONS.find(module_name);
302 if (modrev == YANG_REVISIONS.end()) {
308 if (modrev->second != module->second) {
312 .arg(module->second);
320 bool faulty_model(
false);
322 for (
auto pair : *servers) {
331 "supported. Check logs for details.");
334 for (
auto modrev : YANG_REVISIONS) {
335 auto module =
modules_.find(modrev.first);
341 if (modrev.second != module->second) {
345 .arg(module->second);
354 if (!service_pair.second->getBootUpdate() ||
355 service_pair.second->getModel().empty()) {
366 .arg(service_pair.first);
374 msg <<
"YANG configuration for "
375 << service_pair.second->getModel()
378 .arg(service_pair.first)
384 .arg(service_pair.first)
387 }
catch (
const std::exception& ex) {
389 msg <<
"get YANG configuration for " << service_pair.first
390 <<
" failed with " << ex.what();
392 .arg(service_pair.first)
399 }
catch (
const std::exception& ex) {
401 msg <<
"control socket creation failed with " << ex.what();
403 .arg(service_pair.first)
410 answer = comm->configSet(config, service_pair.first);
412 }
catch (
const std::exception& ex) {
414 msg <<
"config-set command failed with " << ex.what();
416 .arg(service_pair.first)
422 msg <<
"config-set command returned " <<
answerToText(answer);
424 .arg(service_pair.first)
429 .arg(service_pair.first);
434 std::string
const& model(service_pair.second->getModel());
438 if (!service_pair.second->getSubscribeChanges() ||
443 .arg(service_pair.first)
446 auto callback = [=](sysrepo::S_Session sess,
const char* module_name,
447 const char* xpath, sr_event_t event,
449 NetconfAgentCallback agent(service_pair);
450 return agent.module_change(sess, module_name, xpath, event,
nullptr);
453 sr_subscr_options_t options = SR_SUBSCR_DEFAULT;
454 if (!service_pair.second->getValidateChanges()) {
455 options |= SR_SUBSCR_DONE_ONLY;
459 subs->module_change_subscribe(model.c_str(), callback,
nullptr, 0,
461 }
catch (
const std::exception& ex) {
463 msg <<
"module change subscribe failed with " << ex.what();
464 msg <<
"change subscription for model " << model <<
465 " failed with: " << ex.what();
467 .arg(service_pair.first)
468 .arg(service_pair.second->getModel())
478 std::string
const& model(service_pair.second->getModel());
481 if (!service_pair.second->getSubscribeNotifications() ||
486 .arg(service_pair.first)
489 S_Subscribe subscription(std::make_shared<Subscribe>(
running_sess_));
490 auto callback = [=](sysrepo::S_Session session,
491 sr_ev_notif_type_t
const notification_type,
493 sysrepo::S_Vals
const vals,
495 NetconfAgentCallback agent(service_pair);
496 return agent.event_notif(session, notification_type, path, vals, timestamp,
nullptr);
499 subscription->event_notif_subscribe(model.c_str(), callback);
500 }
catch (
const std::exception& ex) {
502 msg <<
"event notification subscription for model " << model <<
503 " failed with: " << ex.what();
505 .arg(service_pair.first)
506 .arg(service_pair.second->getModel())
518 if (!service_pair.second->getSubscribeChanges() ||
519 !service_pair.second->getValidateChanges() ||
520 service_pair.second->getModel().empty()) {
528 .arg(service_pair.first);
535 msg <<
"YANG configuration for "
536 << service_pair.second->getModel()
539 .arg(service_pair.first)
541 return (SR_ERR_OPERATION_FAILED);
545 .arg(service_pair.first)
548 }
catch (
const std::exception& ex) {
550 msg <<
"get YANG configuration for " << service_pair.first
551 <<
" failed with " << ex.what();
553 .arg(service_pair.first)
555 return (SR_ERR_VALIDATION_FAILED);;
560 }
catch (
const std::exception& ex) {
562 msg <<
"createControlSocket failed with " << ex.what();
564 .arg(service_pair.first)
571 answer = comm->configTest(config, service_pair.first);
573 }
catch (
const std::exception& ex) {
575 msg <<
"configTest failed with " << ex.what();
577 .arg(service_pair.first)
579 return (SR_ERR_VALIDATION_FAILED);
585 .arg(service_pair.first)
587 return (SR_ERR_VALIDATION_FAILED);
590 .arg(service_pair.first);
597 if (!service_pair.second->getSubscribeChanges() ||
598 service_pair.second->getModel().empty()) {
609 .arg(service_pair.first);
618 msg <<
"YANG configuration for "
619 << service_pair.second->getModel()
622 .arg(service_pair.first)
624 return (SR_ERR_VALIDATION_FAILED);
628 .arg(service_pair.first)
631 }
catch (
const std::exception& ex) {
633 msg <<
"get YANG configuration for " << service_pair.first
634 <<
" failed with " << ex.what();
636 .arg(service_pair.first)
638 return (SR_ERR_VALIDATION_FAILED);
646 }
catch (
const std::exception& ex) {
648 msg <<
"createControlSocket failed with " << ex.what();
650 .arg(service_pair.first)
659 answer = comm->configSet(config, service_pair.first);
661 }
catch (
const std::exception& ex) {
663 msg <<
"configSet failed with " << ex.what();
665 .arg(service_pair.first)
667 return (SR_ERR_VALIDATION_FAILED);
675 .arg(service_pair.first)
677 return (SR_ERR_VALIDATION_FAILED);
680 .arg(service_pair.first);
686 ostringstream stream;
687 stream <<
"/" << model <<
":*//.";
688 std::string
const xpath(stream.str());
689 S_Iter_Change iter = sess->get_changes_iter(xpath.c_str());
699 change = sess->get_change_next(iter);
700 }
catch (
const sysrepo_exception& ex) {
701 msg <<
"get change iterator next failed: " << ex.what();
710 S_Val new_val =
change->new_val();
711 S_Val old_val =
change->old_val();
717 .arg(
"created but without a new value");
720 msg <<
"created: " << new_val->to_string();
722 boost::erase_all(report,
"\n");
728 if (!old_val || !new_val) {
730 .arg(
"modified but without an old or new value");
733 msg <<
"modified: " << old_val->to_string()
734 <<
" => " << new_val->to_string();
736 boost::erase_all(report,
"\n");
744 .arg(
"deleted but without an old value");
747 msg <<
"deleted: " << old_val->to_string();
749 boost::erase_all(report,
"\n");
757 .arg(
"moved but without a new value");
760 msg <<
"moved: " << new_val->xpath();
764 msg <<
" after " << old_val->xpath();
767 boost::erase_all(report,
"\n");
773 msg <<
"unknown operation (" <<
change->oper() <<
")";
784 boost::dynamic_pointer_cast<NetconfController>(controller)
785 ->getNetconfProcess()
786 ->setShutdownFlag(
true);
792 ->getNetconfProcess()
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
void getModules()
Retrieve names and revisions of installed modules through the sysrepo API.
sysrepo::S_Session running_sess_
Sysrepo running datastore session.
sysrepo::S_Session startup_sess_
Sysrepo startup datastore session.
void yangConfig(const CfgServersMapPair &service_pair)
Retrieve Kea server configuration from the YANG startup datastore and applies it to servers.
virtual ~NetconfAgent()
Destructor (call clear).
static sr_error_t done(sysrepo::S_Session sess, const CfgServersMapPair &service_pair)
SR_EV_DONE callback.
void subscribeConfig(const CfgServersMapPair &service_pair)
Subscribe changes for a module in YANG datastore.
void initSysrepo()
Initialize sysrepo sessions.
std::map< const std::string, sysrepo::S_Subscribe > subscriptions_
Subscription map.
void keaConfig(const CfgServersMapPair &service_pair)
Get and display Kea server configuration.
static sr_error_t change(sysrepo::S_Session sess, const CfgServersMapPair &service_pair)
SR_EV_CHANGE callback.
void announceShutdown() const
Set the shutdown flag of the process to true so that it can exit at the earliest convenient time.
sysrepo::S_Connection conn_
Sysrepo connection.
static void logChanges(sysrepo::S_Session sess, const std::string &model)
Log changes.
void checkModules(CfgServersMapPtr const &servers={}) const
Check module availability.
bool shouldShutdown() const
Check the shutdown flag of the process.
void init(NetconfCfgMgrPtr cfg_mgr)
Initialization.
void subscribeToNotifications(const CfgServersMapPair &service_pair)
Subscribe to notifications for a given YANG module.
bool checkModule(const std::string &module_name) const
Check essential module availability.
std::map< const std::string, const std::string > modules_
Available modules and revisions in Sysrepo.
static process::DControllerBasePtr & instance()
Static singleton instance method.
DHCP configuration translation between YANG and JSON.
isc::data::ElementPtr getConfig()
Get and translate the whole DHCP server configuration from YANG to JSON.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
std::string answerToText(const ConstElementPtr &msg)
void prettyPrint(ConstElementPtr element, std::ostream &out, unsigned indent, unsigned step)
Pretty prints the data into stream.
boost::shared_ptr< const Element > ConstElementPtr
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_FAILED
const int NETCONF_DBG_TRACE_DETAIL_DATA
Additional information.
const isc::log::MessageID NETCONF_GET_CONFIG_STARTED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_REJECTED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_CONFIG_CHANGE_EVENT
const isc::log::MessageID NETCONF_SUBSCRIBE_NOTIFICATIONS_FAILED
isc::log::Logger netconf_logger(NETCONF_LOGGER_NAME)
Base logger for the netconf agent.
boost::shared_ptr< ControlSocketBase > ControlSocketBasePtr
Type definition for the pointer to the ControlSocketBase.
const isc::log::MessageID NETCONF_VALIDATE_CONFIG
const isc::log::MessageID NETCONF_GET_CONFIG_FAILED
const isc::log::MessageID NETCONF_MODULE_REVISION_WARN
const isc::log::MessageID NETCONF_GET_CONFIG
const isc::log::MessageID NETCONF_LOG_CHANGE_FAIL
boost::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
const isc::log::MessageID NETCONF_CONFIG_CHANGED_DETAIL
const isc::log::MessageID NETCONF_SET_CONFIG_FAILED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_STARTED
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG
boost::shared_ptr< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.
const isc::log::MessageID NETCONF_MODULE_MISSING_ERR
const isc::log::MessageID NETCONF_NOTIFICATION_RECEIVED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_MODULE_REVISION_ERR
const isc::log::MessageID NETCONF_SUBSCRIBE_NOTIFICATIONS
const isc::log::MessageID NETCONF_SET_CONFIG_STARTED
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG_FAILED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_BOOT_UPDATE_COMPLETED
const isc::log::MessageID NETCONF_SET_CONFIG
const isc::log::MessageID NETCONF_UPDATE_CONFIG
const isc::log::MessageID NETCONF_UPDATE_CONFIG_STARTED
ControlSocketBasePtr controlSocketFactory(CfgControlSocketPtr ctrl_sock)
Factory function for control sockets.
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
const isc::log::MessageID NETCONF_MODULE_MISSING_WARN
boost::shared_ptr< DControllerBase > DControllerBasePtr
Defines the logger used by the top-level component of kea-lfc.
Contains declarations for loggers used by the Kea netconf agent.