Kea  1.9.9-git
netconf.cc
Go to the documentation of this file.
1 // Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
9 
10 #include <config.h>
11 
12 #include <netconf/netconf.h>
14 #include <netconf/netconf_log.h>
15 #include <cc/command_interpreter.h>
16 #include <yang/translator_config.h>
17 #include <yang/yang_revisions.h>
18 #include <boost/algorithm/string.hpp>
19 #include <sstream>
20 
21 using namespace std;
22 using namespace isc::config;
23 using namespace isc::data;
24 using namespace isc::netconf;
25 using namespace isc::yang;
26 #ifndef HAVE_PRE_0_7_6_SYSREPO
27 using namespace sysrepo;
28 #endif
29 
30 namespace {
31 
33 class NetconfAgentCallback : public Callback {
34 public:
38  NetconfAgentCallback(const CfgServersMapPair& service_pair)
39  : service_pair_(service_pair) {
40  }
41 
43  CfgServersMapPair service_pair_;
44 
55  int module_change(S_Session sess,
56  const char* /*module_name*/,
57  sr_notif_event_t event,
58  void* /*private_ctx*/) {
59  if (NetconfProcess::shut_down) {
60  return (SR_ERR_DISCONNECT);
61  }
62  ostringstream event_type;
63  switch (event) {
64  case SR_EV_VERIFY:
65  event_type << "VERIFY";
66  break;
67  case SR_EV_APPLY:
68  event_type << "APPLY";
69  break;
70  case SR_EV_ABORT:
71  event_type << "ABORT";
72  break;
73  case SR_EV_ENABLED:
74  event_type << "ENABLED";
75  break;
76  default:
77  event_type << "UNKNOWN (" << event << ")";
78  break;
79  }
81  .arg(event_type.str());
82  string xpath = "/" + service_pair_.second->getModel() + ":";
83  NetconfAgent::logChanges(sess, xpath + "config");
84  if (NetconfProcess::shut_down) {
85  return (SR_ERR_DISCONNECT);
86  }
87  switch (event) {
88  case SR_EV_VERIFY:
89  return (NetconfAgent::validate(sess, service_pair_));
90  case SR_EV_APPLY:
91  return (NetconfAgent::update(sess, service_pair_));
92  default:
93  return (SR_ERR_OK);
94  }
95  }
96 };
97 
99 class NetconfAgentInstallCallback : public Callback {
100 public:
109  void module_install(const char* module_name,
110  const char* revision,
111  sr_module_state_t /*state*/,
112  void* /*private_ctx*/) {
113  if (!module_name) {
114  // Not for us...
115  return;
116  }
118  .arg(module_name)
119  .arg(revision ? revision : "unknown");
120  }
121 };
122 
123 } // end of anonymous namespace
124 
125 namespace isc {
126 namespace netconf {
127 
128 NetconfAgent::NetconfAgent() {
129 }
130 
131 NetconfAgent::~NetconfAgent() {
132  clear();
133 }
134 
135 void
136 NetconfAgent::init(NetconfCfgMgrPtr cfg_mgr) {
137  // If there is no configuration manager and/or we're shutting down.
138  if (!cfg_mgr || NetconfProcess::shut_down) {
139  return;
140  }
141  const CfgServersMapPtr& servers =
142  cfg_mgr->getNetconfConfig()->getCfgServersMap();
143  for (auto pair : *servers) {
144  if (NetconfProcess::shut_down) {
145  return;
146  }
147 
148  // Retrieve configuration from existing running DHCP daemons.
149  keaConfig(pair);
150  if (NetconfProcess::shut_down) {
151  return;
152  }
153  }
154  if (NetconfProcess::shut_down) {
155  return;
156  }
157 
158  // Initialize sysrepo interface.
159  initSysrepo();
160  if (NetconfProcess::shut_down) {
161  return;
162  }
163 
164  // Check essential modules / revisions.
165  bool can_start = true;
166  for (auto pair : *servers) {
167  can_start = can_start && checkModule(pair.second->getModel());
168  if (NetconfProcess::shut_down) {
169  return;
170  }
171  }
172  if (!can_start) {
173  cerr << "An essential YANG module / revision is missing."
174  << endl
175  << "The environment is not suitable for running kea-netconf."
176  << endl;
177  exit(EXIT_FAILURE);
178  }
179  if (NetconfProcess::shut_down) {
180  return;
181  }
182 
183  // Check modules / revisions.
184  checkModules();
185  if (NetconfProcess::shut_down) {
186  return;
187  }
188 
189  for (auto pair : *servers) {
190  if (NetconfProcess::shut_down) {
191  return;
192  }
193  yangConfig(pair);
194  if (NetconfProcess::shut_down) {
195  return;
196  }
197  subscribeConfig(pair);
198  if (NetconfProcess::shut_down) {
199  return;
200  }
201  }
202 }
203 
204 void
205 NetconfAgent::clear() {
206  // Should be already set to true but in case...
207  NetconfProcess::shut_down = true;
208  for (auto subs : subscriptions_) {
209  subs.second.reset();
210  }
211  subscriptions_.clear();
212  running_sess_.reset();
213  startup_sess_.reset();
214  conn_.reset();
215 }
216 
217 void
218 NetconfAgent::keaConfig(const CfgServersMapPair& service_pair) {
219  // If the boot-update flag is not set.
220  if (!service_pair.second->getBootUpdate()) {
221  return;
222  }
223  CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
224  if (!ctrl_sock) {
225  return;
226  }
228  try {
229  comm = createControlSocket(ctrl_sock);
230  } catch (const std::exception& ex) {
231  ostringstream msg;
232  msg << "createControlSocket failed with " << ex.what();
234  .arg(service_pair.first)
235  .arg(msg.str());
236  return;
237  }
238  ConstElementPtr answer;
239  int rcode;
240  ConstElementPtr config;
242  .arg(service_pair.first);
243  try {
244  answer = comm->configGet(service_pair.first);
245  config = parseAnswer(rcode, answer);
246  } catch (const std::exception& ex) {
247  ostringstream msg;
248  msg << "config-get command failed with " << ex.what();
250  .arg(service_pair.first)
251  .arg(msg.str());
252  return;
253  }
254  if (NetconfProcess::shut_down) {
255  return;
256  }
257  if (rcode != CONTROL_RESULT_SUCCESS) {
258  ostringstream msg;
259  msg << "config-get command returned " << answerToText(answer);
261  .arg(service_pair.first)
262  .arg(msg.str());
263  return;
264  }
265  if (!config) {
267  .arg(service_pair.first)
268  .arg("config-get command returned an empty configuration");
269  return;
270  }
273  .arg(service_pair.first)
274  .arg(prettyPrint(config));
275 }
276 
277 void
278 NetconfAgent::initSysrepo() {
279  try {
280  conn_.reset(new Connection(NetconfController::netconf_app_name_,
281  SR_CONN_DAEMON_REQUIRED));
282  } catch (const std::exception& ex) {
283  isc_throw(Unexpected, "Can't connect to sysrepo: " << ex.what());
284  }
285  if (NetconfProcess::shut_down) {
286  return;
287  }
288 
289  try {
290  startup_sess_.reset(new Session(conn_, SR_DS_STARTUP));
291  if (NetconfProcess::shut_down) {
292  return;
293  }
294  running_sess_.reset(new Session(conn_, SR_DS_RUNNING));
295  } catch (const std::exception& ex) {
296  isc_throw(Unexpected, "Can't establish a sysrepo session: "
297  << ex.what());
298  }
299  if (NetconfProcess::shut_down) {
300  return;
301  }
302 
303  try {
304  S_Yang_Schemas schemas = startup_sess_->list_schemas();
305  for (size_t i = 0; i < schemas->schema_cnt(); ++i) {
306  if (NetconfProcess::shut_down) {
307  return;
308  }
309  if (!schemas->schema(i) ||
310  !schemas->schema(i)->module_name()) {
311  // Should not happen: skip it.
312  continue;
313  }
314  string module = schemas->schema(i)->module_name();
315  if (!schemas->schema(i)->revision() ||
316  !schemas->schema(i)->revision()->revision()) {
317  // Our modules have revisions: skip it.
318  continue;
319  }
320  string revision = schemas->schema(i)->revision()->revision();
321  modules_.insert(make_pair(module, revision));
322  }
323  } catch (const sysrepo_exception& ex) {
324  isc_throw(Unexpected, "Can't list schemas: " << ex.what());
325  }
326  if (NetconfProcess::shut_down) {
327  return;
328  }
329 
330  // Subscribe to the module (un)installation callback.
331  // When a module is (un)installed the callback is called.
332  // Note this requires a system test (vs. unit test).
333  try {
334  S_Subscribe subs(new Subscribe(startup_sess_));
335  S_Callback cb(new NetconfAgentInstallCallback());
336  subs->module_install_subscribe(cb);
337  subscriptions_.insert(make_pair("__install__", subs));
338  } catch (const sysrepo_exception& ex) {
339  isc_throw(Unexpected, "Can't subscribe module install: "
340  << ex.what());
341  }
342 }
343 
344 bool
345 NetconfAgent::checkModule(const string& module_name) const {
346  if (module_name.empty()) {
347  return (true);
348  }
349  auto module = modules_.find(module_name);
350  if (module == modules_.end()) {
352  .arg(module_name);
353  return (false);
354  }
355  auto modrev = YANG_REVISIONS.find(module_name);
356  if (modrev == YANG_REVISIONS.end()) {
357  // Can't check revision?!
358  // It can happen only with a module which is not in
359  // YANG_REVISIONS but installed so likely on purpose.
360  return (true);
361  }
362  if (modrev->second != module->second) {
364  .arg(module_name)
365  .arg(modrev->second)
366  .arg(module->second);
367  return (false);
368  }
369  return (true);
370 }
371 
372 void
373 NetconfAgent::checkModules() const {
374  for (auto modrev : YANG_REVISIONS) {
375  if (NetconfProcess::shut_down) {
376  return;
377  }
378  auto module = modules_.find(modrev.first);
379  if (module == modules_.end()) {
381  .arg(modrev.first);
382  continue;
383  }
384  if (modrev.second != module->second) {
386  .arg(modrev.first)
387  .arg(modrev.second)
388  .arg(module->second);
389  }
390  }
391 }
392 
393 void
394 NetconfAgent::yangConfig(const CfgServersMapPair& service_pair) {
395  // If we're shutting down, or the boot-update flag is not set or the model
396  // associated with it is not specified.
397  if (NetconfProcess::shut_down ||
398  !service_pair.second->getBootUpdate() ||
399  service_pair.second->getModel().empty()) {
400  return;
401  }
402 
403  // First we need a way to reach the actual servers.
404  CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
405  if (!ctrl_sock) {
406  return;
407  }
408 
410  .arg(service_pair.first);
411  ConstElementPtr config;
412  try {
413  // Retrieve configuration from Sysrepo.
414  TranslatorConfig tc(startup_sess_, service_pair.second->getModel());
415  config = tc.getConfig();
416  if (!config) {
417  ostringstream msg;
418  msg << "YANG configuration for "
419  << service_pair.second->getModel()
420  << " is empty";
422  .arg(service_pair.first)
423  .arg(msg.str());
424  return;
425  } else {
428  .arg(service_pair.first)
429  .arg(prettyPrint(config));
430  }
431  } catch (const std::exception& ex) {
432  ostringstream msg;
433  msg << "get YANG configuration for " << service_pair.first
434  << " failed with " << ex.what();
436  .arg(service_pair.first)
437  .arg(msg.str());
438  return;
439  }
440  if (NetconfProcess::shut_down) {
441  return;
442  }
444  try {
445  comm = createControlSocket(ctrl_sock);
446  } catch (const std::exception& ex) {
447  ostringstream msg;
448  msg << "control socket creation failed with " << ex.what();
450  .arg(service_pair.first)
451  .arg(msg.str());
452  return;
453  }
454  if (NetconfProcess::shut_down) {
455  return;
456  }
457  ConstElementPtr answer;
458  int rcode;
459  try {
460  answer = comm->configSet(config, service_pair.first);
461  parseAnswer(rcode, answer);
462  } catch (const std::exception& ex) {
463  ostringstream msg;
464  msg << "config-set command failed with " << ex.what();
466  .arg(service_pair.first)
467  .arg(msg.str());
468  return;
469  }
470  if (rcode != CONTROL_RESULT_SUCCESS) {
471  ostringstream msg;
472  msg << "config-set command returned " << answerToText(answer);
474  .arg(service_pair.first)
475  .arg(msg.str());
476  return;
477  }
479  .arg(service_pair.first);
480 }
481 
482 void
483 NetconfAgent::subscribeConfig(const CfgServersMapPair& service_pair) {
484  // If we're shutting down, or the subscribe-changes flag is not set or
485  // the model associated with it is not specified.
486  if (NetconfProcess::shut_down ||
487  !service_pair.second->getSubscribeChanges() ||
488  service_pair.second->getModel().empty()) {
489  return;
490  }
492  .arg(service_pair.first)
493  .arg(service_pair.second->getModel());
494  S_Subscribe subs(new Subscribe(running_sess_));
495  S_Callback cb(new NetconfAgentCallback(service_pair));
496  try {
497  sr_subscr_options_t options = SR_SUBSCR_DEFAULT;
498  if (!service_pair.second->getValidateChanges()) {
499  options |= SR_SUBSCR_APPLY_ONLY;
500  }
501  // Note the API stores the module name so do not put it
502  // in a short lifetime variable!
503  subs->module_change_subscribe(service_pair.second->getModel().c_str(),
504  cb, 0, 0, options);
505  } catch (const std::exception& ex) {
506  ostringstream msg;
507  msg << "module change subscribe failed with " << ex.what();
509  .arg(service_pair.first)
510  .arg(service_pair.second->getModel())
511  .arg(msg.str());
512  subs.reset();
513  return;
514  }
515  subscriptions_.insert(make_pair(service_pair.first, subs));
516 }
517 
518 int
519 NetconfAgent::validate(S_Session sess, const CfgServersMapPair& service_pair) {
520  // If we're shutting down, or the subscribe-changes or the
521  // validate-changes flag is not set or the model associated with
522  // it is not specified.
523  if (NetconfProcess::shut_down ||
524  !service_pair.second->getSubscribeChanges() ||
525  !service_pair.second->getValidateChanges() ||
526  service_pair.second->getModel().empty()) {
527  return (SR_ERR_OK);
528  }
529  CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
530  if (!ctrl_sock) {
531  return (SR_ERR_OK);
532  }
534  .arg(service_pair.first);
535  ConstElementPtr config;
536  try {
537  TranslatorConfig tc(sess, service_pair.second->getModel());
538  config = tc.getConfig();
539  if (!config) {
540  ostringstream msg;
541  msg << "YANG configuration for "
542  << service_pair.second->getModel()
543  << " is empty";
545  .arg(service_pair.first)
546  .arg(msg.str());
547  return (SR_ERR_DISCONNECT);
548  } else {
551  .arg(service_pair.first)
552  .arg(prettyPrint(config));
553  }
554  } catch (const std::exception& ex) {
555  ostringstream msg;
556  msg << "get YANG configuration for " << service_pair.first
557  << " failed with " << ex.what();
559  .arg(service_pair.first)
560  .arg(msg.str());
561  return (SR_ERR_VALIDATION_FAILED);;
562  }
563  if (NetconfProcess::shut_down) {
564  return (SR_ERR_DISCONNECT);
565  }
567  try {
568  comm = createControlSocket(ctrl_sock);
569  } catch (const std::exception& ex) {
570  ostringstream msg;
571  msg << "createControlSocket failed with " << ex.what();
573  .arg(service_pair.first)
574  .arg(msg.str());
575  return (SR_ERR_OK);
576  }
577  ConstElementPtr answer;
578  int rcode;
579  try {
580  answer = comm->configTest(config, service_pair.first);
581  parseAnswer(rcode, answer);
582  } catch (const std::exception& ex) {
583  stringstream msg;
584  msg << "configTest failed with " << ex.what();
586  .arg(service_pair.first)
587  .arg(msg.str());
588  return (SR_ERR_VALIDATION_FAILED);
589  }
590  if (rcode != CONTROL_RESULT_SUCCESS) {
591  stringstream msg;
592  msg << "configTest returned " << answerToText(answer);
594  .arg(service_pair.first)
595  .arg(msg.str());
596  return (SR_ERR_VALIDATION_FAILED);
597  }
599  .arg(service_pair.first);
600  return (SR_ERR_OK);
601 }
602 
603 int
604 NetconfAgent::update(S_Session sess, const CfgServersMapPair& service_pair) {
605  // Check if we should and can process this update.
606  if (NetconfProcess::shut_down ||
607  !service_pair.second->getSubscribeChanges() ||
608  service_pair.second->getModel().empty()) {
609  return (SR_ERR_OK);
610  }
611  CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
612  if (!ctrl_sock) {
613  return (SR_ERR_OK);
614  }
615 
616  // All looks good, let's get started. Print an info that we're about
617  // to update the configuration.
619  .arg(service_pair.first);
620 
621  // Retrieve the configuration from SYSREPO first.
622  ConstElementPtr config;
623  try {
624  TranslatorConfig tc(sess, service_pair.second->getModel());
625  config = tc.getConfig();
626  if (!config) {
627  ostringstream msg;
628  msg << "YANG configuration for "
629  << service_pair.second->getModel()
630  << " is empty";
632  .arg(service_pair.first)
633  .arg(msg.str());
634  return (SR_ERR_VALIDATION_FAILED);
635  } else {
638  .arg(service_pair.first)
639  .arg(prettyPrint(config));
640  }
641  } catch (const std::exception& ex) {
642  ostringstream msg;
643  msg << "get YANG configuration for " << service_pair.first
644  << " failed with " << ex.what();
646  .arg(service_pair.first)
647  .arg(msg.str());
648  return (SR_ERR_VALIDATION_FAILED);
649  }
650  if (NetconfProcess::shut_down) {
651  return (SR_ERR_OK);
652  }
653 
654  // Ok, now open the control socket. We need this to send the config to
655  // the server.
657  try {
658  comm = createControlSocket(ctrl_sock);
659  } catch (const std::exception& ex) {
660  ostringstream msg;
661  msg << "createControlSocket failed with " << ex.what();
663  .arg(service_pair.first)
664  .arg(msg.str());
665  return (SR_ERR_OK);
666  }
667 
668  // Now apply the config using config-set command.
669  ConstElementPtr answer;
670  int rcode;
671  try {
672  answer = comm->configSet(config, service_pair.first);
673  parseAnswer(rcode, answer);
674  } catch (const std::exception& ex) {
675  stringstream msg;
676  msg << "configSet failed with " << ex.what();
678  .arg(service_pair.first)
679  .arg(msg.str());
680  return (SR_ERR_VALIDATION_FAILED);
681  }
682 
683  // rcode == CONTROL_RESULT_SUCCESS, unless the docs say otherwise :).
684  if (rcode != CONTROL_RESULT_SUCCESS) {
685  stringstream msg;
686  msg << "configSet returned " << answerToText(answer);
688  .arg(service_pair.first)
689  .arg(msg.str());
690  return (SR_ERR_VALIDATION_FAILED);
691  }
693  .arg(service_pair.first);
694  return (SR_ERR_OK);
695 }
696 
697 void
698 NetconfAgent::logChanges(S_Session sess, const string& model) {
699  if (NetconfProcess::shut_down) {
700  return;
701  }
702  S_Iter_Change iter = sess->get_changes_iter(model.c_str());
703  if (!iter) {
705  .arg("no iterator");
706  return;
707  }
708  for (;;) {
709  if (NetconfProcess::shut_down) {
710  return;
711  }
712  S_Change change;
713  ostringstream msg;
714  try {
715  change = sess->get_change_next(iter);
716  } catch (const sysrepo_exception& ex) {
717  msg << "get change iterator next failed: " << ex.what();
719  .arg(msg.str());
720  return;
721  }
722  if (!change) {
723  // End of changes, not an error.
724  return;
725  }
726  if (NetconfProcess::shut_down) {
727  return;
728  }
729  S_Val new_val = change->new_val();
730  S_Val old_val = change->old_val();
731  string report;
732  switch (change->oper()) {
733  case SR_OP_CREATED:
734  if (!new_val) {
736  .arg("created but without a new value");
737  break;
738  }
739  msg << "created: " << new_val->to_string();
740  report = msg.str();
741  boost::erase_all(report, "\n");
744  .arg(report);
745  break;
746  case SR_OP_MODIFIED:
747  if (!old_val || !new_val) {
749  .arg("modified but without an old or new value");
750  break;
751  }
752  msg << "modified: " << old_val->to_string()
753  << " => " << new_val->to_string();
754  report = msg.str();
755  boost::erase_all(report, "\n");
758  .arg(report);
759  break;
760  case SR_OP_DELETED:
761  if (!old_val) {
763  .arg("deleted but without an old value");
764  break;
765  }
766  msg << "deleted: " << old_val->to_string();
767  report = msg.str();
768  boost::erase_all(report, "\n");
771  .arg(report);
772  break;
773  case SR_OP_MOVED:
774  if (!new_val) {
776  .arg("moved but without a new value");
777  break;
778  }
779  msg << "moved: " << new_val->xpath();
780  if (!old_val) {
781  msg << " first";
782  } else {
783  msg << " after " << old_val->xpath();
784  }
785  report = msg.str();
786  boost::erase_all(report, "\n");
789  .arg(report);
790  break;
791  default:
792  msg << "unknown operation (" << change->oper() << ")";
794  .arg(msg.str());
795  }
796  }
797 }
798 
799 } // namespace netconf
800 } // namespace isc
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
const isc::log::MessageID NETCONF_GET_CONFIG
const isc::log::MessageID NETCONF_SET_CONFIG_FAILED
const isc::log::MessageID NETCONF_GET_CONFIG_FAILED
DHCP configuration translation between YANG and JSON.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< ControlSocketBase > ControlSocketBasePtr
Type definition for the pointer to the ControlSocketBase.
const isc::log::MessageID NETCONF_BOOT_UPDATE_COMPLETED
const int NETCONF_DBG_TRACE_DETAIL_DATA
Additional information.
Definition: netconf_log.h:41
void prettyPrint(ConstElementPtr element, std::ostream &out, unsigned indent, unsigned step)
Pretty prints the data into stream.
Definition: data.cc:1224
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_COMPLETED
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
STL namespace.
const isc::log::MessageID NETCONF_UPDATE_CONFIG
const isc::log::MessageID NETCONF_SET_CONFIG_STARTED
const isc::log::MessageID NETCONF_LOG_CHANGE_FAIL
const isc::log::MessageID NETCONF_SET_CONFIG
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_STARTED
isc::data::ElementPtr getConfig()
Get and translate the whole DHCP server configuration from YANG to JSON.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::string answerToText(const ConstElementPtr &msg)
const isc::log::MessageID NETCONF_VALIDATE_CONFIG
A generic exception that is thrown when an unexpected error condition occurs.
const isc::log::MessageID NETCONF_CONFIG_CHANGE_EVENT
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
const isc::log::MessageID NETCONF_MODULE_REVISION_ERR
isc::log::Logger netconf_logger(NETCONF_LOGGER_NAME)
Base logger for the netconf agent.
Definition: netconf_log.h:49
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG_FAILED
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Defines the logger used by the top-level component of kea-dhcp-ddns.
const isc::log::MessageID NETCONF_UPDATE_CONFIG_STARTED
const isc::log::MessageID NETCONF_MODULE_REVISION_WARN
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
const isc::log::MessageID NETCONF_UPDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_MODULE_MISSING_ERR
const isc::log::MessageID NETCONF_MODULE_INSTALL
This file contains several functions and constants that are used for handling commands and responses ...
ControlSocketBasePtr createControlSocket(CfgControlSocketPtr ctrl_sock)
Factory template for control sockets.
const isc::log::MessageID NETCONF_GET_CONFIG_STARTED
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
Contains declarations for loggers used by the Kea netconf agent.
const isc::log::MessageID NETCONF_CONFIG_CHANGED_DETAIL
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_MODULE_MISSING_WARN
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_REJECTED
boost::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
boost::shared_ptr< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.