Kea 2.7.6
base_command_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2024 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
11#include <config/config_log.h>
14#include <hooks/hooks_manager.h>
15#include <util/encode/encode.h>
16#include <util/buffer.h>
17#include <functional>
18#include <vector>
19
20using namespace isc::data;
21using namespace isc::hooks;
22namespace ph = std::placeholders;
23
24namespace {
25
27struct BaseCommandMgrHooks {
28 int hook_index_command_processed_;
29
31 BaseCommandMgrHooks() {
32 hook_index_command_processed_ = HooksManager::registerHook("command_processed");
33 }
34};
35
36// Declare a Hooks object. As this is outside any function or method, it
37// will be instantiated (and the constructor run) when the module is loaded.
38// As a result, the hook indexes will be defined before any method in this
39// module is called.
40BaseCommandMgrHooks Hooks;
41
42} // anonymous namespace
43
44namespace isc {
45namespace config {
46
48 registerCommand("list-commands", std::bind(&BaseCommandMgr::listCommandsHandler,
49 this, ph::_1, ph::_2));
50}
51
52void
53BaseCommandMgr::registerCommand(const std::string& cmd, CommandHandler handler) {
54 if (!handler) {
55 isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
56 }
57
58 HandlerContainer::const_iterator it = handlers_.find(cmd);
59 if (it != handlers_.end()) {
60 isc_throw(InvalidCommandName, "Handler for command '" << cmd
61 << "' is already installed.");
62 }
63
64 HandlersPair handlers;
65 handlers.handler = handler;
66 handlers_.insert(make_pair(cmd, handlers));
67
69}
70
71void
73 ExtendedCommandHandler handler) {
74 if (!handler) {
75 isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
76 }
77
78 HandlerContainer::const_iterator it = handlers_.find(cmd);
79 if (it != handlers_.end()) {
80 isc_throw(InvalidCommandName, "Handler for command '" << cmd
81 << "' is already installed.");
82 }
83
84 HandlersPair handlers;
85 handlers.extended_handler = handler;
86 handlers_.insert(make_pair(cmd, handlers));
87
89}
90
91void
92BaseCommandMgr::deregisterCommand(const std::string& cmd) {
93 if (cmd == "list-commands") {
95 "Can't uninstall internal command 'list-commands'");
96 }
97
98 HandlerContainer::iterator it = handlers_.find(cmd);
99 if (it == handlers_.end()) {
100 isc_throw(InvalidCommandName, "Handler for command '" << cmd
101 << "' not found.");
102 }
103 handlers_.erase(it);
104
106}
107
108void
110
111 // No need to log anything here. deregisterAll is not used in production
112 // code, just in tests.
113 handlers_.clear();
114 registerCommand("list-commands",
115 std::bind(&BaseCommandMgr::listCommandsHandler, this, ph::_1, ph::_2));
116}
117
120 if (!cmd) {
122 "Command processing failed: NULL command parameter"));
123 }
124
125 try {
126 ConstElementPtr arg;
127 std::string name = parseCommand(arg, cmd);
128
130
131 ConstElementPtr response = handleCommand(name, arg, cmd);
132
133 // If there any callouts for command-processed hook point call them
134 if (HooksManager::calloutsPresent(Hooks.hook_index_command_processed_)) {
135 // Commands are not associated with anything so there's no pre-existing
136 // callout.
138
139 // Add the command name, arguments, and response to the callout context
140 callout_handle->setArgument("name", name);
141 callout_handle->setArgument("arguments", arg);
142 callout_handle->setArgument("response", response);
143
144 // Call callouts
145 HooksManager::callCallouts(Hooks.hook_index_command_processed_,
146 *callout_handle);
147
148 // Refresh the response from the callout context in case it was modified.
149 // @todo Should we allow this?
150 callout_handle->getArgument("response", response);
151 }
152
153 return (response);
154
155 } catch (const Exception& e) {
158 std::string("Error during command processing: ")
159 + e.what()));
160 }
161}
162
164BaseCommandMgr::handleCommand(const std::string& cmd_name,
165 const ConstElementPtr& params,
166 const ConstElementPtr& original_cmd) {
167 auto it = handlers_.find(cmd_name);
168 if (it == handlers_.end()) {
169 // Ok, there's no such command.
171 "'" + cmd_name + "' command not supported."));
172 }
173
174 // Call the actual handler and return whatever it returned
175 if (it->second.handler) {
176 return (it->second.handler(cmd_name, params));
177 }
178 return (it->second.extended_handler(cmd_name, params, original_cmd));
179}
180
182BaseCommandMgr::listCommandsHandler(const std::string& /* name */,
184 using namespace isc::data;
185 ElementPtr commands = Element::createList();
186 for (auto const& it : handlers_) {
187 commands->add(Element::create(it.first));
188 }
189 return (createAnswer(CONTROL_RESULT_SUCCESS, commands));
190}
191
192std::string
194
195 // Sanity.
196 if (!config) {
197 isc_throw(Unexpected, "BaseCommandMgr::getHash called with null");
198 }
199
200 // First, get the string representation.
201 std::string config_txt = config->str();
202 isc::util::OutputBuffer hash_data(0);
203 isc::cryptolink::digest(config_txt.c_str(),
204 config_txt.size(),
206 hash_data);
207
208 // Now we need to convert this to output buffer to vector, which can be accepted
209 // by encodeHex().
210 std::vector<uint8_t> hash;
211 hash.resize(hash_data.getLength());
212 if (hash.size() > 0) {
213 memmove(&hash[0], hash_data.getData(), hash.size());
214 }
215
216 // Now encode the value as base64 and we're done here.
217 return (isc::util::encode::encodeHex(hash));
218}
219
220} // namespace isc::config
221} // namespace isc
CtrlAgentHooks Hooks
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
HandlerContainer handlers_
Container for command handlers.
virtual isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr &cmd)
Triggers command processing.
std::function< isc::data::ConstElementPtr(const std::string &name, const isc::data::ConstElementPtr &params)> CommandHandler
Defines command handler type.
void registerCommand(const std::string &cmd, CommandHandler handler)
Registers specified command handler for a given command.
static std::string getHash(const isc::data::ConstElementPtr &config)
returns a hash of a given Element structure
void deregisterAll()
Auxiliary method that removes all installed commands.
void registerExtendedCommand(const std::string &cmd, ExtendedCommandHandler handler)
Registers specified command handler for a given command.
virtual isc::data::ConstElementPtr handleCommand(const std::string &cmd_name, const isc::data::ConstElementPtr &params, const isc::data::ConstElementPtr &original_cmd)
Handles the command having a given name and arguments.
std::function< isc::data::ConstElementPtr(const std::string &name, const isc::data::ConstElementPtr &params, const isc::data::ConstElementPtr &original)> ExtendedCommandHandler
Defines extended command handler type.
void deregisterCommand(const std::string &cmd)
Deregisters specified command handler.
Exception indicating that the handler specified is not valid.
Exception indicating that the command name is not valid.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
static int registerHook(const std::string &name)
Register Hook.
static bool calloutsPresent(int index)
Are callouts present?
static boost::shared_ptr< CalloutHandle > createCalloutHandle()
Return callout handle.
static void callCallouts(int index, CalloutHandle &handle)
Calls the callouts for a given hook.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:343
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition buffer.h:395
size_t getLength() const
Return the length of data written in the buffer.
Definition buffer.h:409
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const isc::log::MessageID COMMAND_EXTENDED_REGISTERED
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
const isc::log::MessageID COMMAND_DEREGISTERED
std::string parseCommand(ConstElementPtr &arg, ConstElementPtr command)
Parses the given command into a string containing the actual command and an ElementPtr containing the...
const isc::log::MessageID COMMAND_RECEIVED
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const isc::log::MessageID COMMAND_PROCESS_ERROR2
const int CONTROL_RESULT_COMMAND_UNSUPPORTED
Status code indicating that the specified command is not supported.
const isc::log::MessageID COMMAND_REGISTERED
const int DBG_COMMAND
Definition config_log.h:24
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
isc::log::Logger command_logger("commands")
Command processing Logger.
Definition config_log.h:21
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 format.
Definition encode.cc:361
Defines the logger used by the top-level component of kea-lfc.