Kea 2.6.2
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
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,
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;
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
it forwards queries to a single upstream resolver and passes the answers back to the client It is constructed with the address of the forward server Queries are initiated with the question to ask the forward a buffer into which to write the answer
Definition asiodns.dox:60
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.
virtual isc::data::ConstElementPtr shutdown(isc::data::ConstElementPtr args)
Initiates the process's shutdown process.
virtual ~CtrlAgentProcess()
Destructor.
Definition ca_process.cc:36
http::ConstHttpListenerPtr getHttpListener() const
Returns a const pointer to the HTTP listener used by the process.
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.
virtual isc::data::ConstElementPtr configure(isc::data::ConstElementPtr config_set, bool check_only=false)
Processes the given configuration.
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
void setShutdownFlag(bool value)
Sets the process shut down flag to the given value.
Definition d_process.h:162
DProcessBase(const char *app_name, asiolink::IOServicePtr io_service, DCfgMgrBasePtr cfg_mgr)
Constructor.
Definition d_process.h:87
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
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
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Parses a standard config/command level answer and returns arguments or text status code.
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(const int status_code, const std::string &text, const ConstElementPtr &arg)
Creates a standard config/command level answer message.
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...
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.
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