Kea 2.6.0
ca_process.cc
Go to the documentation of this file.
1// Copyright (C) 2016-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>
10#include <agent/ca_process.h>
11#include <agent/ca_controller.h>
13#include <agent/ca_log.h>
14#include <asiolink/io_address.h>
15#include <asiolink/io_error.h>
17#include <config/timeouts.h>
18#include <boost/pointer_cast.hpp>
19
20using namespace isc::asiolink;
21using namespace isc::config;
22using namespace isc::data;
23using namespace isc::http;
24using namespace isc::process;
25
26
27namespace isc {
28namespace agent {
29
31 const asiolink::IOServicePtr& io_service)
32 : DProcessBase(name, io_service, DCfgMgrBasePtr(new CtrlAgentCfgMgr())),
33 http_listeners_() {
34}
35
37 garbageCollectListeners(0);
38}
39
40void
42}
43
44void
47
48 try {
49 // Register commands.
50 CtrlAgentControllerPtr controller =
51 boost::dynamic_pointer_cast<CtrlAgentController>(
53 controller->registerCommands();
54
55 // Let's process incoming data or expiring timers in a loop until
56 // shutdown condition is detected.
57 while (!shouldShutdown()) {
58 // Remove unused listeners within the main loop because new listeners
59 // are created in within a callback method. This avoids removal the
60 // listeners within a callback.
61 garbageCollectListeners(1);
62 runIO();
63 }
64 // Done so removing all listeners.
65 garbageCollectListeners(0);
67 } catch (const std::exception& ex) {
69 try {
71 } catch (...) {
72 // Ignore double errors
73 }
75 "Process run method failed: " << ex.what());
76 }
77
78 try {
79 // Deregister commands.
80 CtrlAgentControllerPtr controller =
81 boost::dynamic_pointer_cast<CtrlAgentController>(
83 controller->deregisterCommands();
84 } catch (const std::exception&) {
85 // What to do? Simply ignore...
86 }
87
89}
90
91size_t
92CtrlAgentProcess::runIO() {
93 // Handle events registered by hooks using external IOService objects.
95 size_t cnt = getIOService()->poll();
96 if (!cnt) {
97 cnt = getIOService()->runOne();
98 }
99 return (cnt);
100}
101
104 setShutdownFlag(true);
106 "Control Agent is shutting down"));
107}
108
111 bool check_only) {
112 // System reconfiguration often poses an interesting issue whereby the
113 // configuration parsing is successful, but an attempt to use a new
114 // configuration is not. This will leave us in the inconsistent state
115 // when the configuration is in fact only partially applied and the
116 // system's ability to operate is impaired. The use of C++ lambda is
117 // a way to resolve this problem by injecting the code to the
118 // simpleParseConfig which performs an attempt to open new instance
119 // of the listener (if required). The lambda code will throw an
120 // exception if it fails and cause the simpleParseConfig to rollback
121 // configuration changes and report an error.
122 ConstElementPtr answer = getCfgMgr()->simpleParseConfig(config_set,
123 check_only,
124 [this]() {
125 ConfigPtr base_ctx = getCfgMgr()->getContext();
127 ctx = boost::dynamic_pointer_cast<CtrlAgentCfgContext>(base_ctx);
128
129 if (!ctx) {
130 isc_throw(Unexpected, "Internal logic error: bad context type");
131 }
132
134 IOAddress server_address("::");
135 try {
136 server_address = IOAddress(ctx->getHttpHost());
137
138 } catch (const IOError& e) {
139 isc_throw(BadValue, "Failed to convert " << ctx->getHttpHost()
140 << " to IP address:" << e.what());
141 }
142
143 uint16_t server_port = ctx->getHttpPort();
144 bool use_https = false;
145
146 // Only open a new listener if the configuration has changed.
147 if (http_listeners_.empty() ||
148 (http_listeners_.back()->getLocalAddress() != server_address) ||
149 (http_listeners_.back()->getLocalPort() != server_port)) {
150 // Create a TLS context.
151 TlsContextPtr tls_context;
152 // When TLS is enabled configure it.
153 if (!ctx->getCertFile().empty()) {
154 TlsContext::configure(tls_context,
155 TlsRole::SERVER,
156 ctx->getTrustAnchor(),
157 ctx->getCertFile(),
158 ctx->getKeyFile(),
159 ctx->getCertRequired());
160 use_https = true;
161 }
162
163 // Create response creator factory first. It will be used to
164 // generate response creators. Each response creator will be
165 // used to generate answer to specific request.
167
168 // Create http listener. It will open up a TCP socket and be
169 // prepared to accept incoming connection.
170 HttpListenerPtr http_listener
171 (new HttpListener(getIOService(), server_address,
172 server_port, tls_context, rcf,
175
176 // Instruct the http listener to actually open socket, install
177 // callback and start listening.
178 http_listener->start();
179
180 // The new listener is running so add it to the collection of
181 // active listeners. The next step will be to remove all other
182 // active listeners, but we do it inside the main process loop.
183 http_listeners_.push_back(http_listener);
184 }
185
186 // Ok, seems we're good to go.
187 if (use_https) {
189 .arg(server_address.toText()).arg(server_port);
190 } else {
192 .arg(server_address.toText()).arg(server_port);
193 }
194 });
195
196 int rcode = 0;
197 config::parseAnswer(rcode, answer);
198
200 try {
201 // Handle events registered by hooks using external IOService objects.
203 } catch (const std::exception& ex) {
204 std::ostringstream err;
205 err << "Error initializing hooks: "
206 << ex.what();
208 }
209
210 return (answer);
211}
212
213void
214CtrlAgentProcess::garbageCollectListeners(size_t leaving) {
215 // We expect only one active listener. If there are more (most likely 2),
216 // it means we have just reconfigured the server and need to shut down all
217 // listeners except the most recently added.
218 if (http_listeners_.size() > leaving) {
219 // Stop no longer used listeners.
220 for (auto l = http_listeners_.begin(); l != http_listeners_.end() - leaving; ++l) {
221 (*l)->stop();
222 }
223 // We have stopped listeners but there may be some pending handlers
224 // related to these listeners. Need to invoke these handlers.
225 try {
226 getIOService()->poll();
227 } catch (...) {
228 }
229 // Finally, we're ready to remove no longer used listeners.
230 http_listeners_.erase(http_listeners_.begin(),
231 http_listeners_.end() - leaving);
232 }
233}
234
237 return (boost::dynamic_pointer_cast<CtrlAgentCfgMgr>(getCfgMgr()));
238}
239
242 // Return the most recent listener or null.
243 return (http_listeners_.empty() ? ConstHttpListenerPtr() :
244 http_listeners_.back());
245}
246
247bool
249 // If there are is a listener, we're listening.
250 return (static_cast<bool>(getHttpListener()));
251}
252
253} // namespace isc::agent
254} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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.
Ctrl Agent Configuration Manager.
Definition: ca_cfg_mgr.h:253
static process::DControllerBasePtr & instance()
Static singleton instance method.
bool isListening() const
Checks if the process is listening to the HTTP requests.
Definition: ca_process.cc:248
virtual isc::data::ConstElementPtr shutdown(isc::data::ConstElementPtr args)
Initiates the process's shutdown process.
Definition: ca_process.cc:103
virtual ~CtrlAgentProcess()
Destructor.
Definition: ca_process.cc:36
http::ConstHttpListenerPtr getHttpListener() const
Returns a const pointer to the HTTP listener used by the process.
Definition: ca_process.cc:241
CtrlAgentProcess(const char *name, const asiolink::IOServicePtr &io_service)
Constructor.
Definition: ca_process.cc:30
virtual void init()
Initialize the Control Agent process.
Definition: ca_process.cc:41
CtrlAgentCfgMgrPtr getCtrlAgentCfgMgr()
Returns a pointer to the configuration manager.
Definition: ca_process.cc:236
virtual isc::data::ConstElementPtr configure(isc::data::ConstElementPtr config_set, bool check_only=false)
Processes the given configuration.
Definition: ca_process.cc:110
virtual void run()
Implements the process's event loop.
Definition: ca_process.cc:45
HTTP response creator factory for Control Agent.
HTTP listener.
Definition: listener.h:52
Exception thrown if the process encountered an operational error.
Definition: d_process.h:24
Application Process Interface.
Definition: d_process.h:75
void setShutdownFlag(bool value)
Sets the process shut down flag to the given value.
Definition: d_process.h:162
void stopIOService()
Convenience method for stopping IOservice processing.
Definition: d_process.h:184
bool shouldShutdown() const
Checks if the process has been instructed to shut down.
Definition: d_process.h:155
asiolink::IOServicePtr & getIOService()
Fetches the controller's IOService.
Definition: d_process.h:176
DCfgMgrBasePtr & getCfgMgr()
Fetches the process's configuration manager.
Definition: d_process.h:191
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_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition: macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< CtrlAgentCfgContext > CtrlAgentCfgContextPtr
Pointer to a configuration context.
Definition: ca_cfg_mgr.h:23
const isc::log::MessageID CTRL_AGENT_HTTP_SERVICE_STARTED
Definition: ca_messages.h:20
const isc::log::MessageID CTRL_AGENT_STARTED
Definition: ca_messages.h:22
isc::log::Logger agent_logger("ctrl-agent")
Control Agent logger.
Definition: ca_log.h:18
boost::shared_ptr< CtrlAgentCfgMgr > CtrlAgentCfgMgrPtr
Defines a shared pointer to CtrlAgentCfgMgr.
Definition: ca_cfg_mgr.h:311
boost::shared_ptr< CtrlAgentController > CtrlAgentControllerPtr
Definition: ca_controller.h:80
const isc::log::MessageID CTRL_AGENT_HTTPS_SERVICE_STARTED
Definition: ca_messages.h:19
const isc::log::MessageID CTRL_AGENT_RUN_EXIT
Definition: ca_messages.h:21
const isc::log::MessageID CTRL_AGENT_FAILED
Definition: ca_messages.h:18
constexpr long TIMEOUT_AGENT_IDLE_CONNECTION_TIMEOUT
Timeout for the idle connection to be closed.
Definition: timeouts.h:24
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
constexpr long TIMEOUT_AGENT_RECEIVE_COMMAND
Timeout for the Control Agent to receive command over the RESTful interface.
Definition: timeouts.h:21
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
boost::shared_ptr< const HttpListener > ConstHttpListenerPtr
Pointer to the const HttpListener.
Definition: listener.h:142
boost::shared_ptr< HttpListener > HttpListenerPtr
Pointer to the HttpListener.
Definition: listener.h:139
boost::shared_ptr< HttpResponseCreatorFactory > HttpResponseCreatorFactoryPtr
Pointer to the HttpResponseCreatorFactory.
const int DBGLVL_START_SHUT
This is given a value of 0 as that is the level selected if debugging is enabled without giving a lev...
Definition: log_dbglevels.h:50
boost::shared_ptr< DCfgMgrBase > DCfgMgrBasePtr
Defines a shared pointer to DCfgMgrBase.
Definition: d_cfg_mgr.h:247
boost::shared_ptr< ConfigBase > ConfigPtr
Non-const pointer to the ConfigBase.
Definition: config_base.h:176
Defines the logger used by the top-level component of kea-lfc.
Idle connection timeout.
Definition: listener.h:67
HTTP request timeout value.
Definition: listener.h:56