27using namespace libyang;
 
   28using namespace sysrepo;
 
   33class NetconfAgentCallback {
 
   39        : service_pair_(service_pair) {
 
   55    sysrepo::ErrorCode moduleChange(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());
 
   96            return (sysrepo::ErrorCode::Ok);
 
  100    void eventNotif(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";
 
  131        if (notification_tree) {
 
  132            optional<string> 
const str(
 
  133                notification_tree->printStr(DataFormat::JSON, PrintFlags::WithDefaultsExplicit));
 
  140            .arg(service_pair_.first)
 
  164        cfg_mgr->getNetconfConfig()->getCfgServersMap();
 
  165    for (
auto const& pair : *servers) {
 
  175    for (
auto const& pair : *servers) {
 
 
  191    string const& server(service_pair.first);
 
  205    } 
catch (exception 
const& ex) {
 
  207        msg << 
"createControlSocket failed with " << ex.what();
 
  221    } 
catch (exception 
const& ex) {
 
  223        msg << 
"config-get command failed with " << ex.what();
 
  231        msg << 
"config-get command returned " << 
answerToText(answer);
 
  240            .arg(
"config-get command returned an empty configuration");
 
 
  256    } 
catch (exception 
const& ex) {
 
 
  266    vector<Module> modules;
 
  269        modules = context.modules();
 
  270    } 
catch (Error 
const& ex) {
 
  274    for (Module 
const& module : modules) {
 
  275        string const name(module.name());
 
  276        if (!module.revision()) {
 
  279        string const revision(*module.revision());
 
 
  286    auto module = modules_.find(module_name);
 
  292    auto modrev = YANG_REVISIONS.find(module_name);
 
  293    if (modrev == YANG_REVISIONS.end()) {
 
  299    if (modrev->second != module->second) {
 
  303            .arg(module->second);
 
 
  311    bool faulty_model(
false);
 
  313        for (
auto const& pair : *servers) {
 
  322                              "supported. Check logs for details.");
 
  325    for (
auto const& modrev : YANG_REVISIONS) {
 
  326        auto module = modules_.find(modrev.first);
 
  332        if (modrev.second != module->second) {
 
  336                .arg(module->second);
 
 
  343    string const& server(service_pair.first);
 
  349        configuration->
getModel().empty()) {
 
  368            msg << 
"YANG configuration for " 
  381    } 
catch (exception 
const& ex) {
 
  383        msg << 
"get YANG configuration for " << server
 
  384            << 
" failed with " << ex.what();
 
  393    } 
catch (exception 
const& ex) {
 
  395        msg << 
"control socket creation failed with " << ex.what();
 
  406    } 
catch (exception 
const& ex) {
 
  408        msg << 
"config-set command failed with " << ex.what();
 
  416        msg << 
"config-set command returned " << 
answerToText(answer);
 
 
  428    string const& server(service_pair.first);
 
  430    string const& model(configuration->
getModel());
 
  440    auto callback = [=](Session session,
 
  441                        uint32_t subscription_id,
 
  442                        string_view module_name,
 
  443                        optional<string_view> sub_xpath,
 
  445                        uint32_t request_id) {
 
  446        NetconfAgentCallback 
agent(service_pair);
 
  447        return agent.moduleChange(session, subscription_id, module_name, sub_xpath, event,
 
  451        SubscribeOptions options(SubscribeOptions::Default);
 
  453            options = options | SubscribeOptions::DoneOnly;
 
  455        auto exception_handler = [model](std::exception& ex) {
 
  460        Subscription subscription(
 
  461            running_sess_->onModuleChange(model, callback, nullopt, 0, options, exception_handler));
 
  462        subscriptions_.emplace(server, std::forward<Subscription>(subscription));
 
  463    } 
catch (exception 
const& ex) {
 
  465        msg << 
"module change subscribe failed with " << ex.what();
 
  466        msg << 
"change subscription for model " << model << 
" failed with: " << ex.what();
 
 
  477    string const& server(service_pair.first);
 
  479    string const& model(configuration->
getModel());
 
  490    auto callback = [=](Session session,
 
  491                        uint32_t subscription_id,
 
  492                        NotificationType 
const notification_type,
 
  493                        optional<DataNode> 
const notification_tree,
 
  494                        NotificationTimeStamp 
const timestamp) {
 
  495        NetconfAgentCallback 
agent(service_pair);
 
  496        return agent.eventNotif(session, subscription_id, notification_type, notification_tree,
 
  500        auto exception_handler = [model](std::exception& ex) {
 
  505        Subscription subscription(
running_sess_->onNotification(model, callback, nullopt, nullopt,
 
  506                                                                nullopt, SubscribeOptions::Default,
 
  508        subscriptions_.emplace(server, std::forward<Subscription>(subscription));
 
  509    } 
catch (exception 
const& ex) {
 
  511        msg << 
"event notification subscription for model " << model <<
 
  512            " failed with: " << ex.what();
 
 
  523    string const& server(service_pair.first);
 
  531        configuration->
getModel().empty()) {
 
  532        return (sysrepo::ErrorCode::Ok);
 
  536        return (sysrepo::ErrorCode::Ok);
 
  546            msg << 
"YANG configuration for " 
  552            return (sysrepo::ErrorCode::OperationFailed);
 
  559    } 
catch (exception 
const& ex) {
 
  561        msg << 
"get YANG configuration for " << server
 
  562            << 
" failed with " << ex.what();
 
  566        return (sysrepo::ErrorCode::ValidationFailed);
 
  571    } 
catch (exception 
const& ex) {
 
  573        msg << 
"createControlSocket failed with " << ex.what();
 
  577        return (sysrepo::ErrorCode::Ok);
 
  584    } 
catch (exception 
const& ex) {
 
  586        msg << 
"configTest failed with " << ex.what();
 
  590        return (sysrepo::ErrorCode::ValidationFailed);
 
  598        return (sysrepo::ErrorCode::ValidationFailed);
 
  602    return (sysrepo::ErrorCode::Ok);
 
 
  607    string const& server(service_pair.first);
 
  612        configuration->
getModel().empty()) {
 
  613        return (sysrepo::ErrorCode::Ok);
 
  617        return (sysrepo::ErrorCode::Ok);
 
  632            msg << 
"YANG configuration for " 
  638            return (sysrepo::ErrorCode::ValidationFailed);
 
  645    } 
catch (exception 
const& ex) {
 
  647        msg << 
"get YANG configuration for " << server
 
  648            << 
" failed with " << ex.what();
 
  652        return (sysrepo::ErrorCode::ValidationFailed);
 
  660    } 
catch (exception 
const& ex) {
 
  662        msg << 
"createControlSocket failed with " << ex.what();
 
  666        return (sysrepo::ErrorCode::Ok);
 
  675    } 
catch (exception 
const& ex) {
 
  677        msg << 
"configSet failed with " << ex.what();
 
  681        return (sysrepo::ErrorCode::ValidationFailed);
 
  691        return (sysrepo::ErrorCode::ValidationFailed);
 
  695    return (sysrepo::ErrorCode::Ok);
 
 
  700    ostringstream stream;
 
  701    stream << 
"/" << model << 
":*//.";
 
  702    string const xpath(stream.str());
 
  703    ChangeCollection 
const changes(sess.getChanges(xpath));
 
  704    for (Change 
const& 
change : changes) {
 
  706        switch (
change.operation) {
 
  707        case sysrepo::ChangeOperation::Created:
 
  710        case sysrepo::ChangeOperation::Deleted:
 
  713        case sysrepo::ChangeOperation::Modified:
 
  716        case sysrepo::ChangeOperation::Moved:
 
  720            msg << 
"unknown operation (" << 
change.operation << 
"): ";
 
  722        string const path(
change.node.path());
 
  724        SchemaNode 
const& schema(
change.node.schema());
 
  725        NodeType 
const node_type(schema.nodeType());
 
  726        if (node_type == NodeType::Container) {
 
  727            msg << 
" (container)";
 
  728        } 
else if (node_type == NodeType::List) {
 
  731            optional<string> 
const str(
 
  733                                            LeafBaseType::Unknown));
 
  735                msg << 
" = " << *str;
 
 
  749        boost::dynamic_pointer_cast<NetconfController>(controller)
 
  750            ->getNetconfProcess()
 
  751            ->setShutdownFlag(
true);
 
 
  758        ->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.
bool getValidateChanges() const
Getter which returns the validate-changes flag.
bool getBootUpdate() const
Getter which returns the boot-update flag.
bool getSubscribeNotifications() const
Getter which returns the subscribe-changes flag.
bool getSubscribeChanges() const
Getter which returns the subscribe-changes flag.
const CfgControlSocketPtr & getCfgControlSocket() const
Getter which returns the control socket.
const std::string getModel() const
Getter which returns the model name.
virtual data::ConstElementPtr configTest(data::ElementPtr config, const std::string &service)=0
Test configuration.
virtual data::ConstElementPtr configSet(data::ElementPtr config, const std::string &service)=0
Set configuration.
virtual data::ConstElementPtr configGet(const std::string &service)=0
Get configuration.
void subscribeToDataChanges(const CfgServersMapPair &service_pair)
Subscribe changes for a module in YANG datastore.
std::optional< sysrepo::Session > running_sess_
Sysrepo running datastore session.
void getModules()
Retrieve names and revisions of installed modules through the sysrepo API.
static void logChanges(sysrepo::Session sess, std::string_view const &model)
Log changes.
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 initSysrepo()
Initialize sysrepo sessions.
void keaConfig(const CfgServersMapPair &service_pair)
Get and display Kea server configuration.
void announceShutdown() const
Set the shutdown flag of the process to true so that it can exit at the earliest convenient time.
void checkModules(CfgServersMapPtr const &servers={}) const
Check module availability.
std::map< const std::string, sysrepo::Subscription > subscriptions_
Subscription map.
bool shouldShutdown() const
Check the shutdown flag of the process.
static sysrepo::ErrorCode change(sysrepo::Session sess, const CfgServersMapPair &service_pair)
Event::Change callback.
std::optional< sysrepo::Session > startup_sess_
Sysrepo startup datastore session.
static sysrepo::ErrorCode done(sysrepo::Session sess, const CfgServersMapPair &service_pair)
Event::Done callback.
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()
Translate the whole DHCP server configuration from YANG to JSON.
static isc::data::ElementPtr translateFromYang(std::optional< libyang::DataNode > data_node)
Translate basic value from the given YANG data node to JSON element.
static std::optional< std::string > translateToYang(isc::data::ConstElementPtr const &elem, libyang::LeafBaseType const type)
Translate basic value from JSON to YANG.
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.
std::string answerToText(const ConstElementPtr &msg)
Converts answer to printable text.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Parses a standard config/command level answer and returns arguments or text status code.
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
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
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
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< ControlSocketBase > ControlSocketBasePtr
Type definition for the pointer to the ControlSocketBase.
const isc::log::MessageID NETCONF_CONFIG_CHANGED_DETAIL
const isc::log::MessageID NETCONF_NOTIFICATION_INTERNAL_ERROR
const isc::log::MessageID NETCONF_SET_CONFIG_FAILED
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< CfgServer > CfgServerPtr
Defines a pointer for CfgServer instances.
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
const isc::log::MessageID NETCONF_NOTIFICATION_RECEIVED
const isc::log::MessageID NETCONF_MODULE_CHANGE_INTERNAL_ERROR
const isc::log::MessageID NETCONF_UPDATE_CONFIG_COMPLETED
std::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
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< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.
const isc::log::MessageID NETCONF_MODULE_MISSING_WARN
const isc::log::MessageID NETCONF_NOT_SUBSCRIBED_TO_NOTIFICATIONS
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.