1 // Copyright (C) 2017-2021 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
7 #include <config.h>
8
9 #include <hooks/hooks_config.h>
10 #include <hooks/hooks_manager.h>
11
12 using namespace std;
13 using namespace isc;
14 using namespace isc::data;
15
16 namespace isc {
17 namespace hooks {
18
19 void
verifyLibraries(const Element::Position & position) const20 HooksConfig::verifyLibraries(const Element::Position& position) const {
21 // The code used to follow this logic:
22 //
23 // Check if the list of libraries has changed. If not, nothing is done
24 // - the command "DhcpN libreload" is required to reload the same
25 // libraries (this prevents needless reloads when anything else in the
26 // configuration is changed).
27 //
28 // We no longer rely on this. Parameters can change. And even if the
29 // parameters stay the same, they could point to files that could
30 // change. We can skip loading routines only if there were and there still
31 // are no libraries specified.
32 vector<string> current_libraries = HooksManager::getLibraryNames();
33 if (current_libraries.empty() && libraries_.empty()) {
34 return;
35 }
36
37 // Library list has changed, validate each of the libraries specified.
38 vector<string> lib_names = isc::hooks::extractNames(libraries_);
39 vector<string> error_libs = HooksManager::validateLibraries(lib_names);
40 if (!error_libs.empty()) {
41
42 // Construct the list of libraries in error for the message.
43 string error_list = error_libs[0];
44 for (size_t i = 1; i < error_libs.size(); ++i) {
45 error_list += (string(", ") + error_libs[i]);
46 }
47 isc_throw(InvalidHooksLibraries,
48 "hooks libraries failed to validate - "
49 "library or libraries in error are: "
50 << error_list << " (" << position << ")");
51 }
52 }
53
54 void
loadLibraries() const55 HooksConfig::loadLibraries() const {
56 /// Commits the list of libraries to the configuration manager storage if
57 /// the list of libraries has changed.
58 /// @todo: Delete any stored CalloutHandles before reloading the
59 /// libraries
60 if (!HooksManager::loadLibraries(libraries_)) {
61 isc_throw(InvalidHooksLibraries,
62 "One or more hook libraries failed to load");
63 }
64 }
65
66 bool
equal(const HooksConfig & other) const67 HooksConfig::equal(const HooksConfig& other) const {
68
69 /// @todo: This comparision assumes that the library order is not relevant,
70 /// so [ lib1, lib2 ] is equal to [ lib2, lib1 ]. However, this is not strictly
71 /// true, because callouts execution is called in other they're loaded. Therefore
72 /// changing the libraries order may change the server behavior.
73 ///
74 /// We don't have any libraries that are interacting (or would change their behavior
75 /// depending on the order in which their callouts are executed), so the code is
76 /// ok for now.
77 for (isc::hooks::HookLibsCollection::const_iterator this_it = libraries_.begin();
78 this_it != libraries_.end(); ++this_it) {
79 bool match = false;
80 for (isc::hooks::HookLibsCollection::const_iterator other_it =
81 other.libraries_.begin(); other_it != other.libraries_.end(); ++other_it) {
82 if (this_it->first != other_it->first) {
83 continue;
84 }
85 if (isNull(this_it->second) && isNull(other_it->second)) {
86 match = true;
87 break;
88 }
89 if (isNull(this_it->second) || isNull(other_it->second)) {
90 continue;
91 }
92 if (this_it->second->equals(*other_it->second)) {
93 match = true;
94 break;
95 }
96 }
97 // No match found for the particular hooks library so return false.
98 if (!match) {
99 return (false);
100 }
101 }
102 return (true);
103 }
104
105 ElementPtr
toElement() const106 HooksConfig::toElement() const {
107 // hooks-libraries is a list of maps
108 ElementPtr result = Element::createList();
109 // Iterate through libraries
110 for (HookLibsCollection::const_iterator hl = libraries_.begin();
111 hl != libraries_.end(); ++hl) {
112 // Entries are maps
113 ElementPtr map = Element::createMap();
114 // Set the library name
115 map->set("library", Element::create(hl->first));
116 // Set parameters (not set vs set empty map)
117 if (!isNull(hl->second)) {
118 map->set("parameters", hl->second);
119 }
120 // Push to the list
121 result->add(map);
122 }
123 return (result);
124 }
125
126 };
127 };
128