Kea  2.1.7-git
base_command_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2022 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>
12 #include <hooks/callout_handle.h>
13 #include <hooks/hooks_manager.h>
14 #include <functional>
15 
16 using namespace isc::data;
17 using namespace isc::hooks;
18 namespace ph = std::placeholders;
19 
20 namespace {
21 
23 struct BaseCommandMgrHooks {
24  int hook_index_command_processed_;
25 
27  BaseCommandMgrHooks() {
28  hook_index_command_processed_ = HooksManager::registerHook("command_processed");
29  }
30 };
31 
32 // Declare a Hooks object. As this is outside any function or method, it
33 // will be instantiated (and the constructor run) when the module is loaded.
34 // As a result, the hook indexes will be defined before any method in this
35 // module is called.
36 BaseCommandMgrHooks Hooks;
37 
38 }; // anonymous namespace
39 
40 namespace isc {
41 namespace config {
42 
43 BaseCommandMgr::BaseCommandMgr() {
44  registerCommand("list-commands", std::bind(&BaseCommandMgr::listCommandsHandler,
45  this, ph::_1, ph::_2));
46 }
47 
48 void
49 BaseCommandMgr::registerCommand(const std::string& cmd, CommandHandler handler) {
50  if (!handler) {
51  isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
52  }
53 
54  HandlerContainer::const_iterator it = handlers_.find(cmd);
55  if (it != handlers_.end()) {
56  isc_throw(InvalidCommandName, "Handler for command '" << cmd
57  << "' is already installed.");
58  }
59 
60  HandlersPair handlers;
61  handlers.handler = handler;
62  handlers_.insert(make_pair(cmd, handlers));
63 
65 }
66 
67 void
68 BaseCommandMgr::registerExtendedCommand(const std::string& cmd,
69  ExtendedCommandHandler handler) {
70  if (!handler) {
71  isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
72  }
73 
74  HandlerContainer::const_iterator it = handlers_.find(cmd);
75  if (it != handlers_.end()) {
76  isc_throw(InvalidCommandName, "Handler for command '" << cmd
77  << "' is already installed.");
78  }
79 
80  HandlersPair handlers;
81  handlers.extended_handler = handler;
82  handlers_.insert(make_pair(cmd, handlers));
83 
85 }
86 
87 void
88 BaseCommandMgr::deregisterCommand(const std::string& cmd) {
89  if (cmd == "list-commands") {
91  "Can't uninstall internal command 'list-commands'");
92  }
93 
94  HandlerContainer::iterator it = handlers_.find(cmd);
95  if (it == handlers_.end()) {
96  isc_throw(InvalidCommandName, "Handler for command '" << cmd
97  << "' not found.");
98  }
99  handlers_.erase(it);
100 
102 }
103 
104 void
105 BaseCommandMgr::deregisterAll() {
106 
107  // No need to log anything here. deregisterAll is not used in production
108  // code, just in tests.
109  handlers_.clear();
110  registerCommand("list-commands",
111  std::bind(&BaseCommandMgr::listCommandsHandler, this, ph::_1, ph::_2));
112 }
113 
115 BaseCommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) {
116  if (!cmd) {
118  "Command processing failed: NULL command parameter"));
119  }
120 
121  try {
122  ConstElementPtr arg;
123  std::string name = parseCommand(arg, cmd);
124 
126 
127  ConstElementPtr response = handleCommand(name, arg, cmd);
128 
129  // If there any callouts for command-processed hook point call them
130  if (HooksManager::calloutsPresent(Hooks.hook_index_command_processed_)) {
131  // Commands are not associated with anything so there's no pre-existing
132  // callout.
133  CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
134 
135  // Add the command name, arguments, and response to the callout context
136  callout_handle->setArgument("name", name);
137  callout_handle->setArgument("arguments", arg);
138  callout_handle->setArgument("response", response);
139 
140  // Call callouts
141  HooksManager::callCallouts(Hooks.hook_index_command_processed_,
142  *callout_handle);
143 
144  // Refresh the response from the callout context in case it was modified.
145  // @todo Should we allow this?
146  callout_handle->getArgument("response", response);
147  }
148 
149  return (response);
150 
151  } catch (const Exception& e) {
154  std::string("Error during command processing: ")
155  + e.what()));
156  }
157 }
158 
160 BaseCommandMgr::handleCommand(const std::string& cmd_name,
161  const ConstElementPtr& params,
162  const ConstElementPtr& original_cmd) {
163  auto it = handlers_.find(cmd_name);
164  if (it == handlers_.end()) {
165  // Ok, there's no such command.
167  "'" + cmd_name + "' command not supported."));
168  }
169 
170  // Call the actual handler and return whatever it returned
171  if (it->second.handler) {
172  return (it->second.handler(cmd_name, params));
173  }
174  return (it->second.extended_handler(cmd_name, params, original_cmd));
175 }
176 
178 BaseCommandMgr::listCommandsHandler(const std::string& /* name */,
179  const isc::data::ConstElementPtr& ) {
180  using namespace isc::data;
181  ElementPtr commands = Element::createList();
182  for (HandlerContainer::const_iterator it = handlers_.begin();
183  it != handlers_.end(); ++it) {
184  commands->add(Element::create(it->first));
185  }
186  return (createAnswer(CONTROL_RESULT_SUCCESS, commands));
187 }
188 
189 
190 } // namespace isc::config
191 } // namespace isc
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
const isc::log::MessageID COMMAND_DEREGISTERED
const isc::log::MessageID COMMAND_REGISTERED
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
const int DBG_COMMAND
Definition: config_log.h:24
const isc::log::MessageID COMMAND_PROCESS_ERROR2
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:281
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
isc::log::Logger command_logger("commands")
Command processing Logger.
Definition: config_log.h:21
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
const isc::log::MessageID COMMAND_RECEIVED
Exception indicating that the command name is not valid.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-lfc.
std::string parseCommand(ConstElementPtr &arg, ConstElementPtr command)
const isc::log::MessageID COMMAND_EXTENDED_REGISTERED
Exception indicating that the handler specified is not valid.
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
This file contains several functions and constants that are used for handling commands and responses ...
CtrlAgentHooks Hooks
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:241
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.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
std::function< isc::data::ConstElementPtr(const std::string &name, const isc::data::ConstElementPtr &params)> CommandHandler
Defines command handler type.
const int CONTROL_RESULT_COMMAND_UNSUPPORTED
Status code indicating that the specified command is not supported.