18#include <boost/algorithm/string.hpp>
26#ifndef HAVE_PRE_0_7_6_SYSREPO
27using namespace sysrepo;
33class NetconfAgentCallback :
public Callback {
39 : service_pair_(service_pair) {
55 int module_change(S_Session sess,
57 sr_notif_event_t event,
60 return (SR_ERR_DISCONNECT);
62 ostringstream event_type;
65 event_type <<
"VERIFY";
68 event_type <<
"APPLY";
71 event_type <<
"ABORT";
74 event_type <<
"ENABLED";
77 event_type <<
"UNKNOWN (" <<
event <<
")";
81 .arg(event_type.str());
82 string xpath =
"/" + service_pair_.second->getModel() +
":";
85 return (SR_ERR_DISCONNECT);
99class NetconfAgentInstallCallback :
public Callback {
109 void module_install(
const char* module_name,
110 const char* revision,
119 .arg(revision ? revision :
"unknown");
142 cfg_mgr->getNetconfConfig()->getCfgServersMap();
143 for (
auto pair : *servers) {
165 bool can_start =
true;
166 for (
auto pair : *servers) {
167 can_start = can_start &&
checkModule(pair.second->getModel());
173 cerr <<
"An essential YANG module / revision is missing."
175 <<
"The environment is not suitable for running kea-netconf."
189 for (
auto pair : *servers) {
220 if (!service_pair.second->getBootUpdate()) {
230 }
catch (
const std::exception& ex) {
232 msg <<
"createControlSocket failed with " << ex.what();
234 .arg(service_pair.first)
242 .arg(service_pair.first);
244 answer = comm->configGet(service_pair.first);
246 }
catch (
const std::exception& ex) {
248 msg <<
"config-get command failed with " << ex.what();
250 .arg(service_pair.first)
259 msg <<
"config-get command returned " <<
answerToText(answer);
261 .arg(service_pair.first)
267 .arg(service_pair.first)
268 .arg(
"config-get command returned an empty configuration");
273 .arg(service_pair.first)
281 SR_CONN_DAEMON_REQUIRED));
282 }
catch (
const std::exception& ex) {
295 }
catch (
const std::exception& ex) {
305 for (
size_t i = 0; i < schemas->schema_cnt(); ++i) {
309 if (!schemas->schema(i) ||
310 !schemas->schema(i)->module_name()) {
314 string module = schemas->schema(i)->module_name();
315 if (!schemas->schema(i)->revision() ||
316 !schemas->schema(i)->revision()->revision()) {
320 string revision = schemas->schema(i)->revision()->revision();
321 modules_.insert(make_pair(module, revision));
323 }
catch (
const sysrepo_exception& ex) {
335 S_Callback cb(
new NetconfAgentInstallCallback());
336 subs->module_install_subscribe(cb);
338 }
catch (
const sysrepo_exception& ex) {
346 if (module_name.empty()) {
349 auto module =
modules_.find(module_name);
355 auto modrev = YANG_REVISIONS.find(module_name);
356 if (modrev == YANG_REVISIONS.end()) {
362 if (modrev->second != module->second) {
366 .arg(module->second);
374 for (
auto modrev : YANG_REVISIONS) {
378 auto module =
modules_.find(modrev.first);
384 if (modrev.second != module->second) {
388 .arg(module->second);
398 !service_pair.second->getBootUpdate() ||
399 service_pair.second->getModel().empty()) {
410 .arg(service_pair.first);
418 msg <<
"YANG configuration for "
419 << service_pair.second->getModel()
422 .arg(service_pair.first)
428 .arg(service_pair.first)
431 }
catch (
const std::exception& ex) {
433 msg <<
"get YANG configuration for " << service_pair.first
434 <<
" failed with " << ex.what();
436 .arg(service_pair.first)
446 }
catch (
const std::exception& ex) {
448 msg <<
"control socket creation failed with " << ex.what();
450 .arg(service_pair.first)
460 answer = comm->configSet(config, service_pair.first);
462 }
catch (
const std::exception& ex) {
464 msg <<
"config-set command failed with " << ex.what();
466 .arg(service_pair.first)
472 msg <<
"config-set command returned " <<
answerToText(answer);
474 .arg(service_pair.first)
479 .arg(service_pair.first);
487 !service_pair.second->getSubscribeChanges() ||
488 service_pair.second->getModel().empty()) {
492 .arg(service_pair.first)
493 .arg(service_pair.second->getModel());
495 S_Callback cb(
new NetconfAgentCallback(service_pair));
497 sr_subscr_options_t options = SR_SUBSCR_DEFAULT;
498 if (!service_pair.second->getValidateChanges()) {
499 options |= SR_SUBSCR_APPLY_ONLY;
503 subs->module_change_subscribe(service_pair.second->getModel().c_str(),
505 }
catch (
const std::exception& ex) {
507 msg <<
"module change subscribe failed with " << ex.what();
509 .arg(service_pair.first)
510 .arg(service_pair.second->getModel())
524 !service_pair.second->getSubscribeChanges() ||
525 !service_pair.second->getValidateChanges() ||
526 service_pair.second->getModel().empty()) {
534 .arg(service_pair.first);
541 msg <<
"YANG configuration for "
542 << service_pair.second->getModel()
545 .arg(service_pair.first)
547 return (SR_ERR_DISCONNECT);
550 NETCONF_VALIDATE_CONFIG)
551 .arg(service_pair.first)
554 }
catch (
const std::exception& ex) {
556 msg <<
"get YANG configuration for " << service_pair.first
557 <<
" failed with " << ex.what();
559 .arg(service_pair.first)
561 return (SR_ERR_VALIDATION_FAILED);;
564 return (SR_ERR_DISCONNECT);
569 }
catch (
const std::exception& ex) {
571 msg <<
"createControlSocket failed with " << ex.what();
573 .arg(service_pair.first)
580 answer = comm->configTest(config, service_pair.first);
582 }
catch (
const std::exception& ex) {
584 msg <<
"configTest failed with " << ex.what();
586 .arg(service_pair.first)
588 return (SR_ERR_VALIDATION_FAILED);
594 .arg(service_pair.first)
596 return (SR_ERR_VALIDATION_FAILED);
599 .arg(service_pair.first);
607 !service_pair.second->getSubscribeChanges() ||
608 service_pair.second->getModel().empty()) {
619 .arg(service_pair.first);
628 msg <<
"YANG configuration for "
629 << service_pair.second->getModel()
632 .arg(service_pair.first)
634 return (SR_ERR_VALIDATION_FAILED);
637 NETCONF_UPDATE_CONFIG)
638 .arg(service_pair.first)
641 }
catch (
const std::exception& ex) {
643 msg <<
"get YANG configuration for " << service_pair.first
644 <<
" failed with " << ex.what();
646 .arg(service_pair.first)
648 return (SR_ERR_VALIDATION_FAILED);
659 }
catch (
const std::exception& ex) {
661 msg <<
"createControlSocket failed with " << ex.what();
663 .arg(service_pair.first)
672 answer = comm->configSet(config, service_pair.first);
674 }
catch (
const std::exception& ex) {
676 msg <<
"configSet failed with " << ex.what();
678 .arg(service_pair.first)
680 return (SR_ERR_VALIDATION_FAILED);
688 .arg(service_pair.first)
690 return (SR_ERR_VALIDATION_FAILED);
693 .arg(service_pair.first);
702 S_Iter_Change iter = sess->get_changes_iter(model.c_str());
715 change = sess->get_change_next(iter);
716 }
catch (
const sysrepo_exception& ex) {
717 msg <<
"get change iterator next failed: " << ex.what();
729 S_Val new_val = change->new_val();
730 S_Val old_val = change->old_val();
732 switch (change->oper()) {
736 .arg(
"created but without a new value");
739 msg <<
"created: " << new_val->to_string();
741 boost::erase_all(report,
"\n");
743 NETCONF_CONFIG_CHANGED_DETAIL)
747 if (!old_val || !new_val) {
749 .arg(
"modified but without an old or new value");
752 msg <<
"modified: " << old_val->to_string()
753 <<
" => " << new_val->to_string();
755 boost::erase_all(report,
"\n");
757 NETCONF_CONFIG_CHANGED_DETAIL)
763 .arg(
"deleted but without an old value");
766 msg <<
"deleted: " << old_val->to_string();
768 boost::erase_all(report,
"\n");
770 NETCONF_CONFIG_CHANGED_DETAIL)
776 .arg(
"moved but without a new value");
779 msg <<
"moved: " << new_val->xpath();
783 msg <<
" after " << old_val->xpath();
786 boost::erase_all(report,
"\n");
788 NETCONF_CONFIG_CHANGED_DETAIL)
792 msg <<
"unknown operation (" << change->oper() <<
")";
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.
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).
void subscribeConfig(const CfgServersMapPair &service_pair)
Subscribe changes for a module in YANG datastore.
static int validate(sysrepo::S_Session sess, const CfgServersMapPair &service_pair)
Validate.
NetconfAgent()
Constructor.
void checkModules() const
Check module availability.
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.
sysrepo::S_Connection conn_
Sysrepo connection.
static void logChanges(sysrepo::S_Session sess, const std::string &model)
Log changes.
static int update(sysrepo::S_Session sess, const CfgServersMapPair &service_pair)
Update.
void init(NetconfCfgMgrPtr cfg_mgr)
Initialization.
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 const char * netconf_app_name_
Defines the application name, this is passed into base class and appears in log statements.
static bool shut_down
Global (globally visible) shutdown flag.
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 int NETCONF_DBG_TRACE_DETAIL_DATA
Additional information.
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.
ControlSocketBasePtr createControlSocket(CfgControlSocketPtr ctrl_sock)
Factory function for control sockets.
boost::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
boost::shared_ptr< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
Defines the logger used by the top-level component of kea-dhcp-ddns.
Contains declarations for loggers used by the Kea netconf agent.