kea-custom-hooks
FeM custom hooks libraries for Kea DHCP
init.cpp
Go to the documentation of this file.
1
8#include <fstream>
9
10#include <pqxx/except>
11
12#include <cc/command_interpreter.h>
13#include <hooks/hooks.h>
14#include <log/macros.h>
15
16#include "AdminDBClient.hpp"
17#include "Config.hpp"
18#include "LocalDBClient.hpp"
19#include "callout.hpp"
20#include "common_vars.hpp"
21#include "log_admindb_host_reservation_importer.h"
22
23namespace ahri::globals
24{
25// NOLINTBEGIN(*-non-const-global-variables)
26isc::asiolink::IOServicePtr io_context{nullptr};
27std::unique_ptr<ahri::Config> config{nullptr};
28isc::log::Logger logger{"ahri"};
29// NOLINTEND(*-non-const-global-variables)
30} // namespace ahri::globals
31
32namespace
33{
34constexpr const char* DEFAULT_CONFIG_FILE_LOCATION{"/etc/admindb-host-reservation-importer.conf"};
35
36// NOLINTBEGIN(*-non-const-global-variables)
37std::unique_ptr<ahri::AdminDBClient> admindb{nullptr};
38std::unique_ptr<ahri::LocalDBClient> localdb{nullptr};
39// NOLINTEND(*-non-const-global-variables)
40
41std::unique_ptr<ahri::LocalDBClient> init_localdb(ahri::Config& config);
42std::unique_ptr<ahri::AdminDBClient> init_admindb(ahri::Config& config);
43void update_dhcp_incrementally();
44int full_sync_command_hdl(isc::hooks::CalloutHandle& hdl);
45size_t full_sync();
46} // namespace
47
48extern "C" {
49int unload();
50
51int load(isc::hooks::LibraryHandle& hdl)
52{
53 std::string config_path = DEFAULT_CONFIG_FILE_LOCATION;
54 try {
55 auto raw_config_path = hdl.getParameter("config");
56 // Only load the config if specified
57 if (raw_config_path) {
58 config_path = raw_config_path->stringValue();
59 }
60 }
61 catch (isc::data::TypeError& e) {
62 LOG_FATAL(ahri::globals::logger, ahri::AHRI_CONFIG_ERROR).arg("Invalid config file path");
63 }
64
65 LOG_INFO(ahri::globals::logger, ahri::AHRI_LOADING_CONFIG).arg(config_path);
66 std::ifstream config_file{config_path};
67 if (config_file.bad()) {
68 LOG_FATAL(ahri::globals::logger, ahri::AHRI_CONFIG_ERROR)
69 .arg("Failed to load configuration file ");
70 return 1;
71 }
72
73 LOG_DEBUG(ahri::globals::logger, 50, ahri::AHRI_PARSING_CONFIG);
74 try {
75 ahri::globals::config = std::make_unique<ahri::Config>(config_file);
76 }
77 catch (ahri::Config::ParseError& e) {
78 LOG_FATAL(ahri::globals::logger, ahri::AHRI_CONFIG_ERROR).arg(e.what());
79 return 1;
80 }
81
82 // Example of how we might register the command callouts
83 // hdl.registerCommandCallout("ahri-consistency-check", ahri::commands::consistency_check);
84 // hdl.registerCommandCallout("ahri-get-last-consistency-check-result",
85 // ahri::commands::get_last_consistency_check_result);
86 hdl.registerCommandCallout("ahri-full-sync", full_sync_command_hdl);
87
88 LOG_INFO(ahri::globals::logger, ahri::AHRI_INIT_LOCALDB);
89 try {
90 localdb = init_localdb(*ahri::globals::config);
91 }
92 catch (const std::exception& e) {
93 LOG_ERROR(ahri::globals::logger, ahri::AHRI_INIT_LOCALDB_FAILED).arg(e.what());
94 unload();
95 return 1;
96 }
97
98 LOG_INFO(ahri::globals::logger, ahri::AHRI_INIT_ADMINDB);
99 try {
100 admindb = init_admindb(*ahri::globals::config);
101 }
102 catch (const std::exception& e) {
103 LOG_ERROR(ahri::globals::logger, ahri::AHRI_INIT_ADMINDB_FAILED).arg(e.what());
104 unload();
105 return 1;
106 }
107
108 assert(localdb);
109 assert(admindb);
110
111 try {
112 full_sync();
113 }
114 catch (const std::exception& e) {
115 LOG_FATAL(ahri::globals::logger, ahri::AHRI_FULL_SYNC_FAILED).arg(e.what());
116 unload();
117 return 1;
118 }
119
120 try {
121 LOG_INFO(ahri::globals::logger, ahri::AHRI_INIT_REGISTER_HANDLER);
122 admindb->handle_notifications(update_dhcp_incrementally);
123 }
124 catch (const std::exception& e) {
125 LOG_FATAL(ahri::globals::logger, ahri::AHRI_INIT_REGISTER_HANDLER_FAILED).arg(e.what());
126 unload();
127 return 1;
128 }
129
130 LOG_INFO(ahri::globals::logger, ahri::AHRI_INIT_OK);
131 return 0;
132}
133
135{
138 }
139 if (admindb) {
140 admindb.reset(nullptr);
141 }
142 if (localdb) {
143 localdb.reset(nullptr);
144 }
145 return 0;
146}
147}
148
149namespace
150{
151std::unique_ptr<ahri::LocalDBClient> init_localdb(ahri::Config& config)
152{
153 return std::make_unique<ahri::LocalDBClient>(
154 config.localdb().server.host, config.localdb().server.port, config.localdb().user,
155 config.localdb().password, config.localdb().database);
156}
157
158std::unique_ptr<ahri::AdminDBClient> init_admindb(ahri::Config& config)
159{
160 assert(!config.admindb().servers.empty());
161 return std::make_unique<ahri::AdminDBClient>(
162 config.admindb().servers.at(0).host, config.admindb().servers.at(0).port,
163 config.admindb().user, config.admindb().password, config.admindb().database);
164}
165
166void update_dhcp_incrementally()
167{
168 try {
169 LOG_INFO(ahri::globals::logger, ahri::AHRI_RECEIVED_HOST_UPDATES);
170 const std::vector<ahri::AdminDBClient::HostUpdate> updates =
171 admindb->fetch_pending_host_updates();
172 localdb->apply_host_updates(updates);
173 }
174 catch (pqxx::sql_error& e) {
175 LOG_ERROR(ahri::globals::logger, ahri::AHRI_HOST_UPDATES_SQL_ERROR)
176 .arg(e.what())
177 .arg(e.query())
178 .arg(e.sqlstate());
179 full_sync();
180 }
181}
182
183int full_sync_command_hdl(isc::hooks::CalloutHandle& hdl)
184{
185 isc::data::ConstElementPtr response;
186 try {
187 const size_t full_sync_diff = full_sync();
188 response = isc::config::createAnswer(
189 isc::config::CONTROL_RESULT_SUCCESS,
190 isc::data::Element::create(static_cast<long long int>(full_sync_diff)));
191 }
192 catch (std::exception& e) {
193 response = isc::config::createAnswer(isc::config::CONTROL_RESULT_ERROR,
194 "Exception during command execution");
195 LOG_WARN(ahri::globals::logger, ahri::AHRI_FULL_SYNC_FAILED).arg(e.what());
196 }
197 hdl.setArgument("response", response);
198 return 0;
199}
200
201size_t full_sync()
202{
203 LOG_INFO(ahri::globals::logger, ahri::AHRI_FULL_SYNC_START);
204 const std::vector<ahri::AdminDBClient::HostUpdate> full_sync =
205 admindb->fetch_all_host_reservations();
206 LOG_INFO(ahri::globals::logger, ahri::AHRI_FULL_SYNC_HOSTS_FETCHED);
207 const std::vector<ahri::AdminDBClient::HostUpdate> table_diff =
208 localdb->compare_full_sync(full_sync);
209 LOG_INFO(ahri::globals::logger, ahri::AHRI_FULL_SYNC_DIFF).arg(table_diff.size());
210 localdb->apply_host_updates(table_diff);
211 LOG_INFO(ahri::globals::logger, ahri::AHRI_FULL_SYNC_COMPLETE);
212 return table_diff.size();
213}
214} // namespace
int unload()
Unitialization/cleanup point for admindb-arpwatch-exporter.
Definition: init.cpp:69
int load(isc::hooks::LibraryHandle &handle)
Initialization/starting point for admindb-arpwatch-exporter.
Definition: init.cpp:48
Declarations for all ahri-related Kea callout handlers.
Exception for errors during configuration parsing.
Definition: Config.hpp:83
Configuration parser for admindb-host-reservation-importer configuration.
Definition: Config.hpp:24
Collection of common variables used throughout the library.
Library-global variables.
Definition: common_vars.hpp:18
std::unique_ptr< ahri::Config > config
Definition: init.cpp:27
isc::log::Logger logger
Definition: init.cpp:28
isc::asiolink::IOServicePtr io_context
Definition: init.cpp:26