summaryrefslogtreecommitdiffstats
path: root/src/lib/config/base_command_mgr.h
blob: 916eebcc0fd93ed075e0d0b9753c444d9967c410 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Copyright (C) 2017-2023 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef BASE_COMMAND_MGR_H
#define BASE_COMMAND_MGR_H

#include <cc/data.h>
#include <exceptions/exceptions.h>
#include <functional>
#include <map>
#include <string>

namespace isc {
namespace config {

/// @brief Exception indicating that the handler specified is not valid
class InvalidCommandHandler : public Exception {
public:
    InvalidCommandHandler(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Exception indicating that the command name is not valid
class InvalidCommandName : public Exception {
public:
    InvalidCommandName(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Commands Manager, responsible for processing external commands.
///
/// Commands Manager is a generic interface for handling external commands.
/// Commands are received over control sockets. Derivations of this class
/// provide implementations of the control socket layers, e.g. unix domain
/// sockets, TCP sockets etc. This base class merely provides methods to manage
/// command handling functions, i.e. register commands, deregister commands.
/// It also includes a @ref BaseCommandMgr::processCommand method which
/// uses the command as an input and invokes appropriate handlers.
///
/// The commands and responses are formatted using JSON.
/// See https://gitlab.isc.org/isc-projects/kea/wikis/designs/Stats-design
/// for details.
///
/// Below is an example of the command using JSON format:
/// @code
/// {
///     "command": "statistic-get",
///     "arguments": {
///         "name": "received-packets"
///     }
/// }
/// @endcode
///
/// And the response is:
///
/// @code
/// {
///     "result": 0,
///     "arguments": {
///         "received-packets": [ [ 1234, "2015-04-15 12:34:45.123" ] ]
///     }
/// }
/// @endcode
///
/// BaseCommandsMgr does not implement the commands (except one,
/// "list-commands") itself, but rather provides an interface
/// (see @ref registerCommand, @ref deregisterCommand, @ref processCommand)
/// for other components to use it.
class BaseCommandMgr {
public:

    /// @brief Defines command handler type
    ///
    /// Command handlers are expected to use this format.
    ///
    /// @param name name of the commands
    /// @param params parameters specific to the command
    /// @return response (created with createAnswer())
    typedef std::function<isc::data::ConstElementPtr (const std::string& name,
        const isc::data::ConstElementPtr& params)> CommandHandler;

    /// @brief Defines extended command handler type.
    ///
    /// This command handler includes third parameter which holds the
    /// entire command control message. The handler can retrieve
    /// additional information from this parameter, e.g. 'service'.
    ///
    /// @param name name of the commands
    /// @param params parameters specific to the command
    /// @param original original control command.
    /// @return response (created with createAnswer())
    typedef std::function<isc::data::ConstElementPtr (const std::string& name,
        const isc::data::ConstElementPtr& params,
        const isc::data::ConstElementPtr& original)> ExtendedCommandHandler;

    /// @brief Constructor.
    ///
    /// Registers hookpoint "command-processed"
    /// Registers "list-commands" command.
    BaseCommandMgr();

    /// @brief Destructor.
    virtual ~BaseCommandMgr() { };

    /// @brief Triggers command processing.
    ///
    /// This method processes specified command. The command is specified using
    /// a single Element. See @ref BaseCommandMgr for description of its syntax.
    /// After the command has been handled, callouts for the hook point,
    /// "command-processed" will be invoked.
    ///
    /// This method is virtual so it can be overridden in derived classes to
    /// pre-process command and post-process response if necessary.
    ///
    /// This method is an entry point for dealing with a command. Internally
    /// it calls @c BaseCommandMgr::handleCommand.
    ///
    /// @param cmd Pointer to the data element representing command in JSON
    /// format.
    virtual isc::data::ConstElementPtr
    processCommand(const isc::data::ConstElementPtr& cmd);

    /// @brief Registers specified command handler for a given command
    ///
    /// @param cmd Name of the command to be handled.
    /// @param handler Pointer to the method that will handle the command.
    void registerCommand(const std::string& cmd, CommandHandler handler);

    /// @brief Registers specified command handler for a given command.
    ///
    /// This variant of the method uses extended command handler which, besides
    /// command name and arguments, also has a third parameter 'original_cmd'
    /// in its signature. Such handlers can retrieve additional parameters from
    /// the command, e.g. 'service' indicating where the command should be
    /// routed.
    ///
    /// @param cmd Name of the command to be handled.
    /// @param handler Pointer to the method that will handle the command.
    void registerExtendedCommand(const std::string& cmd,
                                 ExtendedCommandHandler handler);

    /// @brief Deregisters specified command handler.
    ///
    /// @param cmd Name of the command that's no longer handled.
    void deregisterCommand(const std::string& cmd);

    /// @brief Auxiliary method that removes all installed commands.
    ///
    /// The only unwipeable method is list-commands, which is internally
    /// handled at all times.
    void deregisterAll();

    /// @brief returns a hash of a given Element structure
    ///
    /// The hash is currently implemented as SHA256 on the string
    // representation of the structure.
    ///
    /// @param config typically full config, but hash can be calculated on any structure
    /// @return hash of string representation
    static std::string getHash(const isc::data::ConstElementPtr& config);

protected:

    /// @brief Handles the command having a given name and arguments.
    ///
    /// This method can be overridden in the derived classes to provide
    /// custom logic for processing commands. For example, the
    /// @ref HookedCommandMgr extends this method to delegate commands
    /// processing to a hook library.
    ///
    /// @param cmd_name Command name.
    /// @param params Command arguments.
    /// @param original_cmd Pointer to the entire command received. It may
    /// be sometimes useful to retrieve additional parameters from this
    /// command.
    ///
    /// @return Pointer to the const data element representing response
    /// to a command.
    virtual isc::data::ConstElementPtr
    handleCommand(const std::string& cmd_name,
                  const isc::data::ConstElementPtr& params,
                  const isc::data::ConstElementPtr& original_cmd);

    struct HandlersPair {
        CommandHandler handler;
        ExtendedCommandHandler extended_handler;
    };

    /// @brief Type of the container for command handlers.
    typedef std::map<std::string, HandlersPair> HandlerContainer;

    /// @brief Container for command handlers.
    HandlerContainer handlers_;

private:

    /// @brief 'list-commands' command handler.
    ///
    /// This method implements command 'list-commands'. It returns a list of all
    /// currently supported commands.
    ///
    /// @param name Name of the command (should always be 'list-commands').
    /// @param params Additional parameters (ignored).
    ///
    /// @return Pointer to the structure that includes all currently supported
    /// commands.
    isc::data::ConstElementPtr
    listCommandsHandler(const std::string& name,
                        const isc::data::ConstElementPtr& params);
};

} // end of namespace isc::config
} // end of namespace isc

#endif