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