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>
13#include <hooks/hooks_manager.h>
14#include <boost/bind.hpp>
15
16using namespace isc::data;
17using namespace isc::hooks;
18
19namespace {
20
22struct 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.
35BaseCommandMgrHooks Hooks;
36
37}; // anonymous namespace
38
39namespace isc {
40namespace config {
41
43 registerCommand("list-commands", boost::bind(&BaseCommandMgr::listCommandsHandler,
44 this, _1, _2));
45}
46
47void
48BaseCommandMgr::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
66void
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
86void
87BaseCommandMgr::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
103void
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
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.
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
159BaseCommandMgr::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
177BaseCommandMgr::listCommandsHandler(const std::string& /* name */,
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
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.
HandlerContainer handlers_
Container for command handlers.
isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr &cmd)
Triggers command processing.
void registerCommand(const std::string &cmd, CommandHandler handler)
Registers specified command handler for a given command.
void deregisterAll()
Auxiliary method that removes all installed commands.
boost::function< isc::data::ConstElementPtr(const std::string &name, const isc::data::ConstElementPtr &params)> CommandHandler
Defines command handler type.
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.
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.
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:223
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:263
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.
This file contains several functions and constants that are used for handling commands and responses ...
Dhcp4Hooks Hooks
Definition: dhcp4_srv.cc:117
#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 int CONTROL_RESULT_ERROR
Status code indicating a general failure.
std::string parseCommand(ConstElementPtr &arg, ConstElementPtr command)
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_COMMAND_UNSUPPORTED
Status code indicating that the specified command is not supported.
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:23
boost::shared_ptr< Element > ElementPtr
Definition: data.h:22
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
Defines the logger used by the top-level component of kea-dhcp-ddns.