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