2021-02-19 17:24:29 +01:00
|
|
|
// Copyright (C) 2016-2021 Internet Systems Consortium, Inc. ("ISC")
|
2016-12-01 16:29:07 +01:00
|
|
|
//
|
|
|
|
// 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/.
|
|
|
|
|
|
|
|
/**
|
|
|
|
@page libprocess libkea-process - Controllable Process Layer (CPL)
|
|
|
|
|
|
|
|
@section cpl Controllable Process Layer (CPL)
|
2016-12-02 10:09:02 -05:00
|
|
|
During the design and development of D2 (Kea's DHCP-DDNS process), an abstract
|
|
|
|
layer for process control, called the Controllable Process Layer or CPL, was
|
|
|
|
created. Kea's DHCP servers were initially developed prior to D2 and thus
|
2016-12-02 16:38:50 +01:00
|
|
|
before CPL existed.
|
2016-12-02 10:09:02 -05:00
|
|
|
|
|
|
|
Out of short term convenience and the fact that only D2 was using it, the CPL
|
|
|
|
was initially developed as part of D2 in src/bin/d2. In order to use CPL for
|
|
|
|
new Kea processes, it has since been moved into its own library, libkea-process.
|
|
|
|
The following sections describe the architecture of CPL and how it can be used to implement new daemons in Kea.
|
2016-12-01 16:29:07 +01:00
|
|
|
|
2016-12-02 10:09:02 -05:00
|
|
|
The CPL provides the essentials for a controllable, configurable,
|
2016-12-01 16:29:07 +01:00
|
|
|
asynchronous process. They are the result of an effort to distill the
|
|
|
|
common facets of process control currently duplicated in Kea's
|
|
|
|
DHCP servers into a reusable construct. The classes which form this abstract
|
|
|
|
base are shown in the following class diagram:
|
|
|
|
|
|
|
|
@image html abstract_app_classes.svg "Controllable Process Layer Classes"
|
|
|
|
|
|
|
|
- isc::process::DControllerBase - provides all of the services necessary to manage
|
|
|
|
an application process class derived from isc::d2::DProcess. These services include:
|
|
|
|
- Command line argument handling
|
|
|
|
- Process instantiation and initialization
|
|
|
|
- Support for stand-alone execution
|
|
|
|
- Process event loop invocation and shutdown
|
|
|
|
|
|
|
|
It creates and manages an instance of isc::process::DProcessBase. The CPL is
|
|
|
|
designed for asynchronous event processing applications. It is constructed
|
|
|
|
to use ASIO library for IO processing. @c DControllerBase owns an
|
|
|
|
isc::asiolink::IOService instance and it passes this into the @c
|
|
|
|
DProcessBase constructor. It is this @c IOService that is used to drive the
|
|
|
|
process's event loop. The controller is designed to provide any interfaces
|
|
|
|
between the process it controls and the outside world.
|
|
|
|
|
|
|
|
@c DControllerBase provides configuration for its process via a JSON file
|
|
|
|
specified as a mandatory command line argument. The file structure is
|
|
|
|
expected be as follows:
|
|
|
|
|
|
|
|
{ "<module-name>": {<module-config>} }
|
|
|
|
|
|
|
|
where:
|
|
|
|
- module-name : is a label which uniquely identifies the
|
|
|
|
configuration data for the (i.e. the controlled process.)
|
|
|
|
It is the value returned by @ref
|
|
|
|
isc::process::DControllerBase::getAppName()
|
|
|
|
|
|
|
|
- module-config: a set of zero or more JSON elements which comprise
|
|
|
|
application's configuration values. Element syntax is governed
|
|
|
|
by those elements supported in isc::cc.
|
|
|
|
|
|
|
|
The file may contain an arbitrary number of other modules.
|
|
|
|
|
|
|
|
@todo Eventually, some sort of secure socket interface which supports remote
|
|
|
|
control operations such as configuration changes or status reporting will
|
|
|
|
likely be implemented.
|
|
|
|
|
|
|
|
- isc::process::DProcessBase - defines an asynchronous-event processor (i.e.
|
|
|
|
application) which provides a uniform interface to:
|
|
|
|
- Instantiate and initialize a process instance
|
|
|
|
- "Run" the application by starting its event loop
|
|
|
|
- Inject events to control the process
|
|
|
|
It owns an instance of @c DCfgMgrBase.
|
|
|
|
|
|
|
|
- isc::process::DCfgMgrBase - provides the mechanisms for managing an application's
|
|
|
|
configuration. This includes services for parsing sets of configuration
|
|
|
|
values, storing the parsed information in its converted form, and retrieving
|
|
|
|
the information on demand. It owns an instance of @c DCfgContextBase, which
|
|
|
|
provides a "global" context for information that is accessible before, during,
|
|
|
|
and after parsing.
|
|
|
|
|
|
|
|
- isc::process::DCfgContextBase - implements a container for configuration
|
|
|
|
information or "context". It provides a single enclosure for the storage of
|
|
|
|
configuration parameters or any other information that needs to accessible
|
|
|
|
within a given context.
|
|
|
|
|
|
|
|
The following sequence diagram shows how a configuration from file moves
|
|
|
|
through the CPL layer:
|
|
|
|
|
|
|
|
@image html config_from_file_sequence.svg "CPL Configuration From File Sequence"
|
|
|
|
|
|
|
|
The CPL classes will likely move into a common library.
|
|
|
|
|
|
|
|
@section cplSignals CPL Signal Handling
|
|
|
|
|
|
|
|
CPL supports interaction with the outside world via OS signals. The default
|
|
|
|
implementation supports the following signal driven behavior:
|
|
|
|
- SIGHUP receipt of this signal will cause a reloading of the configuration
|
|
|
|
file.
|
|
|
|
- SIGINT/SIGTERM receipt of either of these signals will initiate an
|
|
|
|
orderly shutdown.
|
|
|
|
|
|
|
|
CPL applications wait for for process asynchronous IO events through
|
|
|
|
isc::asiolink::IOService::run() or its variants. These calls are not
|
|
|
|
interrupted upon signal receipt as is the select() function and while
|
|
|
|
boost::asio provides a signal mechanism it requires linking in additional
|
|
|
|
libraries. Therefore, CPL provides its own signal handling mechanism to
|
2017-07-23 16:26:52 -04:00
|
|
|
propagate an OS signal such as SIGHUP to an IOService as a ready event with a
|
2016-12-01 16:29:07 +01:00
|
|
|
callback.
|
|
|
|
|
|
|
|
isc::process::DControllerBase uses two mechanisms to carry out signal handling. It
|
|
|
|
uses isc::util::SignalSet to catch OS signals, and isc::process::IOSignalQueue to
|
|
|
|
propagate them to its isc::asiolink::IOService as instances of
|
|
|
|
isc::process::IOSignal.
|
|
|
|
|
|
|
|
This CPL signaling class hierarchy is illustrated in the following diagram:
|
|
|
|
|
|
|
|
@image html cpl_signal_classes.svg "CPL Signal Classes"
|
|
|
|
|
|
|
|
The mechanics of isc::process::IOSignal are straight forward. Upon construction it
|
|
|
|
is given the target isc::asiolink::IOService, the value of the OS signal to
|
|
|
|
send (e.g. SIGINT, SIGHUP...), and an isc::process::IOSignalHandler. This handler
|
|
|
|
should contain the logic the caller would normally execute in its OS signal
|
|
|
|
handler. Each isc::process::IOSignal instance has a unique identifier called its
|
|
|
|
sequence_id.
|
|
|
|
|
|
|
|
Internally, IOSignal creates a 1 ms, one-shot timer, on the given
|
|
|
|
IOService. When the timer expires its event handler invokes the caller's
|
|
|
|
IOSignalHandler passing it the sequence_id of the IOSignal.
|
|
|
|
|
|
|
|
Sending IOSignals is done through an isc::process::IOSignalQueue. This class is
|
|
|
|
used to create the signals, house them until they are delivered, and dequeue
|
|
|
|
them so they can be been handled. To generate an IOSignal when an OS signal
|
|
|
|
arrives, the process's OS signal handler need only call
|
|
|
|
isc::process::IOSignalQueue::pushSignal() with the appropriate values.
|
|
|
|
|
|
|
|
To dequeue the IOSignal inside the caller's IOSignalHandler, one simply
|
|
|
|
invokes isc::process::IOSignalQueue::popSignal() passing it the sequence_id
|
|
|
|
parameter passed to the handler. This method returns a pointer to
|
|
|
|
instigating IOSignal from which the value of OS signal (i.e. SIGINT,
|
|
|
|
SIGUSR1...) can be obtained. Note that calling popSignal() removes the
|
|
|
|
IOSignalPtr from the queue, which should reduce its reference count to
|
|
|
|
zero upon exiting the handler (unless a deliberate copy of it is made).
|
|
|
|
|
|
|
|
A typical isc::process::IOSignalHandler might be structured as follows:
|
|
|
|
@code
|
|
|
|
|
|
|
|
void processSignal(IOSignalId sequence_id) {
|
|
|
|
// Pop the signal instance off the queue.
|
|
|
|
IOSignalPtr signal = io_signal_queue_->popSignal(sequence_id);
|
|
|
|
|
|
|
|
int os_signal_value = signal->getSignum();
|
|
|
|
:
|
|
|
|
// logic based on the signal value
|
|
|
|
:
|
|
|
|
}
|
|
|
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
IOSignal's handler invocation code will catch, log ,and then swallow any
|
|
|
|
exceptions thrown by an IOSignalHandler. This is done to protect the integrity
|
|
|
|
IOService context.
|
|
|
|
|
|
|
|
The following sequence diagram depicts the initialization of signal handling
|
|
|
|
during startup and the subsequent receipt of a SIGHUP:
|
|
|
|
|
|
|
|
@image html cpl_signal_sequence.svg "CPL Signal Handling Sequence"
|
|
|
|
|
2020-10-19 18:33:46 +02:00
|
|
|
@section redact Redact Passwords
|
|
|
|
|
2021-03-23 00:23:12 +01:00
|
|
|
There are two tools to remove sensitive data as passwords or secrets from logs:
|
2020-10-19 18:33:46 +02:00
|
|
|
- redactedAccessString for database access strings
|
|
|
|
- redactConfig for full configurations
|
|
|
|
|
2021-05-21 15:52:39 +03:00
|
|
|
The jsonPathsToRedact method must be defined in derived classes following this
|
2020-10-19 18:33:46 +02:00
|
|
|
procedure:
|
2021-05-21 15:52:39 +03:00
|
|
|
- Get all possible JSON paths from the root of the configuration to leaves that
|
|
|
|
fulfill the role of map keys and which contain "password" or "secret".
|
|
|
|
- For each of these paths, remove the root node and the leaf node.
|
|
|
|
- Include all the paths in the method. Duplicate subpaths are expected in the
|
|
|
|
case of common subpaths to different leaves.
|
|
|
|
|
|
|
|
There are two special syntaxes:
|
|
|
|
- "[]" suggests that the searched element is a list. This is required for all
|
|
|
|
lists and is for performance gain.
|
|
|
|
- "*" as a last element in a JSON path tells the redacter to look in all
|
|
|
|
elements that follow for elements that contain "password" and "secret". This is
|
|
|
|
when the particular configuration that is targeted by the "*" does not have a
|
|
|
|
well defined structure, such as is the case for "parameters" in the
|
|
|
|
"hooks-libraries" map in "Dhcp4" and "Dhcp6".
|
2020-10-19 18:33:46 +02:00
|
|
|
|
2020-07-01 15:21:30 +02:00
|
|
|
@section cplMTConsiderations Multi-Threading Consideration for Controllable Process Layer
|
|
|
|
|
|
|
|
By default this library is not thread safe and currently there is no known
|
|
|
|
exception.
|
|
|
|
|
2016-12-01 16:29:07 +01:00
|
|
|
*/
|