27 using namespace libyang;
28 using namespace sysrepo;
33 class NetconfAgentCallback {
39 : service_pair_(service_pair) {
55 sysrepo::ErrorCode module_change(Session sess,
57 string_view module_name,
58 optional<string_view> ,
61 ostringstream event_type;
66 event_type <<
"Event::Update";
69 event_type <<
"Event::Change";
72 event_type <<
"Event::Done";
75 event_type <<
"Event::Abort";
78 event_type <<
"Event::Enabled";
81 event_type <<
"Event::RPC";
84 event_type <<
"UNKNOWN (" <<
event <<
")";
88 .arg(event_type.str());
89 NetconfAgent::logChanges(sess, module_name);
92 return (NetconfAgent::change(sess, service_pair_));
94 return (NetconfAgent::done(sess, service_pair_));
96 return (sysrepo::ErrorCode::Ok);
100 void event_notif(Session ,
102 NotificationType
const notification_type,
103 optional<DataNode>
const notification_tree,
104 NotificationTimeStamp
const ) {
106 switch (notification_type) {
107 case NotificationType::Realtime:
108 n =
"NotificationType::Realtime";
110 case NotificationType::Replay:
111 n =
"NotificationType::Replay";
113 case NotificationType::ReplayComplete:
114 n =
"NotificationType::ReplayComplete";
116 case NotificationType::Terminated:
117 n =
"NotificationType::Terminated";
119 case NotificationType::Modified:
120 n =
"NotificationType::Modified";
122 case NotificationType::Suspended:
123 n =
"NotificationType::Suspended";
125 case NotificationType::Resumed:
126 n =
"NotificationType::Resumed";
130 optional<string>
const str(
131 notification_tree->printStr(DataFormat::JSON, PrintFlags::WithDefaultsExplicit));
132 string const tree(str ? *str :
string());
135 .arg(service_pair_.first)
145 NetconfAgent::~NetconfAgent() {
159 cfg_mgr->getNetconfConfig()->getCfgServersMap();
160 for (
auto const& pair : *servers) {
168 checkModules(servers);
170 for (
auto const& pair : *servers) {
172 subscribeToDataChanges(pair);
173 subscribeToNotifications(pair);
178 NetconfAgent::clear() {
179 subscriptions_.clear();
180 running_sess_.reset();
181 startup_sess_.reset();
186 string const& server(service_pair.first);
190 if (!configuration->getBootUpdate()) {
200 }
catch (exception
const& ex) {
202 msg <<
"createControlSocket failed with " << ex.what();
214 answer = comm->configGet(server);
216 }
catch (exception
const& ex) {
218 msg <<
"config-get command failed with " << ex.what();
226 msg <<
"config-get command returned " <<
answerToText(answer);
235 .arg(
"config-get command returned an empty configuration");
245 NetconfAgent::initSysrepo() {
247 running_sess_ = Connection{}.sessionStart();
248 running_sess_->switchDatastore(Datastore::Running);
249 startup_sess_ = Connection{}.sessionStart();
250 startup_sess_->switchDatastore(Datastore::Startup);
251 }
catch (exception
const& ex) {
260 void NetconfAgent::getModules() {
261 vector<Module> modules;
263 Context context(running_sess_->getContext());
264 modules = context.modules();
265 }
catch (Error
const& ex) {
269 for (Module
const& module : modules) {
270 string const name(module.name());
271 if (!module.revision()) {
273 "could not retrieve module revision for module " << name);
275 string const revision(*module.revision());
276 modules_.emplace(name, revision);
281 NetconfAgent::checkModule(
const string& module_name)
const {
282 auto module = modules_.find(module_name);
283 if (module == modules_.end()) {
288 auto modrev = YANG_REVISIONS.find(module_name);
289 if (modrev == YANG_REVISIONS.end()) {
295 if (modrev->second != module->second) {
299 .arg(module->second);
307 bool faulty_model(
false);
309 for (
auto pair : *servers) {
310 if (!checkModule(pair.second->getModel())) {
318 "supported. Check logs for details.");
321 for (
auto modrev : YANG_REVISIONS) {
322 auto module = modules_.find(modrev.first);
323 if (module == modules_.end()) {
328 if (modrev.second != module->second) {
332 .arg(module->second);
339 string const& server(service_pair.first);
344 if (!configuration->getBootUpdate() ||
345 configuration->getModel().empty()) {
364 msg <<
"YANG configuration for "
365 << configuration->getModel()
377 }
catch (exception
const& ex) {
379 msg <<
"get YANG configuration for " << server
380 <<
" failed with " << ex.what();
389 }
catch (exception
const& ex) {
391 msg <<
"control socket creation failed with " << ex.what();
400 answer = comm->configSet(config, server);
402 }
catch (exception
const& ex) {
404 msg <<
"config-set command failed with " << ex.what();
412 msg <<
"config-set command returned " <<
answerToText(answer);
424 string const& server(service_pair.first);
426 string const& model(configuration->getModel());
430 if (!configuration->getSubscribeChanges() || model.empty()) {
436 auto callback = [=](Session session,
437 uint32_t subscription_id,
438 string_view module_name,
439 optional<string_view> sub_xpath,
441 uint32_t request_id) {
442 NetconfAgentCallback agent(service_pair);
443 return agent.module_change(session, subscription_id, module_name, sub_xpath, event, request_id);
446 SubscribeOptions options(SubscribeOptions::Default);
447 if (!configuration->getValidateChanges()) {
448 options = options | SubscribeOptions::DoneOnly;
450 Subscription subscription(
451 running_sess_->onModuleChange(model, callback, nullopt, 0, options));
452 subscriptions_.emplace(server, std::forward<Subscription>(subscription));
453 }
catch (exception
const& ex) {
455 msg <<
"module change subscribe failed with " << ex.what();
456 msg <<
"change subscription for model " << model <<
457 " failed with: " << ex.what();
460 .arg(configuration->getModel())
468 string const& server(service_pair.first);
470 string const& model(configuration->getModel());
474 if (!configuration->getSubscribeNotifications() || model.empty()) {
481 auto callback = [=](Session session,
482 uint32_t subscription_id,
483 NotificationType
const notification_type,
484 optional<DataNode>
const notification_tree,
485 NotificationTimeStamp
const timestamp) {
486 NetconfAgentCallback agent(service_pair);
487 return agent.event_notif(session, subscription_id, notification_type, notification_tree, timestamp);
490 Subscription subscription(running_sess_->onNotification(model, callback));
491 subscriptions_.emplace(server, std::forward<Subscription>(subscription));
492 }
catch (exception
const& ex) {
494 msg <<
"event notification subscription for model " << model <<
495 " failed with: " << ex.what();
498 .arg(configuration->getModel())
506 string const& server(service_pair.first);
512 if (!configuration->getSubscribeChanges() ||
513 !configuration->getValidateChanges() ||
514 configuration->getModel().empty()) {
515 return (sysrepo::ErrorCode::Ok);
519 return (sysrepo::ErrorCode::Ok);
529 msg <<
"YANG configuration for "
530 << configuration->getModel()
535 return (sysrepo::ErrorCode::OperationFailed);
542 }
catch (exception
const& ex) {
544 msg <<
"get YANG configuration for " << server
545 <<
" failed with " << ex.what();
549 return (sysrepo::ErrorCode::ValidationFailed);
554 }
catch (exception
const& ex) {
556 msg <<
"createControlSocket failed with " << ex.what();
560 return (sysrepo::ErrorCode::Ok);
565 answer = comm->configTest(config, server);
567 }
catch (exception
const& ex) {
569 msg <<
"configTest failed with " << ex.what();
573 return (sysrepo::ErrorCode::ValidationFailed);
581 return (sysrepo::ErrorCode::ValidationFailed);
585 return (sysrepo::ErrorCode::Ok);
590 string const& server(service_pair.first);
594 if (!configuration->getSubscribeChanges() ||
595 configuration->getModel().empty()) {
596 return (sysrepo::ErrorCode::Ok);
600 return (sysrepo::ErrorCode::Ok);
615 msg <<
"YANG configuration for "
616 << configuration->getModel()
621 return (sysrepo::ErrorCode::ValidationFailed);
628 }
catch (exception
const& ex) {
630 msg <<
"get YANG configuration for " << server
631 <<
" failed with " << ex.what();
635 return (sysrepo::ErrorCode::ValidationFailed);
643 }
catch (exception
const& ex) {
645 msg <<
"createControlSocket failed with " << ex.what();
649 return (sysrepo::ErrorCode::Ok);
656 answer = comm->configSet(config, server);
658 }
catch (exception
const& ex) {
660 msg <<
"configSet failed with " << ex.what();
664 return (sysrepo::ErrorCode::ValidationFailed);
674 return (sysrepo::ErrorCode::ValidationFailed);
678 return (sysrepo::ErrorCode::Ok);
682 NetconfAgent::logChanges(Session sess, string_view
const& model) {
683 ostringstream stream;
684 stream <<
"/" << model <<
":*//.";
685 string const xpath(stream.str());
686 ChangeCollection
const changes(sess.getChanges(xpath));
687 for (Change
const& change : changes) {
689 switch (change.operation) {
690 case sysrepo::ChangeOperation::Created:
693 case sysrepo::ChangeOperation::Deleted:
696 case sysrepo::ChangeOperation::Modified:
699 case sysrepo::ChangeOperation::Moved:
703 msg <<
"unknown operation (" << change.operation <<
"): ";
705 string const path(change.node.path());
707 SchemaNode
const& schema(change.node.schema());
708 NodeType
const node_type(schema.nodeType());
709 if (node_type == NodeType::Container) {
710 msg <<
" (container)";
711 }
else if (node_type == NodeType::List) {
714 optional<string>
const str(
715 Translator::translateToYang(Translator::translateFromYang(change.node),
716 LeafBaseType::Unknown));
718 msg <<
" = " << *str;
729 NetconfAgent::announceShutdown()
const {
732 boost::dynamic_pointer_cast<NetconfController>(controller)
733 ->getNetconfProcess()
734 ->setShutdownFlag(
true);
738 bool NetconfAgent::shouldShutdown()
const {
739 return boost::dynamic_pointer_cast<NetconfController>(NetconfController::instance())
740 ->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.
DHCP configuration translation between YANG and JSON.
isc::data::ElementPtr getConfig()
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
boost::shared_ptr< Element > ElementPtr
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
isc::log::Logger netconf_logger(NETCONF_LOGGER_NAME)
Base logger for the netconf agent.
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
std::shared_ptr< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.
const isc::log::MessageID NETCONF_CONFIG_CHANGED_DETAIL
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
const isc::log::MessageID NETCONF_SET_CONFIG_FAILED
std::shared_ptr< CfgServer > CfgServerPtr
Defines a pointer for CfgServer instances.
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_STARTED
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG
const isc::log::MessageID NETCONF_MODULE_MISSING_ERR
std::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
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::shared_ptr< ControlSocketBase > ControlSocketBasePtr
Type definition for the pointer to the ControlSocketBase.
const isc::log::MessageID NETCONF_MODULE_MISSING_WARN
const isc::log::MessageID NETCONF_NOT_SUBSCRIBED_TO_NOTIFICATIONS
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
boost::shared_ptr< DControllerBase > DControllerBasePtr
LabeledValue Event
Define an Event.
Defines the logger used by the top-level component of kea-lfc.
Contains declarations for loggers used by the Kea netconf agent.