configuration.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include "configuration.hpp"
  2. // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
  3. // _log_level is initialized in a function that is called directly from the
  4. // constructor. If _log_level cannot be initialized, an error is thrown.
  5. Configuration::Configuration(const std::string& filename) :
  6. _node_container(std::make_shared<NodeContainer>()),
  7. _log_level(boost::log::trivial::info)
  8. {
  9. // NOLINTEND(cppcoreguidelines-pro-type-member-init)
  10. this->load(filename);
  11. this->validate_node_depth();
  12. }
  13. void Configuration::load(const std::string& filename)
  14. {
  15. try
  16. {
  17. const YAML::Node config = YAML::LoadFile(filename);
  18. this->load_log_level(config["log_level"]);
  19. const YAML::Node device_name_node = config["device_name"];
  20. if (!device_name_node.IsDefined())
  21. throw std::runtime_error("device name is missing.");
  22. this->_device_name = device_name_node.as<std::string>();
  23. const YAML::Node post_up_command_node = config["post_up_commands"];
  24. this->load_postup_commands(post_up_command_node);
  25. const YAML::Node nodes_config = config["nodes"];
  26. this->load_nodes(nodes_config, this->_node_container);
  27. }
  28. catch (const YAML::Exception& e)
  29. {
  30. BOOST_LOG_TRIVIAL(error)
  31. << "Failed to load configuration file: " << e.what() << std::endl;
  32. throw std::runtime_error("Failed to load configuration file: YAML");
  33. }
  34. }
  35. void Configuration::validate_node_depth() const
  36. {
  37. const std::size_t max_depth = this->_node_container->max_depth();
  38. if (max_depth > 255)
  39. {
  40. throw std::runtime_error("The nodes are too deep.");
  41. }
  42. }
  43. void Configuration::load_log_level(const YAML::Node& node)
  44. {
  45. if (!node.IsDefined())
  46. return;
  47. const std::string log_level_string = node.as<std::string>();
  48. this->_log_level = LogLevel(log_level_string);
  49. }
  50. void Configuration::load_postup_commands(const YAML::Node& node)
  51. {
  52. if (node.IsDefined())
  53. {
  54. if (!node.IsSequence())
  55. throw std::runtime_error("post up commands must be an array.");
  56. for (const auto& command_node : node)
  57. {
  58. this->_postup_commands.add_postup_command(
  59. command_node.as<std::string>());
  60. }
  61. }
  62. }
  63. template<typename T,
  64. typename std::enable_if_t<std::is_same_v<T, NodeInfo> ||
  65. std::is_same_v<T, NodeContainer>,
  66. int>>
  67. void Configuration::load_nodes(const YAML::Node& nodes_config,
  68. std::shared_ptr<T> nodes,
  69. bool mac)
  70. {
  71. if (nodes_config.IsDefined() && !nodes_config.IsNull())
  72. {
  73. if (!nodes_config.IsSequence())
  74. throw std::runtime_error(
  75. "Failed to load configuration file: Nodes is not a sequence.");
  76. for (const auto& node_config : nodes_config)
  77. {
  78. if (node_config.IsNull())
  79. continue;
  80. if (!node_config.IsMap())
  81. throw std::runtime_error(
  82. "Failed to load configuration file: Node is not a map.");
  83. if (!node_config["addresses"].IsDefined())
  84. throw std::runtime_error("Failed to load configuration file: "
  85. "Missing addresses attribute.");
  86. if (!node_config["addresses"].IsSequence())
  87. throw std::runtime_error("Failed to load configuration file: "
  88. "Addresses is not a sequence.");
  89. if (mac && !node_config["mac"].IsDefined())
  90. throw std::runtime_error("Failed to load configuration "
  91. "file: Missing mac attribute.");
  92. const auto node = std::make_shared<NodeInfo>();
  93. if (mac)
  94. {
  95. node->set_mac_address(
  96. Tins::HWAddress<6>(node_config["mac"].as<std::string>()));
  97. }
  98. for (const YAML::Node addresses_config = node_config["addresses"];
  99. const auto& address_config : addresses_config)
  100. node->add_address(
  101. Tins::IPv6Address(address_config.as<std::string>()));
  102. if (const YAML::Node hoplimit_config = node_config["hoplimit"];
  103. hoplimit_config.IsDefined())
  104. node->set_hoplimit(hoplimit_config.as<int>());
  105. load_nodes(node_config["nodes"], node, false);
  106. nodes->add_node(node);
  107. }
  108. }
  109. }
  110. std::shared_ptr<NodeContainer>
  111. Configuration::get_node_container() const noexcept
  112. {
  113. return this->_node_container;
  114. }
  115. LogLevel Configuration::get_log_level() const noexcept
  116. {
  117. return this->_log_level;
  118. }
  119. const std::string& Configuration::get_device_name() const noexcept
  120. {
  121. return this->_device_name;
  122. }
  123. const PostupCommands& Configuration::get_postup_commands() const noexcept
  124. {
  125. return this->_postup_commands;
  126. }