|
|
# Kea Configuration Backend Design
|
|
|
This is a design document for the Kea Configuration Backend feature in Kea. This feature is planned to be included in the Kea 1.6.0 release.
|
|
|
|
|
|
Extensions of this design exist:
|
|
|
- [Client Classes in Config Backend](designs/client-classes-in-cb)
|
|
|
|
|
|
# Introduction
|
|
|
|
|
|
This Kea Configuration Backend is a new feature of Kea which allows for storing configuration of Kea server in a database. Parts of the configurations can still be provided in the configuration file and such local configuration takes precedence over the configuration provided in the database. The configuration file may now include connection information and credentials to be used by the server to connect to the database and fetch the configuration information. Additional control commands and necessary updates to the existing control commands are going to be introduced to allow for managing any piece of the server configuration that can be stored in the database. The database schema contains ancillary data for the servers to be determine when new changes to the configuration have been introduced, e.g. subnet removed, subnet added, subnet modified etc.
|
|
|
|
|
|
## Design Considerations
|
|
|
|
|
|
The following is a list of various aspects of the design to be considered and debated:
|
|
|
|
|
|
* Database schemas and how that applies to various database backends
|
|
|
* Database content versioning
|
|
|
* Database credentials management
|
|
|
* Identification of Kea daemons, including DHCP servers within a single cluster and within the whole system
|
|
|
* Determine when the database changes should/can be fetched by respective daemons
|
|
|
* Address slight differences between configurations of certain servers, within the same shard
|
|
|
* Configuration daemon that can directly talk to the database
|
|
|
* Reuse of hooks libraries, e.g. subnet_cmds, to directly talk to the database
|
|
|
* Create new configuration in a db from scratch using a daemon
|
|
|
* Dump configuration from the database, by converting it to JSON
|
|
|
* Adaptation of the config-get, config-write etc. commands
|
|
|
* Provide central information about the DHCP servers in the database
|
|
|
* Isolation of the config backend code from the libdhcpsrv, perhaps even a hook?
|
|
|
* Possible extensions to kea-shell to wrap complex RESTful API commands into atomic operations
|
|
|
* How multiple DHCP servers using the same database configuration can work in isolation, e.g. can they assign addresses from the same subnet or different ones?
|
|
|
|
|
|
## High Level Architecture
|
|
|
|
|
|
![kea-config-backend-high-level](/uploads/839a32def4bd96070a90b56e444dc5e3/kea-config-backend-high-level.png)
|
|
|
|
|
|
This picture shows three Kea instances, of which two are connected to the same database, i.e. DB1, and one is connected to the second database DB2. The Kea instances can comprise a DHCPv4 server, DHCPv6 server, Control Agent and/or D2 server. Each of these servers is capable of connecting to the database to fetch configuration. Also, each server uses a configuration file, which may comprise connection information and credentials required to connect to the database. In addition, the configuration file may contain configuration specific to the particular server instance. If this configuration overlaps with a configuration in the database for this server, the configuration from the file takes precedence over the configuration in the database. For example: if global DHCP parameters such as DHCP timers are specified in the JSON file and different values of these parameters are specified in the database, the values from the JSON file will be used.
|
|
|
|
|
|
In the Kea 1.6.0 release, only limited part of the server configuration can be stored in the database, i.e. subnets, networks, options, global parameters. The remaining parts of the DHCP server configuration must be provided in the JSON file. In Kea 1.6.0 release it will neither be possible to store Control Agent configuration nor D2 configuration in the database. Therefore, these daemons will have to be configured as usual, i.e. using the config files.
|
|
|
|
|
|
The Kea4 instance is used to provide a management interface to the entire system. It receives commands over the RESTful API and communicates directly with the database instances to insert new configurations, fetch configuration and present to an administrator or update the configuration. The process that is used to manage the database content is one or more of the existing Kea processes. The following cases are planned for the upcoming releases:
|
|
|
|
|
|
* A DHCPv4 server which doesn't respond to DHCP traffic, with suitable hooks libraries loaded,
|
|
|
* A DHCPv6 server which doesn't respond to DHCP traffic, with suitable hooks libraries loaded,
|
|
|
* A Control Agent with suitable hooks libraries loaded.
|
|
|
|
|
|
Obviously, allowing the Control Agent to use DHCP specific hooks libraries, e.g. subnet_cmds, will require some changes to those libraries to adopt them to be used by a different process. In particular, the Control Agent is not aware of the DHCP Configuration Manager which holds the DHCP configuration. Therefore, supporting the first two cases is mandatory for Kea 1.6.0. Support for the third case will be added in a future release.
|
|
|
|
|
|
It is envisaged that some deployments may require additional configuration step which we call bootstrapping. One possible use case is when additional configuration data is held in yet another database instance. This additional configuration data may possibly affect how the rest of the configuration is performed. Imagine the case when the connection information to the DB1 and DB2 is held in a central database. The Kea server in the bootstrapping step could get the connection information from the central database and then use it to connect to the DB1 or DB2 to get the actual configuration information.
|
|
|
|
|
|
Since bootstrapping is highly dependent on the particular deployment, the bootstrapping code must be implemented as proprietary hooks library (custom hook). The Kea servers will be extended to provide new bootstrapping hook points. They will be called: dhcp4_srv_bootstrap and dhcp6_srv_bootstrap for the DHCPv4 and the DHCPv6 servers respectively. The names of the corresponding hook points for D2 and the CA process are to be determined.
|
|
|
|
|
|
In order to manage the content of the database use for bootstrapping there is a need to develop some custom management tool. Since such tool is proprietary it is out of scope for this document. However, it is worth noting that such tool can be integrated with Kea if it is implemented as a hooks library providing specific REST commands. This hooks library can be loaded by the Kea4 instance which in our example would be used to manage both the content of the DB1/DB2 and CustomDB1 databases.
|
|
|
|
|
|
# Configuration Management
|
|
|
|
|
|
The server configuration stored in a database will be managed via the RESTful API. Rather than extending existing commands, e.g. subnet_cmds, we will add a new `cb_cmds` hooks library providing the configuration backend specific commands. All these commands will allow for specifying an optional `remote` parameter, which will specify the database type, location and access credentials. If this parameter is not specified, the following logic will be followed:
|
|
|
|
|
|
- if the command attempts to fetch the data from the database, the server will fetch the data from all available backends, merge them and return to the caller,
|
|
|
- if the command attempts to modify or delete the data in the database and the server uses exactly one backend, the server will use this sole backend to process the command,
|
|
|
- if the command attempts to modify or delete the data in the database and the server uses more than one backend, an error will be returned indicated that the remote specification is ambiguous.
|
|
|
|
|
|
All commands implemented in the `cb_cmds` hooks library will use `remote-` as a command name prefix. For example, the name of the command adding a new IPv4 subnet to the database will be called `remote-subnet4-set`. Using the unified prefix for all these new commands will make it easily recognizable that these commands are related to the configuration backend and all of them will be grouped together in the `list-commands` command output.
|
|
|
|
|
|
The following is the example of the `remote-subnet4-set` command which adds (SQL INSERT) or updates (i.e. if there is already a subnet with the id and/or subnet its configuration will be merged by a SQL UPDATE) a subnet in the database:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-set",
|
|
|
"service": "dhcp4",
|
|
|
"arguments": {
|
|
|
"log-message": "updated subnet with id 123",
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ],
|
|
|
"subnet4": [ {
|
|
|
"id": 123,
|
|
|
"subnet": "10.20.30.0/24",
|
|
|
...
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
The `server-tags` list includes a list of server tags which associate the given configuration element with one or many servers. In the example above, the subnet is added to be used only by the "server1" server. There are two keywords that can be used instead of the explicit server tag: "all" and "unassigned". The former means that the subnet is used by all servers. The latter means that the subnet is used by no servers. In Kea 1.6.0 release at most one element in this list will be supported. This parameter will be mandatory.
|
|
|
|
|
|
The `log-message` parameter is optional. It includes a log entry to be inserted into the audit table along with the audit entry corresponding to the change being applied.
|
|
|
|
|
|
In the future (post Kea 1.6.0 release) it is planned to extend the `remote` structure to include the database credentials, such as user name, database name and password, and the location of the database, i.e. host and port. Admittedly, putting database credentials into every command looks somewhat redundant, but it is important to note that a single server instance may talk to multiple database instances. In this deployment model, the server instance may not even process any DHCP traffic but rather be designated to configure the cluster of DHCP servers. Various deployment models are presented in subsections of this chapter.
|
|
|
|
|
|
## Management Only Configuration
|
|
|
|
|
|
In this deployment scenario the subnet management hooks library is loaded by the Control Agent. The CA instance is designated as a configuration daemon for a cluster of database instances.
|
|
|
|
|
|
![kea-config-backend-ca-only.svg](/uploads/56764b445a773e8ae594cc2aa642e2ec/kea-config-backend-ca-only.svg)
|
|
|
|
|
|
The *service* argument in the following command specifies that the Control Agent should process the command (via cb_cmds library).
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-set",
|
|
|
"service": "ca",
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql",
|
|
|
"name": "kea",
|
|
|
"user": "kea",
|
|
|
"password": "kea",
|
|
|
"host": "marine.example.org"
|
|
|
},
|
|
|
"subnets": [ {
|
|
|
"id": 123,
|
|
|
"subnet": "10.20.30.0/24",
|
|
|
...
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## Manage and Fetch Configuration
|
|
|
|
|
|
In this deployment model the Control Agent is designated to manage Kea configuration in several database instances.
|
|
|
|
|
|
![kea-config-backend-components-ca-manage.svg](/uploads/d064387ca41e9937a15a9ee1397ec302/kea-config-backend-components-ca-manage.svg)
|
|
|
|
|
|
The *service* parameter in the following command specifies that Control Agent should add the subnet (via cb_cmds hooks library):
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-set",
|
|
|
"service": "ca",
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql",
|
|
|
"name": "kea",
|
|
|
"user": "kea",
|
|
|
"password": "kea",
|
|
|
"host": "marine.example.org"
|
|
|
},
|
|
|
"subnets": [ {
|
|
|
"id": 123,
|
|
|
"subnet": "10.20.30.0/24",
|
|
|
...
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## Manage and Fetch Configuration with DHCP Servers
|
|
|
|
|
|
In the following deployment model, the DHCP server is responsible for managing Kea configurations in a cluster of databases:
|
|
|
|
|
|
![kea-config-backend-components-dhcp-manage.svg](/uploads/19b574023bde7b9b1dd969f32b70a3fd/kea-config-backend-components-dhcp-manage.svg)
|
|
|
|
|
|
The *service* parameter in the following command specifies that the DHCP server should process the command (via cb_cmds hooks library):
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-set",
|
|
|
"service": "dhcp4",
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql",
|
|
|
"name": "kea",
|
|
|
"user": "kea",
|
|
|
"password": "kea",
|
|
|
"host": "marine.example.org"
|
|
|
},
|
|
|
"subnets": [ {
|
|
|
"id": 123,
|
|
|
"subnet": "10.20.30.0/24",
|
|
|
...
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
# Configuration Sequence
|
|
|
|
|
|
## Configuration State Diagram
|
|
|
|
|
|
The server startup and configuration must be modified to introduce two new configuration phases required by the feature:
|
|
|
|
|
|
1. bootstrapping
|
|
|
2. server configuration fetching from a database
|
|
|
|
|
|
The following state diagram presents the updated startup and configuration phase.
|
|
|
|
|
|
![kea-config-backend-bootstrap.svg](/uploads/03eb2e15846c5ba74269e9c5f62bdc2a/kea-config-backend-bootstrap.svg)
|
|
|
|
|
|
The server starts as usual by reading the configuration file (ConfigFileRead). Bootstrapping requires that the hooks libraries implementing it are loaded. Therefore, the part of the configuration read from the file which contains a list of hooks libraries must be parsed and the hooks libraries must be loaded (NewHooksLibrariesLoad). If the libraries are loaded successfully, the server checks if there are any callouts implementing bootstrap hook points. The callouts are invoked (HooksSrvBootstrap) and can return one of the three status codes:
|
|
|
|
|
|
``NEXT_STEP_CONTINUE`` - in which the Kea server will continue normally, i.e. will process configuration read from the file,
|
|
|
``NEXT_STEP_SKIP`` - in which case the Kea server will skip loading configuration read from the file and will rather fetch configuration from the database, if the database connection information is provided,
|
|
|
``NEXT_STEP_DROP`` - in which case the server will cease configuration and will rollback to the previous configuration (config error).
|
|
|
The server processes the configuration from the file (StagingConfig) where it presumably finds the connection information to the database. Note that such connection information could also be provided in the bootstrap step by the hooks library. The server will next connect to the database, fetch the configuration (DatabaseConfigFetch) and merge it into the existing (staging) configuration. Finally, the configuration is applied, i.e. logger is configured, D2 process is started, DHCP sockets are opened etc. (ConfigApply).
|
|
|
|
|
|
## Bootstrap Hook
|
|
|
```c++
|
|
|
int dhcp4_srv_bootstrap(CalloutHandle& handle) {
|
|
|
// Staging server configuration.
|
|
|
isc::dhcp::SrvConfigPtr server_config;
|
|
|
handle.getArgument("server_config", server_config);
|
|
|
|
|
|
// Configuration from the config file.
|
|
|
isc::config::ConstElementPtr config_file_contents;
|
|
|
handle.getArgument("json_config", config_file_contents);
|
|
|
|
|
|
// ...
|
|
|
// Connect to another source of configuration information
|
|
|
// and apply the configuration to the staging configuration
|
|
|
// object provided as "server_config". One possibility is to
|
|
|
// set the configuration backend connection information and
|
|
|
// credentials. The details how to do it is TBD.
|
|
|
|
|
|
// Set the 'skip' status if there is no need for applying the configuration
|
|
|
// read from the file (e.g. if the required configuration was fetched from
|
|
|
// another source).
|
|
|
handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
|
|
|
return (0);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## Adopting DHCP Configuration Manager
|
|
|
|
|
|
The DHCP servers must be updated to facilitate the new configuration model where part of the server configuration comes from the configuration file and part from one or more databases. In general, there will be cases when none of those configuration sources will contain enough information for the server to operate. In some deployments the configuration file will contain only minimal amount of configuration information (database credentials, logging etc.) and the database will contain remaining part of the server configuration.
|
|
|
|
|
|
Upon server startup the server must be able to distinguish between two sets of configuration: staging configuration and external configuration to that comes from the database. They may partially overlap, but in general we will recommend that initially the server administrators should avoid such overlaps. For example, they should avoid specifying configuration of the subnets within both the configuration file and the database.
|
|
|
|
|
|
When the booted server has already fetched those two sets of configuration it must merge it into a single configuration structure (`SrvConfig` object) which can be used as the current configuration in the `CfgMgr`. This guarantees backward compatibility with the current code which calls:
|
|
|
```
|
|
|
CfgMgr::instance().getCurrentCfg()
|
|
|
```
|
|
|
to fetch current server configuration. This call will fetch the server configuration combined from the configuration file and the database.
|
|
|
|
|
|
Currently, the `CfgMgr` includes two configuration storages:
|
|
|
- staging configuration - used when the server starts up or reloads,
|
|
|
- current configuration - used currently by the server until staging configuration is committed.
|
|
|
|
|
|
These configurations are stored in the respective `SrvConfig` instances.
|
|
|
|
|
|
The Configuration Manager must be extended to include additional storage(s) where configuration data fetched from the database(s) is held before it is merged to the staging or current configuration. In the simplest case, only one additional storage is needed, but it is better to make it generic and allow any number of additional storages to hold configuration information fetched from different external sources. Note that Kea Config Backend allows for simultaneous use of multiple database backends.
|
|
|
|
|
|
In addition, the updated Configuration Manager will have to facilitate the use case when configuration data is incrementally added to the running server, e.g. as a result of processing a command. So, depending on the use case, the data fetched from the database may need to be merged to the current configuration directly or to the staging configuration, upon server startup.
|
|
|
|
|
|
The following extensions are planned for the `CfgMgr` and the classes it depends on:
|
|
|
- add `createExternalCfg` function which will create new instance of the `SrvConfig` and return an index/handle of this instance. The index will be always greater than 1 because the index of 0 will be reserved for the current configuration and the index of 1 will be reserved for the staging configuration.
|
|
|
- add `getCfg(index)` function which will return a pointer to the specified configuration instance.
|
|
|
- add `mergeCfg(from_index, to_index)` which will attempt to merge the configuration identified by `from_index` to the configuration identified by `to_index`. For example, in order to merge the database configuration identified by the index 1024 into staging configuration, one has to call `mergeCfg(1024, 1)`.
|
|
|
- each `Cfg...` object must be extended to include `mergeCfg` function that merges one configuration of the given type to another.
|
|
|
|
|
|
The staging or current configuration is always modified via the merge mechanism. That includes the case when the server runs the periodic checks for the configuration updates in the database. For example, if the server finds that there is one new subnet and one new option definition in the database, the server builds new `SrvConfig` instance via the new API calls described above, and then calls `CfgMgr::mergeCfg(from_index, 0)` to try to merge this configuration into the current configuration.
|
|
|
|
|
|
# Database Schema
|
|
|
|
|
|
The database schema will ultimately hold all configuration parameters for every Kea server. In the Kea 1.5 release there will be only a subset of parameters stored in the database.
|
|
|
|
|
|
## Configuration Parameters in DHCPv4
|
|
|
|
|
|
The following configuration parameters are currently (Kea 1.4.0) supported by the DHCPv4 server. The bold items will be supported by the Config Backend in Kea 1.5.0 release. Support for the remaining ones will be added in a later time.
|
|
|
|
|
|
* boot-file-name
|
|
|
* calculate-tee-times
|
|
|
* client-classes
|
|
|
* control-socket
|
|
|
* **decline-probation-period**
|
|
|
* dhcp-ddns
|
|
|
* dhcp4o6-port
|
|
|
* **echo-client-id**
|
|
|
* expired-leases-processing
|
|
|
* hooks-libraries
|
|
|
* host-reservation-identifiers
|
|
|
* hosts-databases
|
|
|
* lease-database
|
|
|
* match-client-id
|
|
|
* next-server
|
|
|
* **option-data**
|
|
|
* **option-def**
|
|
|
* **rebind-timer**
|
|
|
* **renew-timer**
|
|
|
* sanity-checks
|
|
|
* server-hostname
|
|
|
* **shared-networks**
|
|
|
* **subnet4**
|
|
|
* t1-percent
|
|
|
* t2-percent
|
|
|
* user-context
|
|
|
* **valid-lifetime**
|
|
|
|
|
|
## Configuration Parameters in DHCPv6
|
|
|
|
|
|
The following configuration parameters are currently (Kea 1.4.0) supported by the DHCPv6 server. The bold items will be supported by the Config Backend in Kea 1.5.0 release. Support for the remaining ones will be added in a later time.
|
|
|
|
|
|
* client-classes
|
|
|
* control-socket
|
|
|
* decline-probation-period
|
|
|
* dhcp-ddns
|
|
|
* dhcp4o6-port
|
|
|
* expired-leases-processing
|
|
|
* hooks-libraries
|
|
|
* host-reservation-identifiers
|
|
|
* hosts-databases
|
|
|
* interfaces-config
|
|
|
* lease-database
|
|
|
* mac-sources
|
|
|
* **option-data**
|
|
|
* **option-def**
|
|
|
* **preferred-lifetime**
|
|
|
* relay-supplied-options
|
|
|
* **renew-timer**
|
|
|
* **rebind-timer**
|
|
|
* relay-supplied-options
|
|
|
* sanity-checks
|
|
|
* server-id
|
|
|
* **shared-networks**
|
|
|
* **subnet6**
|
|
|
* user-context
|
|
|
* **valid-lifetime**
|
|
|
|
|
|
## Sharing Database Between Kea Servers
|
|
|
|
|
|
One of the applications of the Config Backend is to provide a common source of configuration information for multiple Kea instances. In a common database like this, some configuration information may be common for multiple servers, e.g. the same option definition for each Kea instance. Some parts of the configuration may be specific for various Kea instances. Therefore, it is required to be able to specify that the particular configuration element is common for all servers or specific to a selected Kea instance. Kea instances need to be uniquely identified by "tags". Tag is a string of a free form which uniquely identifies the server in the database.
|
|
|
|
|
|
The Many-To-Many relationship in the relational databases will be achieved by providing additional tables joining the particular configuration elements with the known servers. For example, the `dhcp4_subnet_server` table will be used to create M:M relationship between the `dhcp4_subnet` table and the `dhcp4_server` table. The latter will hold one *logical* server named 'all' which associates a given configuration element with all servers. The Kea administrators will be able to add more servers along with their server tags and match them with specific configuration elements.
|
|
|
|
|
|
In Cassandra, the matching between the configuration elements and the server tags will be achieved by Cassandra specific techniques, i.e. the server tags must be included in the tables holding the configuration elements (details TBD).
|
|
|
|
|
|
## MySQL
|
|
|
|
|
|
### MySQL Schema Updates
|
|
|
|
|
|
The following picture shows new (and updated) tables to be included in the Kea MySQL schema to facilitate storing DHCPv4 configuration in the database.
|
|
|
|
|
|
![kea-config-backend-mysql-v4](uploads/11ebd879729596ff3f2e8f61eaaf78cb/kea-config-backend-mysql-v4.png)
|
|
|
|
|
|
The next picture shows the corresponding tables for the DHCPv6 server.
|
|
|
|
|
|
![kea-config-backend-mysql-v6.svg](/uploads/0d08af7588a191c96e3823cd285904de/kea-config-backend-mysql-v6.svg)
|
|
|
|
|
|
### MySQL Select Statements
|
|
|
|
|
|
The following query fetches all IPv4 subnets which, have been modified after a given timestamp, along with address pools and DHCP options.
|
|
|
|
|
|
```sql
|
|
|
SELECT
|
|
|
s.subnet_id,
|
|
|
s.subnet_prefix,
|
|
|
s.4o6_interface,
|
|
|
s.4o6_interface_id,
|
|
|
s.4o6_subnet,
|
|
|
s.boot_file_name,
|
|
|
s.client_class,
|
|
|
s.interface,
|
|
|
s.match_client_id,
|
|
|
s.modification_ts,
|
|
|
s.next_server,
|
|
|
s.rebind_timer,
|
|
|
s.relay,
|
|
|
s.renew_timer,
|
|
|
s.require_client_classes,
|
|
|
s.reservation_mode,
|
|
|
s.server_hostname,
|
|
|
s.shared_network_name,
|
|
|
s.user_context,
|
|
|
s.valid_lifetime,
|
|
|
p.id,
|
|
|
p.start_address,
|
|
|
p.end_address,
|
|
|
p.subnet_id,
|
|
|
p.modification_ts,
|
|
|
x.option_id,
|
|
|
x.code,
|
|
|
x.value,
|
|
|
x.formatted_value,
|
|
|
x.space,
|
|
|
x.persistent,
|
|
|
x.dhcp4_subnet_id,
|
|
|
x.scope_id,
|
|
|
x.user_context,
|
|
|
x.shared_network_name,
|
|
|
x.pool_id,
|
|
|
x.modification_ts,
|
|
|
o.option_id,
|
|
|
o.code,
|
|
|
o.value,
|
|
|
o.formatted_value,
|
|
|
o.space,
|
|
|
o.persistent,
|
|
|
o.dhcp4_subnet_id,
|
|
|
o.scope_id,
|
|
|
o.user_context,
|
|
|
o.shared_network_name,
|
|
|
o.pool_id,
|
|
|
o.modification_ts
|
|
|
FROM dhcp4_subnet AS s
|
|
|
INNER JOIN dhcp4_subnet_server AS a
|
|
|
ON s.subnet_id = a.subnet_id
|
|
|
INNER JOIN dhcp4_server AS srv
|
|
|
ON (a.server_id = srv.id) OR (a.server_id = 1)
|
|
|
LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id
|
|
|
LEFT JOIN dhcp4_options AS x ON x.scope_id = 5 AND p.id = x.pool_id
|
|
|
LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id
|
|
|
WHERE (srv.tag = ? OR srv.id = 1) AND t.modification_ts > ?
|
|
|
ORDER BY s.subnet_id, p.id, x.option_id, o.option_id
|
|
|
```
|
|
|
|
|
|
The following query fetches all IPv6 subnets along with address pools, prefix delegation pools and DHCP options on all nesting levels (TO BE UPDATED)
|
|
|
|
|
|
```sql
|
|
|
SELECT
|
|
|
dhcp6_subnet.subnet_prefix,
|
|
|
dhcp6_subnet.client_class,
|
|
|
dhcp6_subnet.interface,
|
|
|
dhcp6_subnet.modification_ts,
|
|
|
dhcp6_subnet.modification_type,
|
|
|
dhcp6_subnet.preferred_lifetime,
|
|
|
dhcp6_subnet.rapid_commit,
|
|
|
dhcp6_subnet.rebind_timer,
|
|
|
dhcp6_subnet.relay,
|
|
|
dhcp6_subnet.renew_timer,
|
|
|
dhcp6_subnet.require_client_classes,
|
|
|
dhcp6_subnet.reservation_mode,
|
|
|
dhcp6_subnet.shared_network_name,
|
|
|
dhcp6_subnet.subnet_id,
|
|
|
dhcp6_subnet.user_context,
|
|
|
dhcp6_subnet.valid_lifetime,
|
|
|
dhcp6_options.option_id,
|
|
|
dhcp6_options.code,
|
|
|
dhcp6_options.value,
|
|
|
dhcp6_options.formatted_value,
|
|
|
dhcp6_options.space,
|
|
|
dhcp6_options.persistent,
|
|
|
dhcp6_options.dhcp_client_class,
|
|
|
dhcp6_options.dhcp6_subnet_id,
|
|
|
dhcp6_options.host_id,
|
|
|
dhcp6_options.scope_id,
|
|
|
dhcp6_options.user_context,
|
|
|
dhcp6_options.dhcp6_shared_network_name,
|
|
|
dhcp6_options.dhcp6_pool_id,
|
|
|
dhcp6_options.dhcp6_pd_pool_id,
|
|
|
dhcp6_options.modification_ts,
|
|
|
dhcp6_options.modification_type,
|
|
|
dhcp6_pool.start_address,
|
|
|
dhcp6_pool.end_address,
|
|
|
dhcp6_pool.dhcp6_subnet_id,
|
|
|
dhcp6_pool.pool_id,
|
|
|
dhcp6_pool.modification_ts,
|
|
|
dhcp6_pool.modification_type,
|
|
|
dhcp6_pool_options.option_id,
|
|
|
dhcp6_pool_options.code,
|
|
|
dhcp6_pool_options.value,
|
|
|
dhcp6_pool_options.formatted_value,
|
|
|
dhcp6_pool_options.space,
|
|
|
dhcp6_pool_options.persistent,
|
|
|
dhcp6_pool_options.dhcp_client_class,
|
|
|
dhcp6_pool_options.dhcp6_subnet_id,
|
|
|
dhcp6_pool_options.host_id,
|
|
|
dhcp6_pool_options.scope_id,
|
|
|
dhcp6_pool_options.user_context,
|
|
|
dhcp6_pool_options.dhcp6_shared_network_name,
|
|
|
dhcp6_pool_options.dhcp6_pool_id,
|
|
|
dhcp6_pool_options.dhcp6_pd_pool_id,
|
|
|
dhcp6_pool_options.modification_ts,
|
|
|
dhcp6_pool_options.modification_type,
|
|
|
dhcp6_pd_pool.prefix,
|
|
|
dhcp6_pd_pool.prefix_length,
|
|
|
dhcp6_pd_pool.delegated_prefix_length,
|
|
|
dhcp6_pd_pool.dhcp6_subnet_id,
|
|
|
dhcp6_pd_pool.pool_id,
|
|
|
dhcp6_pd_pool.modification_ts,
|
|
|
dhcp6_pd_pool.modification_type,
|
|
|
dhcp6_pd_pool_options.option_id,
|
|
|
dhcp6_pd_pool_options.code,
|
|
|
dhcp6_pd_pool_options.value,
|
|
|
dhcp6_pd_pool_options.formatted_value,
|
|
|
dhcp6_pd_pool_options.space,
|
|
|
dhcp6_pd_pool_options.persistent,
|
|
|
dhcp6_pd_pool_options.dhcp_client_class,
|
|
|
dhcp6_pd_pool_options.dhcp6_subnet_id,
|
|
|
dhcp6_pd_pool_options.host_id,
|
|
|
dhcp6_pd_pool_options.scope_id,
|
|
|
dhcp6_pd_pool_options.user_context,
|
|
|
dhcp6_pd_pool_options.dhcp6_shared_network_name,
|
|
|
dhcp6_pd_pool_options.dhcp6_pool_id,
|
|
|
dhcp6_pd_pool_options.dhcp6_pd_pool_id,
|
|
|
dhcp6_pd_pool_options.modification_ts,
|
|
|
dhcp6_pd_pool_options.modification_type
|
|
|
FROM kea15.dhcp6_subnet
|
|
|
LEFT JOIN dhcp6_options
|
|
|
ON dhcp6_subnet.subnet_id = dhcp6_options.dhcp6_subnet_id
|
|
|
LEFT JOIN dhcp6_pool
|
|
|
ON dhcp6_subnet.subnet_id = dhcp6_pool.dhcp6_subnet_id
|
|
|
LEFT JOIN dhcp6_options AS dhcp6_pool_options
|
|
|
ON dhcp6_pool.pool_id = dhcp6_pool_options.dhcp6_pool_id
|
|
|
LEFT JOIN dhcp6_pd_pool ON dhcp6_subnet.subnet_id = dhcp6_pd_pool.dhcp6_subnet_id
|
|
|
LEFT JOIN dhcp6_options AS dhcp6_pd_pool_options
|
|
|
ON dhcp6_pool.pool_id = dhcp6_pd_pool_options.dhcp6_pool_id
|
|
|
ORDER BY dhcp6_subnet.subnet_id, dhcp6_pd_pool_options.option_id,
|
|
|
dhcp6_pool.pool_id, dhcp6_pool_options.option_id,
|
|
|
dhcp6_pd_pool.pool_id, dhcp6_pd_pool_options.option_id;
|
|
|
|
|
|
```
|
|
|
|
|
|
Note that the queries above merely fetch shared network name rather than the full shared network information. The full shared network data is fetched by a separate query provided below.
|
|
|
|
|
|
```sql
|
|
|
SELECT
|
|
|
n.id,
|
|
|
n.name,
|
|
|
n.client_class,
|
|
|
n.interface,
|
|
|
n.match_client_id,
|
|
|
n.modification_ts,
|
|
|
n.rebind_timer,
|
|
|
n.relay,
|
|
|
n.renew_timer,
|
|
|
n.require_client_classes,
|
|
|
n.reservation_mode,
|
|
|
n.user_context,
|
|
|
n.valid_lifetime,
|
|
|
o.option_id,
|
|
|
o.code,
|
|
|
o.value,
|
|
|
o.formatted_value,
|
|
|
o.space,
|
|
|
o.persistent,
|
|
|
o.dhcp4_subnet_id,
|
|
|
o.scope_id,
|
|
|
o.user_context,
|
|
|
o.shared_network_name,
|
|
|
o.pool_id,
|
|
|
o.modification_ts
|
|
|
FROM dhcp4_shared_network AS n
|
|
|
INNER JOIN dhcp4_shared_network_server AS a
|
|
|
ON n.id = a.shared_network_id
|
|
|
INNER JOIN dhcp4_server AS s
|
|
|
ON (a.server_id = s.id) OR (a.server_id = 1)
|
|
|
LEFT JOIN dhcp4_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name
|
|
|
WHERE (s.tag = ? OR s.id = 1) AND n.modification_ts > ?
|
|
|
ORDER BY n.id, o.option_id"
|
|
|
```
|
|
|
|
|
|
The corresponding query for the DHCPv6 case is not provided but it differs only by table names.
|
|
|
|
|
|
For each table it is possible to fetch incremental changes applied after a certain timestamp remembered by the server. For example:
|
|
|
|
|
|
### Audit (a.k.a. journal) in MySQL
|
|
|
|
|
|
An audit table (a.k.a. journal) is a well known technique for tracking incremental changes in the database. Every servers' configuration change in the database triggers insertion of the new entry in the audit table. This entry includes the name of the modified table, identifier of the modified object (inserted, updated or deleted), modification type etc. Some of the operations may result in multiple audit entries, e.g. a command to delete all subnets would result in number of audit entries equal to the number of deleted subnets. All audit entries which are associated with a single configuration change like this are grouped by `audit revisions`. The audit revision contains the timestamp when the change has been applied and the log message specified by the user (or a client who sent the control command). In the future, the revisions may also include user name to identify the person who applied the change, source IP address etc.
|
|
|
|
|
|
Revisions and audit entries are in 1:M relationship. The `dhcp4_audit` table contains `revision_id` column which constitutes this association.
|
|
|
|
|
|
Having all configuration changes listed in the audit & revision tables, the server can periodically check which SQL tables contain these changes using the following SQL query:
|
|
|
|
|
|
```sql
|
|
|
SELECT
|
|
|
a.id,
|
|
|
a.object_type,
|
|
|
a.object_id,
|
|
|
a.modification_type,
|
|
|
r.modification_ts,
|
|
|
r.log_message
|
|
|
FROM dhcp4_audit AS a
|
|
|
INNER JOIN dhcp4_audit_revision AS r
|
|
|
ON a.revision_id = r.id
|
|
|
INNER JOIN dhcp4_server AS s
|
|
|
ON r.server_id = s.id
|
|
|
WHERE (s.tag = ? OR s.id = 1) AND (r.modification_ts > ?)
|
|
|
ORDER BY r.modification_ts"
|
|
|
```
|
|
|
|
|
|
And the following is the sample output:
|
|
|
|
|
|
```
|
|
|
+----+--------------+-----------+-------------------+---------------------+--------------------+
|
|
|
| id | object_type | object_id | modification_type | modification_ts | log_message |
|
|
|
+----+--------------+-----------+-------------------+---------------------+--------------------+
|
|
|
| 1 | dhcp4_subnet | 1024 | 0 | 2019-01-28 11:39:11 | some sample change |
|
|
|
+----+--------------+-----------+-------------------+---------------------+--------------------+
|
|
|
```
|
|
|
|
|
|
which indicates that the new subnet with ID 1024 has been added to the dhcp4_subnet table. Other possible modification types are:
|
|
|
- 1: object has been updated
|
|
|
- 2: object has been deleted
|
|
|
|
|
|
Seeing that the object has been inserted or updated, the server may now make a query on the dhcp4_subnet table to fetch the new subnet information. If the modification type is `deleted`, the subnet information no longer exists in the dhcp4_subnet. The Kea server doesn't have to make another query to the dhcp4_subnet table, unless the audit table indicates that some other subnets have been inserted or updated. In case of the example above, the server simply deletes the subnet with ID of 1024 from its local (in-memory) configuration.
|
|
|
|
|
|
### Generating Audit in MySQL
|
|
|
|
|
|
Using the database triggers is the most convenient way to populate the data into the audit tables. The triggers are invoked for each modified row, making it straightforward to generate many audit entries per single query. For example, when a command is sent to delete all subnets, for each subnet deleted from the dhcp4_subnet a trigger will be invoked with the necessary information to generate an audit entry for the deleted subnet. The triggers have one more useful property. Since they are running on the database side, they always have access to primary key of the table in which the data is modified. This primary key is needed to generate the audit entry. The primary key may not always be available on the Kea side, as it often refers to the certain objects by other keys. For example: Kea refers to the shared networks by name, rather than its ID in the database.
|
|
|
|
|
|
Each table for which the audit trail is to be generated must include 3 triggers: for insert, update and delete. These triggers simply create the audit entries in the dedicated audit tables, e.g. dhcp4_audit table. As already mentioned, the audit entries are associated with the audit revisions stored in their own tables, e.g. dhcp4_audit_revision. The audit revision table is meant to contain a lot of user-defined information, such as: log messages, server id, user name etc. Therefore, it doesn't make sense to use the triggers to create the audit revisions. Instead, the Kea server should create the audit revision at the beginning of the transaction.
|
|
|
|
|
|
The challenging part is how to associate the created audit revision with the audit entries generated by the triggers as part of this transaction. Take a look at the following stored procedure used to create the new audit revision:
|
|
|
|
|
|
```sql
|
|
|
DROP PROCEDURE IF EXISTS createAuditRevisionDHCP4;
|
|
|
DELIMITER $$
|
|
|
CREATE PROCEDURE createAuditRevisionDHCP4(IN server_tag VARCHAR(256),
|
|
|
IN audit_log_message TEXT,
|
|
|
IN cascade_transaction TINYINT(1))
|
|
|
BEGIN
|
|
|
DECLARE srv_id BIGINT(20);
|
|
|
SELECT id INTO srv_id FROM dhcp4_server WHERE tag = server_tag;
|
|
|
INSERT INTO dhcp4_audit_revision (modification_ts, server_id, log_message)
|
|
|
VALUES (NOW(), srv_id, audit_log_message);
|
|
|
SET @audit_revision_id = LAST_INSERT_ID();
|
|
|
SET @cascade_transaction = cascade_transaction;
|
|
|
END $$
|
|
|
DELIMITER ;
|
|
|
```
|
|
|
|
|
|
This procedure sets the `@audit_revision_id` to the ID of the inserted audit revision. The triggers can use the value stored in this session variable to insert the revision id into the dhcp4_audit table. Obviously, this ID is only valid until the end of the transaction. The Kea server MUST create the audit revision for the next configuration update. If it fails to do it, the triggers invoked upon the next configuration update will associate the new audit entries with the old audit revision. Note that the session variables exist until the end of the session, so they remain even after the current transaction ends.
|
|
|
|
|
|
The second session variable set in this stored procedure is `@cascade_transaction`. It is described in the next section.
|
|
|
|
|
|
### Complex Updates in MySQL (cascade_transaction)
|
|
|
|
|
|
DHCP servers have hierarchical configuration data structure in which DHCP options can be specified on different levels. In many ways it is easier for the Kea server to treat an update of the DHCP option within a subnet as a "subnet update" rather than "option update". Similarly, updating a subnet specific renew timer is treated as a "subnet update", and the entire subnet information is fetched from the database as a result of the renew timer change. By fetching the entire subnet information, the server can validate the updated subnet against runtime information and check configuration integrity. Also, the Kea server doesn't currently have a notion of database option ID, so it is not really possible to match audit information for an option with the particular subnet, shared network or pool.
|
|
|
|
|
|
The only case when an audit entry should be generated specifically for an option rather than a parent is when the global option is inserted, updated or deleted. Global options do not have a parent/owner in the database.
|
|
|
|
|
|
The following table lists the object types for which modification is signaled in the audit table, depending on the DHCP option scope:
|
|
|
|
|
|
|DHCP option scope|dhcp4_audit/object_type|
|
|
|
|-----------------|-----------------------|
|
|
|
|global|dhcp4_options|
|
|
|
|shared network|dhcp4_shared_network|
|
|
|
|subnet|dhcp4_subnet|
|
|
|
|pool|dhcp4_subnet|
|
|
|
|host|(none)|
|
|
|
|class|(none)|
|
|
|
|
|
|
Note that currently the audit is not generated for the hosts nor classes because the Configuration Backend does not support configuration of these objects.
|
|
|
|
|
|
In order to customize the audit entries depending on the DHCP option scopes there is a need to pass additional information to the MySQL triggers. In the previous section we have demonstrated the example implementation of the `createAuditRevisionDHCP4` in which the `@cascade_update` boolean value was set via the stored procedure's parameter. When this value is set to non-zero value (true), the triggers associated with the dhcp4_options table will assume that the options are added as part of the larger change (e.g. adding a new subnet, shared network etc along with their options). In this case, they won't create audit entries for the DHCP options. Note that the appropriate audit entries for the parent object should have been already created by the triggers invoked for dhcp4_subnet or dhcp4_shared_network tables.
|
|
|
|
|
|
If the `@cascade_update` is set to 0 (false), it means that there is no parent object is being modified with this change. This is possible in the following cases:
|
|
|
|
|
|
- global option added/updated/deleted,
|
|
|
- shared network specific option added/updated/deleted,
|
|
|
- subnet specific option added/updated/deleted,
|
|
|
- pool specific option added/updated/deleted
|
|
|
|
|
|
Depending on the case, the object_type value in the dhcp4_audit table has to be set to an appropriate value as shown in the table above. The triggers can determine the scope by looking into the `scope_id` column of the `dhcp4_options` table.
|
|
|
|
|
|
### Timestamps
|
|
|
|
|
|
MySQL converts timestamps specified in local time into UTC and internally stores them as UTC. When timestamps are fetched from the database using SELECT statements they are returned in local time. Therefore, Kea MySQL Config Backend uses local posix time clock to generate input timestamps and assumes that the returned timestamps are in local time too.
|
|
|
|
|
|
The timestamp columns in MySQL schema use microseconds precision (TIMESTAMP(6)). Even though, the millisecond precision could be enough for the CB, it is actually easier to use microsecond precision as it corresponds with the precision of the `boost::posix_time::microsec_clock` used in Kea to represent time. Turning it into millisecond precision would require manual truncation of the last three digits in unit testing.
|
|
|
|
|
|
## Postgres
|
|
|
|
|
|
Postgres schema is going to be almost the same as MySQL database schema.
|
|
|
|
|
|
## Cassandra (not part of 1.6.0 release)
|
|
|
|
|
|
***Any notes related to Cassandra are preliminary at this stage. Due to non-relative nature of Cassandra, its hypothetical implementation would need to be significantly different than what we have for MySQL. We currently do not have any specific plans to implement config backend for Cassandra at this time.***
|
|
|
|
|
|
Cassandra schema will also implement the concept of "server tagging" to differentiate between configurations of multiple Kea servers. The pictures and queries below haven't been updated to include the server tags because we temporarily lack tools to visualize the updated schema.
|
|
|
|
|
|
### Cassandra Schema Updates
|
|
|
|
|
|
The following picture shows new tables to be included in the Kea CQL schema to facilitate storing DHCPv4 configuration in the database.
|
|
|
|
|
|
![kea-config-backend-cass-v4](/uploads/7ecbfac93f44c1c6ddfc1f6847ad50ef/kea-config-backend-cass-v4.png)
|
|
|
|
|
|
|
|
|
The next picture shows the corresponding tables for the DHCPv6 server.
|
|
|
|
|
|
![kea-config-backend-cass-v6](/uploads/27fe55d72e89352b781b851d49357fd2/kea-config-backend-cass-v6.png)
|
|
|
|
|
|
### Cassandra Select Statements
|
|
|
|
|
|
Unlike relational databases, Cassandra is designed to partition stored data which allows for spreading the data across multiple database nodes. One of the table columns must be designated as a partition key. The value of the partition key denotes the partition in which the particular information is stored. The primary key comprises a partition key and may also comprise additional clustering keys for sorting the data within partition and to guarantee the primary key uniqueness. Config Backend generally requires three types of *select* queries:
|
|
|
|
|
|
* to select whole server configuration, e.g. upon server startup,
|
|
|
* to select recently modified parts of the configuration, e.g. added new subnet, shared network etc.
|
|
|
* to select specific configuration item, e.g. configuration information for a given subnet.
|
|
|
|
|
|
In many cases data modeling in Cassandra requires duplicating the data in separate tables which are optimized for certain queries. However, in our case the first type of queries will be the most common one. Such queries do not require the *WHERE* clause because they retrieve the entire configuration information which is later cached by the server. Even for incremental changes, e.g. add DHCP option definition to the server configuration, it is possible to use the first type of query and filter out the new (e.g. modified or added) element by modification timestamp.
|
|
|
|
|
|
The following query is invoked to retrieve the high level information about modifications applied to certain tables. As the number of rows in this table is small, retrieving all rows from this table without sorting by modification timestamp is not going to cause performance issues.
|
|
|
```sql
|
|
|
SELECT * FROM config_modification_state4;
|
|
|
```
|
|
|
|
|
|
The following query retrieves all global DHCP option definitions.
|
|
|
```sql
|
|
|
SELECT * FROM option_def4;
|
|
|
```
|
|
|
|
|
|
The following query retrieves all global DHCP options.
|
|
|
```sql
|
|
|
SELECT * FROM global_option4;
|
|
|
```
|
|
|
|
|
|
The following query retrieves all global configuration parameters, other than options, option definitions, subnets and shared networks.
|
|
|
```sql
|
|
|
SELECT * FROM global_parameter4;
|
|
|
```
|
|
|
|
|
|
Note that each query above would retrieve the entire table's content, even if only incremental changes have been applied to the configuration. For example: adding a new option definition will cause the server to fetch all existing option definitions and merge them with the option definitions it knows about. In the future we may apply similar optimizations to those queries as we use for subnets (see below), however as of Kea 1.4.0 release incremental modifications of options, option definitions or global parameters aren't supported in Kea, so such optimizations would not be used.
|
|
|
|
|
|
The following query retrieves all IPv4 subnets, e.g. upon server startup.
|
|
|
```sql
|
|
|
SELECT * FROM subnet4;
|
|
|
```
|
|
|
|
|
|
The following query fetches a specific subnet by prefix taking advantage of the search index on *subnet_prefix*.
|
|
|
```sql
|
|
|
SELECT * FROM subnet4 WHERE subnet_prefix="192.0.2.0/24";
|
|
|
```
|
|
|
|
|
|
The following query fetches a specific subnet by subnet identifier taking advantage of the search index in *subnet_id*.
|
|
|
```sql
|
|
|
SELECT * FROM subnet4 WHERE subnet_id=100;
|
|
|
```
|
|
|
|
|
|
The following query catches incremental changes applied to some of the subnets and newly added subnets. The *modification_ts* column holds timestamp indicating when the particular subnet have been modified (or added). The server keeps track of the most recent modification time across all subnets. This modification time is used to find more recent modifications (modification_ts is greater than the example time of '2018-01-01 01:01:00'). This would be enough in relational databases where an index would be applied on the *modification_ts* column. In Cassandra, the *greater than* operator can be used on the data belonging to a particular partition and the partition must be selected with some partition key using equality operator. For that reason the *modification_ts* can't be used as a primary key because we need to use *greater than* operator. Instead, the artificial partition key *modification_seq* has been introduced which is meant to hold a value known by the server (or which can be easily computed by the server) which is also used to evenly partition the subnets. The *modification_seq* should contain a day of month (or an hour of day) extracted from the *modification_ts* timestamp. A server which is periodically polling the database for changes would use the current day as a partition key and will fetch all subnet modifications within that day. That assumes that the server is polling much more frequently for the configuration changes than once a day. In order to handle the case when the new changes have been applied before the midnight and the server is polling after the midnight, the server should also fetch all modifications from the previous day applied later than the timestamp it is using. Obviously, this selection of the partition key implies that all subnets modified at certain day belong to the same partition.
|
|
|
```sql
|
|
|
SELECT * FROM subnet4 WHERE modification_seq IN (22, 23) AND modification_ts > '2018-01-01 01:01:00';
|
|
|
```
|
|
|
|
|
|
The following query fetches all shared networks.
|
|
|
```sql
|
|
|
SELECT * FROM shared_network4;
|
|
|
```
|
|
|
|
|
|
## Configuration Deletion
|
|
|
|
|
|
Suppose that an administrator wants to delete a particular piece of Kea server configuration from the database, e.g. remove a subnet. A naive approach would be to simply send an SQL DELETE statement to the database to delete appropriate row or rows. This approach is already used for host reservations. However, there is a significant issue which makes it inappropriate in this case.
|
|
|
|
|
|
The Kea configuration may be extensive, e.g. may contain many subnets. Introducing incremental changes, such as removal of a subnet should not cause the server to reload the entire configuration. When a new subnet is added or an existing subnet is updated it is sufficient for the server to fetch all subnets with the *modification_ts* value greater than certain timestamp it remembers, to detect which subnets have been lately added or modified. This is not enough to detect which subnets have been removed from the configuration. If the subnet information is simply deleted from the database the server can merely determine that the number of subnets has changed and that is only the case if no new subnet have been added right after deleting the other one.
|
|
|
|
|
|
In order to determine which subnet have been removed from the configuration without a need to reload the entire list of subnets, the subnet information must be retained in the database and marked as removed. The *modification_type* column will be used for that purpose. In fact, all tables holding the information associated with this subnet can be marked as removed too. However, if the subnet is removed the server won't use associated pools and options anyway, so marking all associated objects as removed may be unnecessary in many cases.
|
|
|
|
|
|
If the subnet information about removed subnet is preserved in the database it poses two new issues to be solved. If new subnet is going to be added with the same prefix or subnet id it will conflict with the removed subnet information. Using *modification_type* as a part of the primary key for each table would mitigate this problem because it would be possible to have two objects with duplicate subnet id/subnet prefix but with different modification type value. This wouldn't, however, eliminate the problem when two subnets with the same id are marked as deleted. Perhaps the easiest solution is to simply add a parameter to the control commands to force remove the configuration information, in which case the information would be deleted from the database upon reception of the command.
|
|
|
|
|
|
Another issue is that the information about removed subnets should ultimately be deleted from the database. In many cases it could be done once the Kea server determines that the subnet was removed and updates its local (in-memory) configuration. This is not always a viable solution because in some deployments there might be multiple Kea servers connected to the same database instance. All these servers must learn about the configuration changes, in particular about the removal of the subnet, before stale subnet information can be removed. As there is typically no coordination between the Kea instances the only viable option seems to be to add a configurable timer which triggers deletion of the stale data periodically. For example, for MySQL:
|
|
|
|
|
|
```sql
|
|
|
DELETE FROM subnet4 WHERE DATE_SUB(modification_ts, INTERVAL 120 SECOND);
|
|
|
```
|
|
|
|
|
|
Note that such cleanup task would need to be performed on multiple tables in certain order. Therefore, it would be best to embed it in an SQL routine and call this routine periodically. In Cassandra, it may require issuing multiple queries instead because creating a database side routine involves Java programming.
|
|
|
|
|
|
## Config File Updates
|
|
|
|
|
|
In the Kea 1.5.0 release, only selected parts of the configuration can be held in the database. Other parts will still be configured via configuration file. The server will fetch configuration available for the Kea server from the database and merge it into the local configuration from the file.
|
|
|
|
|
|
The configuration file will include a new configuration element *config-databases* specifying database connection information. For example:
|
|
|
|
|
|
```json
|
|
|
"config-databases" [ {
|
|
|
"type": "mysql",
|
|
|
"name": "kea",
|
|
|
"user": "kea",
|
|
|
"password": "kea",
|
|
|
} ]
|
|
|
```
|
|
|
|
|
|
This new parameter is a list of maps with each list element specifying connection information to a single backend. Similarly to *hosts-database* case, the server will be able to use multiple database configuration backends simultaneously.
|
|
|
|
|
|
In addition, the server configuration file will include an optional *server-tag* string parameter which value will be used to search for configuration elements in the database for that server. If this parameter is not specified or empty the server instance is considered untagged and only untagged (common) configuration parameters will be retrieved from the database for that server.
|
|
|
|
|
|
The server tag is specified at the global configuration level, e.g.:
|
|
|
```
|
|
|
{
|
|
|
"Dhcp4": {
|
|
|
"server-tag": "shellfish123",
|
|
|
...
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Multiple server instances can use the same server tag if they are supposed to use the same configuration.
|
|
|
|
|
|
## Encoding "unspecified" Timers
|
|
|
|
|
|
The DHCP configuration includes protocol timers such as "renew-timer", "rebind-timer" etc. These timers may be set to the following values:
|
|
|
- "unspecified", which is assigned when the timer is not specified in the server configuration
|
|
|
- 0 (zero) - which is a valid value sent in T1 field and indicates that the client should determine when to renew.
|
|
|
- greater than 0 - which is an explicit value to be sent to the client. The client must start renewing when this time elapses.
|
|
|
|
|
|
The first case ("unspecified") is handled differently than the second case. If the value is unspecified the server would attempt to calculate the respective times from the percentage values specified as "t1-percentage" and "t2-percentage". Therefore, the subnet information stored in the database must mirror all three cases.
|
|
|
|
|
|
The DHCP timers are represented by the `Triplet` template in Kea. It has three constructors. The parameterless constructor sets the value to "unspecified". The CB must use this constructor to set the timer value to "unspecified" when the value fetched from the database is NULL. Otherwise, it should use the constructor that sets it to an explicit value.
|
|
|
|
|
|
Similarly, when the CB stores the subnet in the database, it should check if the triplet value is "unspecified", and if it is, the NULL value should be stored in the database.
|
|
|
|
|
|
Currently, the only case when the subnet parser sets a timer value to "unspecified" is when the corresponding configuration parameter is not provided. Therefore, if the `remote-subnet4-set` command is sent to update the timer to "unspecified", the subnet information within this command must exclude the timer value (e.g. exclude "renew-timer"). In the future we may also allow for explicitly specifying:
|
|
|
```
|
|
|
"renew-timer": null,
|
|
|
"rebind-timer": null
|
|
|
```
|
|
|
|
|
|
to indicate that the new values of the timers should become "unspecified". However, this is currently not supported by our parsers and won't be available in the Kea 1.6.0 release.
|
|
|
|
|
|
The DHCP protocol timers can also be specified at the global level. The global level parameters must always be non-NULL in the database. In order to indicate that the global "renew-timer" or "rebind-timer" is NULL, it must be deleted from the database. When the server fails to find the timer value in the database it will assume it is "unspecified".
|
|
|
|
|
|
## Encoding other "unspecified" parameters
|
|
|
|
|
|
The Config Backend API uses Subnet4, Subnet6, SharedNetwork4 and SharedNetwork6 objects to represent the data to be stored in the database. These objects are currently created in the `cb_cmds` hooks library in two steps: derive the defaults and then run the dhcpsrv parsers. This is similar to `subnet_cmds`, but has significant implications for the Kea servers fetching the subnets and shared network configurations. The default values are set for the parameters which are not specified by the user. The subnet is stored in the database with these parameters and from the server perspective it looks as if the parameters were explicitly specified. The information that the parameter was actually not specified is lost. As a result the global parameters are not applied for the subnet, because the subnet already includes the values set as defaults.
|
|
|
|
|
|
In order to address this problem we first have to remove setting the defaults in the `cb_cmds` hooks library. The values that are not specified should be set to null in the database. In order to represent unspecified values in the subnet we have to use the `OptionalValue` template to encapsulate the optional subnet and shared network parameters. The values that were not explicitly set for the subnet should be marked as unspecified in the `OptionalValue` instances. The subnet and shared network API must be modified to return `OptionalValue` objects rather than the actual value. The Config Backends must interpret the unspecified values as null when they are inserted and fetched from the database. When the server finds that a subnet parameter is unspecified it should use the higher level value, e.g. a global value.
|
|
|
|
|
|
# Configuration Backend Structure
|
|
|
|
|
|
## Class Diagram
|
|
|
|
|
|
The Configuration Backend feature must be structured to satisfy several constraints:
|
|
|
|
|
|
* respective Kea servers and associated management hooks libraries should not need to include the unrelated code, e.g. CA should not need include/link with libkea-dhcpsrv to use the configuration backend feature
|
|
|
* specific implementations of the Configuration Backend, e.g. MySQL, should be best isolated into separate modules so as they can be used optionally.
|
|
|
|
|
|
The following diagram segregates parts of the Configuration Backend system into separate packages/libraries. We may decide that such fine grained split is not desired for Kea 1.5.0 release, but this split is considered to give the most flexibility.
|
|
|
|
|
|
![kea-config-backend-class-diagram.svg](/uploads/890850533be68fe136a16c7d1245ef73/kea-config-backend-class-diagram.svg)
|
|
|
|
|
|
The BaseConfigBackendMgr is a base class for Config Backend managers used by respective Kea servers. It merely provides means for registering *factory* functions used to create instances of various backends and creating instances of those backends using database access strings. Derived classes will typically provide functions to access them as singletons and will use specific ConfigurationBackendPool classes as template arguments.
|
|
|
|
|
|
Unlike LeaseMgr or HostMgr, neither BaseConfigurationBackendMgr nor derived classes provide APIs for managing configuration information in the database. The APIs for respective servers are provided by the derivations of the BaseConfigurationBackendPool class. Each ConfigurationBackendMgr contains exactly one pool of backends. Each pool is used to route calls to the backend instances it holds in the particular order. For example, if the first backend within the pool returns no result for the particular call/query the pool will route the call to the next backend. If neither backend returns configuration data, the pool returns no data to the caller.
|
|
|
|
|
|
Both the pool and the backend must implement the ConfigBackend interface for the specific server. For example, both ConfigBackendPoolDHCPv4 and the MySQLConfigBackendDHCPv4 implement the ConfigBackendDHCPv4 interface defined in libkea-dhcpsrv.
|
|
|
|
|
|
The MySQL specific classes, i.e. MySQLConfigBackendD2, MySQLConfigBackendDHCPv4, MySQLConfigBackendDHCPv6 and MySQLConfigBackendCA are implemented within a separate library libkea-cb-mysql, which can either be a regular library linked with Kea or a hooks library. The corresponding libraries for Postgres and Cassandra will be stored in their own libraries.
|
|
|
|
|
|
## Config Backend Interface for DHCPv4
|
|
|
|
|
|
The following picture shows all operations to be supported by the DHCPv4 Configuration Backend in Kea 1.5.0.
|
|
|
|
|
|
![kea-config-backend-dhcp4-interface.svg](/uploads/5ef40c83d68f12f0a6b9dd8ac8d76bd7/kea-config-backend-dhcp4-interface.svg)
|
|
|
|
|
|
## Config Backend Interface for DHCPv6
|
|
|
|
|
|
The following picture shows all operations to be supported by the DHCPv4 Configuration Backend in Kea 1.5.0.
|
|
|
|
|
|
![kea-config-_backend-dhcp6-interface.svg](/uploads/f0afeeb1f20eb3d6be0e3202c119b565/kea-config-_backend-dhcp6-interface.svg)
|
|
|
|
|
|
## Config Backend Interfaces for CA and D2
|
|
|
|
|
|
The interfaces for the Control Agent and DHCP DDNS daemons will be designed at a later time as they are not planned to be implemented for the Kea 1.5.0 release.
|
|
|
|
|
|
## Backend Implementation Example
|
|
|
|
|
|
The following picture illustrates a very simplified example of the backend implementation for the DHCPv4 server. Each backend implements a single data access function *getSubnet*.
|
|
|
|
|
|
![kea-config-backend-inheritance-class-diagram.svg](/uploads/0cec7744d69074b44eaa3b6b44691778/kea-config-backend-inheritance-class-diagram.svg)
|
|
|
|
|
|
The following is the C++ code used in this example:
|
|
|
|
|
|
```c++
|
|
|
class ConfigBackendDHCPv4 {
|
|
|
public:
|
|
|
|
|
|
virtual ~ConfigBackendDHCPv4() {
|
|
|
}
|
|
|
|
|
|
virtual std::string getSubnet(const int subnet_id) = 0;
|
|
|
|
|
|
};
|
|
|
|
|
|
class MySQLConfigBackendDHCPv4 : public BaseConfigBackend, public ConfigBackendDHCPv4 {
|
|
|
public:
|
|
|
|
|
|
virtual std::string getSubnet(const int subnet_id) {
|
|
|
if (subnet_id == 0) {
|
|
|
return ("subnet0");
|
|
|
|
|
|
}
|
|
|
|
|
|
return ("");
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
typedef boost::shared_ptr<MySQLConfigBackendDHCPv4> MySQLConfigBackendDHCPv4Ptr;
|
|
|
|
|
|
class PgSQLConfigBackendDHCPv4 : public BaseConfigBackend, public ConfigBackendDHCPv4 {
|
|
|
public:
|
|
|
|
|
|
virtual std::string getSubnet(const int subnet_id) {
|
|
|
if (subnet_id == 1) {
|
|
|
return ("subnet1");
|
|
|
}
|
|
|
|
|
|
return ("");
|
|
|
}
|
|
|
};
|
|
|
|
|
|
typedef boost::shared_ptr<PgSQLConfigBackendDHCPv4> PgSQLConfigBackendDHCPv4Ptr;
|
|
|
|
|
|
|
|
|
class ConfigBackendPoolDHCPv4 : public BaseConfigBackendPool, public ConfigBackendDHCPv4 {
|
|
|
public:
|
|
|
|
|
|
virtual std::string getSubnet(const int subnet_id) {
|
|
|
for (auto backend : backends_) {
|
|
|
auto v = boost::dynamic_pointer_cast<ConfigBackendDHCPv4>(backend)->getSubnet(subnet_id);
|
|
|
if (!v.empty()) {
|
|
|
return (v);
|
|
|
}
|
|
|
}
|
|
|
return ("");
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
class DHCPConfigBackendMgr : public BaseConfigBackendMgr<ConfigBackendPoolDHCPv4> {
|
|
|
public:
|
|
|
|
|
|
// More functions here
|
|
|
|
|
|
};
|
|
|
```
|
|
|
|
|
|
And this is the test code that uses the backend implementation:
|
|
|
|
|
|
```c++
|
|
|
TEST(ConfigBackendMgrTest, basic) {
|
|
|
|
|
|
ConfigBackendMgrDHCPv4 dhcp_mgr;
|
|
|
|
|
|
dhcp_mgr.registerBackendFactory("mysql", [](const DatabaseConnection::ParameterMap&)
|
|
|
-> BaseConfigBackendPtr {
|
|
|
return (MySQLConfigBackendDHCPv4Ptr(new MySQLConfigBackendDHCPv4()));
|
|
|
});
|
|
|
|
|
|
dhcp_mgr.registerBackendFactory("postgres", [](const DatabaseConnection::ParameterMap&)
|
|
|
-> BaseConfigBackendPtr {
|
|
|
return (PgSQLConfigBackendDHCPv4Ptr(new PgSQLPConfigBackendDHCPv4()));
|
|
|
});
|
|
|
|
|
|
dhcp_mgr.addBackend("type=mysql");
|
|
|
dhcp_mgr.addBackend("type=postgres");
|
|
|
|
|
|
EXPECT_EQ("subnet0", dhcp_mgr.getPool()->getSubnet(0));
|
|
|
EXPECT_EQ("subnet1", dhcp_mgr.getPool()->getSubnet(1));
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## Existing Code Refactoring
|
|
|
|
|
|
The architecture described in the previous sections requires that the existing code (Kea 1.4.0) is refactored to move certain classes pertaining to the database management from libkea-dhcpsrv to new libraries. This, in turn, will impact some existing hooks libraries using those classes as they will have to include headers and link with libraries being in a new location.
|
|
|
|
|
|
The following common classes are proposed to be moved to a new library **libkea-database**:
|
|
|
* DbExceptions (db_exceptions.h)
|
|
|
* DbLogger (db_logger.h, db_logger.cc)
|
|
|
* DatabaseConnection (database_connection.h, database_connection.cc)
|
|
|
|
|
|
The MySQL, Postgres and Cassandra specific general purpose classes should be used to their own
|
|
|
libraries, e.g.:
|
|
|
|
|
|
* libkea-mysql
|
|
|
* libkea-pgsql
|
|
|
* libkea-cql
|
|
|
|
|
|
For example, in case of *libkea-mysql* it would be:
|
|
|
* MySqlConnection (mysql_connection.h, mysql_connection.cc)
|
|
|
|
|
|
and perhaps any additional classes created as part of the designed feature.
|
|
|
|
|
|
# Control Commands
|
|
|
|
|
|
The CB specific commands are going to be implemented in the new cb_cmds hooks library. The following sections describe the commands to be supported for the respective servers.
|
|
|
|
|
|
## Naming conventions
|
|
|
|
|
|
The commands supported by the cb_cmds hooks library follow the naming rules that group similar commands together when sorted alphabetically. All commands start with the prefix `remote-`, which indicates that the commands are used to manipulate the data in a remote location (database).
|
|
|
|
|
|
The naming scheme can be presented as follows:
|
|
|
|
|
|
```
|
|
|
remote-[what][4|6]-[level]-[operation]-by-[access-keys]
|
|
|
```
|
|
|
|
|
|
The `[what]` designates a configured object, e.g. a subnet. The `[4|6]` part indicates if the configured object is DHCPv4 or DHCPv6 specific. This part is optional for non-DHCP daemons, e.g. Control Agent. The `[level]` is also optional and it designates the level of the configured object in the configuration hierarchy, e.g. global, subnet, pool etc.
|
|
|
|
|
|
The `[operation]` is mandatory and can be one of the following:
|
|
|
- `[del]` - delete objects.
|
|
|
- `[get]` - get one or multiple objects by some keys.
|
|
|
- `[get-all]` - get all objects of a specific type.
|
|
|
- `[get-modified]` - get all objects which have been added, updated or deleted after a certain time.
|
|
|
- `[list]` - similar to `[get-all]` but returns brief information about the objects, e.g. a list of subnet ids and prefixes, but excludes the rest of the subnets information.
|
|
|
- `[set]` - add or update objects.
|
|
|
|
|
|
The `[access-keys]` are optional. They are the names of the properties of the fetched objects which are used as the selection keys. If a given command has multiple variants that differs by access keys the access keys should be included in the command name. If the command is intended to have only one variant the access keys can be dropped from the command name.
|
|
|
|
|
|
The `-by-` prefix must only be included if the access keys are specified.
|
|
|
|
|
|
## GET Command Structures
|
|
|
|
|
|
One of the design goals for the commands is to keep their structures consistent to minimize the amount of the special code to be written for the individual commands. The ISC team members debated about the structures of the commands used to fetch the configuration objects by keys and came up with the following scheme:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-[what][4|6]-[operation]-by-[access-keys]",
|
|
|
"arguments": {
|
|
|
"[plural-object-name]": [
|
|
|
{
|
|
|
"[access-key-1]": [value-of-access-key-1],
|
|
|
"[access-key-2]": [value-of-access-key-2]
|
|
|
},
|
|
|
...
|
|
|
]
|
|
|
},
|
|
|
"remote": {
|
|
|
[backend-selectors]
|
|
|
},
|
|
|
"server-tags": [ "[server-tag-1]", "[server-tag-2]" ]
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Where the `[plural-object-name]` can be but is not limited to:
|
|
|
- subnets
|
|
|
- shared-networks
|
|
|
- parameters (for global parameters)
|
|
|
- option-defs
|
|
|
- options
|
|
|
|
|
|
And the corresponding response is:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": [result],
|
|
|
"text": [text],
|
|
|
"arguments": {
|
|
|
"[plural-object-name]": [
|
|
|
{
|
|
|
[object-details]
|
|
|
},
|
|
|
...
|
|
|
]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## DHCPv4 Specific Commands List
|
|
|
|
|
|
The following commands for managing the DHCPv4 server configuration will be supported in the Kea 1.6.0 release. Also see the footnotes for selected commands.
|
|
|
|
|
|
1. remote-server4-del
|
|
|
1. remote-server4-get
|
|
|
1. remote-server4-get-all
|
|
|
1. remote-server4-set
|
|
|
1. remote-global-parameter4-del
|
|
|
1. remote-global-parameter4-get
|
|
|
1. remote-global-parameter4-get-all
|
|
|
1. remote-global-parameter4-set
|
|
|
1. remote-option4-global-del
|
|
|
1. remote-option4-global-get
|
|
|
1. remote-option4-global-get-all
|
|
|
1. remote-option4-global-set
|
|
|
1. remote-option-def4-del
|
|
|
1. remote-option-def4-get
|
|
|
1. remote-option-def4-get-all
|
|
|
1. remote-option-def4-set
|
|
|
1. remote-network4-del
|
|
|
1. remote-network4-get
|
|
|
1. remote-network4-list
|
|
|
1. remote-network4-set
|
|
|
1. remote-subnet4-del-by-id
|
|
|
1. remote-subnet4-del-by-prefix
|
|
|
1. remote-subnet4-get-by-id
|
|
|
1. remote-subnet4-get-by-prefix
|
|
|
1. remote-subnet4-list
|
|
|
1. remote-subnet4-set
|
|
|
|
|
|
The following command are under consideration for implementation sometime later. They're out of scope for 1.6.0:
|
|
|
|
|
|
1. remote-global-parameter4-del-all [^2]
|
|
|
1. remote-global-parameter4-get-modified [^2]
|
|
|
1. remote-option4-global-del-all [^2]
|
|
|
1. remote-option4-global-get-modified [^2]
|
|
|
1. remote-option-def4-del-all [^2]
|
|
|
1. remote-option-def4-get-modified [^2]
|
|
|
1. remote-network4-del-all [^2]
|
|
|
1. remote-network4-get-all [^2]
|
|
|
1. remote-network4-get-modified [^2]
|
|
|
1. remote-network4-list-modified [^2]
|
|
|
1. remote-subnet4-del-all [^2]
|
|
|
1. remote-subnet4-list-modified [^2]
|
|
|
|
|
|
[^2]: Usefulness of this command is doubtful or the command may be dangerous if misused. Therefore, it has low priority and will only be implemented if there are specific use cases identified and the agreement between the team members is reached that it is required.
|
|
|
|
|
|
## DHCPv4 Specific Commands Examples
|
|
|
|
|
|
### remote-server4-del
|
|
|
|
|
|
This command attempts to delete a single server. Associated global parameters, options and option definitions are deleted. Associated subnets and shared networks are disassociated.
|
|
|
|
|
|
Note it is not allowed to delete the 'all' server.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-server4-del"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"servers": [
|
|
|
{
|
|
|
"server-tag": "server1"
|
|
|
}
|
|
|
],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "1 DHCPv4 server(s) deleted.",
|
|
|
"arguments": {
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-server4-get
|
|
|
|
|
|
This command retrives a server.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-server4-get"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"servers": [
|
|
|
{
|
|
|
"server-tag": "server1"
|
|
|
}
|
|
|
],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 server 'server1' found.",
|
|
|
"arguments": {
|
|
|
"servers": [
|
|
|
{
|
|
|
"server-tag": "server1",
|
|
|
"description": "server 1 on ground floor"
|
|
|
}
|
|
|
],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-server4-get-all
|
|
|
|
|
|
This command retrieves all servers. Note the 'all' server always exists.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-server4-get-all"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "2 DHCPv4 server(s) found.",
|
|
|
"arguments": {
|
|
|
"servers": [
|
|
|
{
|
|
|
"server-tag": "all",
|
|
|
"description": "special type: all servers"
|
|
|
},
|
|
|
{
|
|
|
"server-tag": "server1",
|
|
|
"description": "server 1 on ground floor"
|
|
|
}
|
|
|
],
|
|
|
"count": 2
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-server4-set
|
|
|
|
|
|
This command attempts to create or update an existing server. It is not allowed to update the 'all' server.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-server4-set"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"servers": [
|
|
|
{
|
|
|
"server-tag": "server1",
|
|
|
"description": "server 1 on ground floor"
|
|
|
}
|
|
|
],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 server successfully set.",
|
|
|
"arguments": {
|
|
|
"servers": [
|
|
|
{
|
|
|
"server-tag": "server1",
|
|
|
"description": "server 1 on ground floor"
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-global-parameter4-del
|
|
|
|
|
|
This command deletes a global parameter associated with a given server or all servers. The `parameters` list must contain exactly one parameter name. The `server-tags` list is required and must contain exactly one server tag. If the server tag points to the user defined server, the command attempts to delete the server specific value (associated with this server). If there is no server specific value for this parameter and the server is using the value specified for 'all' servers, no value is deleted. In order to delete the global parameter value associated with 'all' servers, the server tag "all" must be specified instead.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-global-parameter4-del"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"log-message": "deleted boot-file-name global parameter",
|
|
|
"parameters": [ "boot-file-name" ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 global parameter successfully deleted.",
|
|
|
"arguments": {
|
|
|
"parameters": [ {
|
|
|
"name": "boot-file-name"
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-global-parameter4-get
|
|
|
|
|
|
This command retrieves a value of the global parameter associated with a given server or all servers. The list of parameters must contain exactly one parameter name. The `server-tags` list is mandatory and it must contain exactly one server tag. If there is an explicit value for this parameter associated with this server, this value is returned. If there is no explicit value associated with the given server, the value for 'all' servers is returned if it is specified. In order to retrieve the value associated with all servers, use the server tag "all".
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-global-parameter4-get"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"parameters": [ "boot-file-name" ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "'boot-file-name` DHCPv4 global parameter found.",
|
|
|
"arguments": {
|
|
|
"parameters": {
|
|
|
"boot-file-name": "/dev/null",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
},
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Note that the returned values are not limited to strings (as in the example above). The other types of returned values are: integer, boolean and real.
|
|
|
|
|
|
### remote-global-parameter4-get-all
|
|
|
|
|
|
This command is similar to the `remote-global-parameter4-get` but it returns all global parameters for a given server or for all servers. It requires `server-tags` list and this list must contain exactly one server tag. It can be a tag of any user defined server or "all". If the server tag points to a user defined server, the command will return all global parameters to be used by this server. For each parameter which has an explicit value associated with the server tag, it returns this parameter. For each parameter for which there is no explicit value for the given server tag, it returns the value associated with 'all' servers, if it exists.
|
|
|
|
|
|
In order to retrieve only global parameters associated with 'all' servers, the server tag "all" should be specified.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-global-parameter4-get-all"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 global parameters found.",
|
|
|
"arguments": {
|
|
|
"parameters": [
|
|
|
{
|
|
|
"boot-file-name": "/dev/null",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
"renew-timer": 3600,
|
|
|
"metadata": {
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
"count": 2
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Note that the response contains a list of parameters and some of the parameters may be associated with the "all" servers and some with the specified server - "server1" in this case. Note that even the server-tag is a global parameter it is not included here. To retrieve the server tag of a server please use the "server-tag-get" command.
|
|
|
|
|
|
### remote-global-parameter4-set
|
|
|
|
|
|
This command conveys the following types of parameters: string, integer, boolean, real. The server detects the type of the specified parameter based on the encoding of the conveyed value. The type is stored in the database along with the value which is converted to a string for storage.
|
|
|
|
|
|
The `server-tags` list is required for this command and this list must include exactly one server tag. If the server tag is set to "all", the command will associated the new value with 'all' servers. If it contains a server tag for user defined server, the value is associated with this particular server.
|
|
|
|
|
|
#### String variant
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-global-parameter4-set"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"log-message": "added boot-file-name global parameter",
|
|
|
"parameters": {
|
|
|
"boot-file-name": "/dev/null"
|
|
|
},
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 global parameter successfully set.",
|
|
|
"arguments": {
|
|
|
"parameters": {
|
|
|
"boot-file-name": "/dev/null"
|
|
|
},
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### Integer variant
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-global-parameter4-set"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"log-message": "added renew timer of 30",
|
|
|
"parameters": {
|
|
|
"renew-timer": 30
|
|
|
},
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### Boolean variant
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-global-parameter4-set"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"log-message": "echo-client-id set to true",
|
|
|
"parameters": {
|
|
|
"echo-client-id": true
|
|
|
},
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### Real variant
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-global-parameter4-set"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"log-message": "some parameter I made up set to 1.4",
|
|
|
"parameters": {
|
|
|
"elevation": 1.4
|
|
|
},
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-option4-global-del
|
|
|
|
|
|
This command attempts to delete a single global option for a given server or 'all' servers. The `server-tags` list is mandatory and it must contain exactly one server tag. In order to delete the global option associated with all servers, the 'all' server tag must be specified. If the server tag points to a particular server, the option specific to this server is deleted. If there is no explicit value for the given server, no option is deleted. In particular the option specific to 'all' servers is preserved.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option4-global-del",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"options": [ {
|
|
|
"code": 6,
|
|
|
"space": "dhcp4"
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 option successfully deleted.",
|
|
|
"arguments": {
|
|
|
"options": [ {
|
|
|
"code": 6,
|
|
|
"space": "dhcp4"
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-option4-global-get
|
|
|
|
|
|
This command retrieves a global option for the particular server. If such option is not explicitly specified for that server, the 'all' specific value is returned if it exists. The `server-tags` parameter is required and it must contain exactly one server tag. If the option instance for 'all' servers is to be returned, the "all" server tag must be specified.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option4-global-get"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"options": [ {
|
|
|
"code": 6,
|
|
|
"space": "dhcp4"
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 option 6 in 'dhcp4' found.",
|
|
|
"arguments": {
|
|
|
"options": [
|
|
|
{
|
|
|
"name": "domain-name-servers",
|
|
|
"code": 6,
|
|
|
"space": "dhcp4",
|
|
|
"csv-format": false,
|
|
|
"data": "C0 00 03 01 C0 00 03 02",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Note that the returned option contains metadata which indicates which servers it is associated with. In the example above, the option is associated with the server1. If there is no such option for the server1 but the option returned is for 'all' servers, the "all" server tag is included in the metadata instead.
|
|
|
|
|
|
### remote-option4-global-get-all
|
|
|
|
|
|
This command retrieves all global options to be used by the given server. The server specific options take precedence over the options specified for 'all' servers. If there is no server specific option found, but there is an option specified for 'all' servers, the latter is returned. The `server-tags` map is required and it must contain exactly one server tag. If only options specific to 'all' servers are desired, the "all" server tag should be included.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option4-global-get-all"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 options found.",
|
|
|
"arguments": {
|
|
|
"options": [
|
|
|
{
|
|
|
"name": "domain-name-servers",
|
|
|
"code": 6,
|
|
|
"space": "dhcp4",
|
|
|
"csv-format": false,
|
|
|
"data": "C0 00 03 01 C0 00 03 02",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
},
|
|
|
...
|
|
|
],
|
|
|
"count": 5
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
In the example above, one of the returned options is marked as belonging to 'all' servers in the metadata map. Other returned options may belong to 'all' servers or to a given server as indicated by the respective metadata maps.
|
|
|
|
|
|
### remote-option4-global-set
|
|
|
|
|
|
This command attempts to create or update an existing global option for the given server as indicated by the server tag. The `server-tag` list is mandatory and must include exactly one server tag. If the new global option must be associated with 'all' servers, the server tag "all" must be specified.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option4-global-set",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"options": [ {
|
|
|
"code": 6,
|
|
|
"space": "dhcp4",
|
|
|
"data": "192.0.2.1, 192.0.2.2"
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 option successfully set.",
|
|
|
"arguments": {
|
|
|
"options": [ {
|
|
|
"code": 6,
|
|
|
"space": "dhcp4"
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-option-def4-del
|
|
|
|
|
|
This command attempts to delete an option definition for the specified server or for 'all' servers. The `server-tags` parameter is required and must include exactly one server tag or "all". If the option definition is associated with the given server it is deleted for this server. If there is another option definition specified for 'all' servers the value for 'all' servers is not deleted. In order to delete the value associated with 'all' server, the "all" server tag must be used.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option-def4-del",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"option-defs": [ {
|
|
|
"name": "foo",
|
|
|
"code": 222
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 option definition successfully deleted.",
|
|
|
"arguments": {
|
|
|
"option-defs": [ {
|
|
|
"code": 222,
|
|
|
"space": "dhcp4"
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-option-def4-get
|
|
|
|
|
|
This command retrieves an option definition for a given server or for all servers. The `server-tags` parameter is required and must include exactly one server tag. If the server tag points to any particular server, the server will try to fetch the option definition associated with this server. If the option definition for that server doesn't exist, the instance of the option definition for 'all' servers is returned. If the option definition for 'all' servers doesn't exist, no option definition is returned. In order to fetch the option definition associated with 'all' servers, the "all" server tag should be used.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option-def4-get"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"option-defs": [ {
|
|
|
"code": 6,
|
|
|
"space": "dhcp4"
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 option definition 222 in 'dhcp4' found.",
|
|
|
"arguments": {
|
|
|
"option-defs": [ {
|
|
|
"name": "foo",
|
|
|
"code": 222,
|
|
|
"type": "uint32",
|
|
|
"array": false,
|
|
|
"record-types": "",
|
|
|
"space": "dhcp4",
|
|
|
"encapsulate": ""
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-option-def4-get-all
|
|
|
|
|
|
This command retrieves all global option definitions to be used by the given server. The server specific option definitions take precedence over the definitions specified for 'all' servers. If there is no server specific option definitions found, but there is an option definition specified for 'all' servers, the latter is returned. The `server-tags` map is required and it must contain exactly one server tag. If only options specific to 'all' servers are desired, the "all" server tag should be included.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option-def4-get-all"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 option definitions found.",
|
|
|
"arguments": {
|
|
|
"option-defs": [
|
|
|
{
|
|
|
"name": "foo",
|
|
|
"code": 222,
|
|
|
"type": "uint32",
|
|
|
"array": false,
|
|
|
"record-types": "",
|
|
|
"space": "dhcp4",
|
|
|
"encapsulate": ""
|
|
|
}
|
|
|
....
|
|
|
],
|
|
|
"count": 7
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
### remote-option-def4-set
|
|
|
|
|
|
This command attempts to create or update an existing global option definition for the given server as indicated by the server tag. The `server-tag` list is mandatory and must include exactly one server tag. If the new global option definition must be associated with 'all' servers, the server tag "all" must be specified.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-option-def4-set",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"option-defs": [ {
|
|
|
"name": "foo",
|
|
|
"code": 222,
|
|
|
"type": "uint32",
|
|
|
"array": false,
|
|
|
"record-types": "",
|
|
|
"space": "dhcp4",
|
|
|
"encapsulate": ""
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 option definition successfully set.",
|
|
|
"arguments": {
|
|
|
"option-defs": [ {
|
|
|
"code": 222,
|
|
|
"space": "dhcp4"
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-network4-del
|
|
|
|
|
|
#### Delete Network but Keep Subnets
|
|
|
|
|
|
The following command contains an optional "subnets-action" parameter set to a default value "keep" which indicates that the subnets contained within the deleted network must not be deleted. When this command successfully executes, the shared network is dissociated from the subnets and removed. The subnets remain in the top level scope for subnets. Omitting the "subnets-action" parameter will have the same effect.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-network4-del",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"shared-networks": [ {
|
|
|
"name": "floor13"
|
|
|
} ],
|
|
|
"subnets-action": "keep",
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 shared network successfully deleted.",
|
|
|
"arguments": {
|
|
|
"shared-networks": [ {
|
|
|
"name": "floor13"
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### Delete Network and Subnets
|
|
|
|
|
|
The following command contains an optional "subnets-action" parameter set to a value "delete" which indicates that the subnets contained within the deleted network must be deleted along with the shared network. When this command successfully executes, the shared network and all the subnets it contained are removed.
|
|
|
|
|
|
The `server-tags` parameter must not be specified for this command. The shared networks are uniquely identified by their names and may be shared by multiple servers (may be associated with multiple tags).
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-network4-del",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"shared-networks": [ {
|
|
|
"name": "floor13"
|
|
|
} ],
|
|
|
"subnets-action": "delete",
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 shared network successfully deleted.",
|
|
|
"arguments": {
|
|
|
"shared-networks": [ {
|
|
|
"name": "floor13"
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-network4-get
|
|
|
|
|
|
The `server-tags` parameter must not be specified in this command because the shared network is uniquely identified by its name and may be shared by multiple servers.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-network4-get"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"shared-networks": [ {
|
|
|
"name": "floor1"
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "IPv4 shared network 'floor1' found.",
|
|
|
"arguments": {
|
|
|
"shared-network": [ {
|
|
|
"name": "floor1",
|
|
|
...
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-network4-list
|
|
|
|
|
|
The `server-tags` parameter is required for this command. It is allowed to specify multiple server tags in which the results will be concatenated.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-network4-list"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "IPv4 shared networks found.",
|
|
|
"arguments": {
|
|
|
"shared-networks": [
|
|
|
{
|
|
|
"name": "floor1",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "server1", "server2" ]
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
"name": "floor2",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
"name": "floor3",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
"count": 3
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Note that some of the returned shared networks may be associated with other servers than "server1" as well. One of the returned shared networks is associated with "all" servers because this network is to be used by the server having the "server1" tag as well.
|
|
|
|
|
|
#### Variant Listing Unassigned Shared Networks
|
|
|
|
|
|
In the previous example we have demonstrated how to list the shared networks belonging to a particular server and/or all servers. But, some of the shared networks may be unassigned, i.e. do not belong to any server (orphaned networks). One of the cases when the network may be become orphaned is when the server to which the network is assigned is deleted. All associations of the deleted server are removed from the database automatically, but the networks (and subnets) are left in the database because they may be associated with other servers. In order to list all orphaned shared networks the client must use `null` server tag to indicate that only unassigned shared networks should be returned.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-network4-list"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ null ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
The example response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "IPv4 shared networks found.",
|
|
|
"arguments": {
|
|
|
"shared-networks": [
|
|
|
{
|
|
|
"name": "floor1",
|
|
|
"metadata": {
|
|
|
"server-tags": [ null ]
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Currently, we do not allow for combining explicit server tags with null in the `server-tags` list. For example, it is not allowed to use:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-network4-list"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"server-tags": [ null, "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-network4-set
|
|
|
This command creates or updates information about a shared network. It does not create or modify subnets within the shared networks. An attempt to specify `subnet4` parameter within the shared network specification will result in an error. The subnets can be added to a shared network via the `remote-subnet4-set` command including a `shared-network-name` parameter. When updating an existing shared network using `remote-network4-set` the subnets belonging to this shared network are not modified.
|
|
|
|
|
|
The `server-tags` parameter is mandatory and it may contain one or more server tags. When multiple server tags are specified, the shared network instance is associated with multiple servers.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-network4-set",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"shared-networks": [ {
|
|
|
"name": "floor13",
|
|
|
...
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1", "server2" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 shared network successfully set.",
|
|
|
"arguments": {
|
|
|
"shared-networks": [ {
|
|
|
"name": "floor13"
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-subnet4-del-by-id
|
|
|
|
|
|
The `server-tags` parameter must not be specified for this command because the subnet is uniquely identified by id.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-del-by-id",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"id": 13
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 subnet successfully deleted.",
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"id": 13,
|
|
|
"subnet": "10.20.30.0/24"
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-subnet4-del-by-prefix
|
|
|
|
|
|
The `sever-tags` parameter is not specified for this command because the subnet is uniquely identified by the prefix.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-del-by-prefix",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"subnet": "10.20.30.0/24"
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 subnet successfully deleted.",
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"id": 13,
|
|
|
"subnet": "10.20.30.0/24"
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-subnet4-get-by-id
|
|
|
|
|
|
The `server-tags` parameter must not be specified in this command because the subnet is uniquely identified by id.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-get-by-id"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"id": 123
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "IPv4 subnet 123 found.",
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"id": 123,
|
|
|
"subnet": "192.0.2.0/24",
|
|
|
...,
|
|
|
"metadata": {
|
|
|
"server-tags": [ "server1", "server2" ]
|
|
|
}
|
|
|
} ],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Note that in the example above the returned subnet is associated with multiple servers.
|
|
|
|
|
|
### remote-subnet4-get-by-prefix
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-get-by-prefix"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"subnet": "192.0.2.0/24"
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
The `server-tags` parameter must not be specified for this command because the subnet is uniquely identified by the prefix.
|
|
|
|
|
|
### remote-subnet4-list
|
|
|
|
|
|
#### Variant with Explicit Server Tags
|
|
|
|
|
|
The `server-tags` parameter must be specified for this command. It may include one or more server tags. If multiple server tags are included the results are concatenated.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-list"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "IPv4 subnets found.",
|
|
|
"arguments": {
|
|
|
"subnets": [
|
|
|
{
|
|
|
"id": 123,
|
|
|
"shared-network-name": "level1",
|
|
|
"subnet": "192.0.2.0/24",
|
|
|
"metadata": {
|
|
|
"server-tags": [ "server1", "server2" ]
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
"id": 234,
|
|
|
"shared-network-name": null,
|
|
|
"subnet": "192.0.3.0/24",
|
|
|
"server-tags": [ "server1" ]
|
|
|
},
|
|
|
{
|
|
|
"id": 345,
|
|
|
"shared-network-name": null,
|
|
|
"subnet": "192.0.4.0/24",
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
],
|
|
|
"count": 3
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Note that the response above contains three subnets. One of the subnets is associated with more than one server. The last subnet is associated with all servers, which is also used by the server using the "server1" tag.
|
|
|
|
|
|
#### Variant Listing Unassigned Subnets
|
|
|
|
|
|
In the previous example we have demonstrated how to list the subnets belonging to a particular server and/or all servers. But, some of the subnets may be unassigned, i.e. do not belong to any server (orphaned subnets). One of the cases when the subnet may be become orphaned is when the server to which the subnet is assigned is deleted. All associations of the deleted server are removed from the database automatically, but the subnet (and shared networks) are left in the database because they may be associated with other servers. In order to list all orphaned subnets the client must use `null` server tag to indicate that only unassigned subnets should be returned.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-list"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ null ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
The example response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "IPv4 subnets found.",
|
|
|
"arguments": {
|
|
|
"subnets": [
|
|
|
{
|
|
|
"id": 123,
|
|
|
"shared-network-name": "level1",
|
|
|
"subnet": "192.0.2.0/24",
|
|
|
"metadata": {
|
|
|
"server-tags": [ null ]
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
"count": 1
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Currently, we do not allow for combining explicit server tags with null in the `server-tags` list. For example, it is not allowed to use:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-list"
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"server-tags": [ null, "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-subnet4-set
|
|
|
|
|
|
This command includes mandatory parameter `shared-network-name` which, associates the subnet with a shared network. If this parameter carries an empty string or is null the subnet becomes global.
|
|
|
|
|
|
The `server-tags` parameter is mandatory and it includes one or more server tags. The subnet is associated with all the servers listed in this parameter.
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-subnet4-set",
|
|
|
"service": [ "dhcp4" ],
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"id": 13,
|
|
|
"subnet": "10.20.30.0/24",
|
|
|
"shared-network-name": "level1"
|
|
|
...
|
|
|
} ],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1", "server2" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Successful response:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"result": 0,
|
|
|
"text": "DHCPv4 subnet successfully set.",
|
|
|
"arguments": {
|
|
|
"subnets": [ {
|
|
|
"id": 13,
|
|
|
"subnet": "10.20.30.0/24"
|
|
|
} ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## DHCPv6 Specific Commands
|
|
|
|
|
|
TBD
|
|
|
|
|
|
# Implementation Tasks
|
|
|
|
|
|
## Kea 1.5.0/1.6.0
|
|
|
|
|
|
### Design and Documentation
|
|
|
1. Update Config Backend design: CQL schema, class hierarchies etc.
|
|
|
1. ~~Update User's Guide for Configuration Backend (#71)~~
|
|
|
1. Update Developer's Guide for Configuration Backend (#106)
|
|
|
|
|
|
### Schema
|
|
|
1. ~~Create MySQL schema and upgrade scripts (#89)~~
|
|
|
|
|
|
### Refactoring
|
|
|
1. ~~Move common classes pertaining to databases from libkea-dhcpsrv to their own libraries (#92)~~
|
|
|
|
|
|
### Config Backend Implementation
|
|
|
1. ~~Implement basic class hierarchy for Config Backend (#28)~~
|
|
|
1. ~~Implement MySQLConfigBackendDHCPv4 (#93)~~
|
|
|
1. ~~Implement config backend support for DHCPv6 in the library (#458)~~
|
|
|
1. ~~Update MySQL schema for DHCPv6 config backend (#460)~~
|
|
|
1. ~~Implement MySQLConfigBackendDHCPv6 (#94)~~
|
|
|
1. ~~Create a class representing audit entries (#395)~~
|
|
|
1. ~~Implement audit trail for DHCPv4 MySQL backend (#396)~~
|
|
|
1. ~~Implement audit trail for DHCPv6 MySQL backend (#397)~~
|
|
|
1. ~~Add logging to the MySQL config backend (#398)~~
|
|
|
1. ~~Include global parameter data type in CB MySQL Config Backend (#429)~~
|
|
|
1. ~~Return all subnets belonging to a given shared network (#440)~~
|
|
|
1. ~~MySQL config backend must not set timers to default value of 0 (#451)~~
|
|
|
1. ~~The MySQL Config Backend must store unspecified subnet and network parameters as null (#489)~~
|
|
|
1. ~~MySQL Config Backend must not validate formatted options fetched from the DB (#521)~~
|
|
|
|
|
|
### Server Configuration
|
|
|
1. ~~Add config-database and server-tag parameters into DHCPv4 (#32)~~
|
|
|
1. ~~Add config-database and server-tag parameters into DHCPv6 (#32)~~
|
|
|
1. ~~Add two step configuration to the DHCPv4 server (#101)~~
|
|
|
1. ~~Add two step configuration to the DHCPv6 server (#102)~~
|
|
|
1. ~~Modify subnet and shared network objects to hold information about unspecified values (#487)~~
|
|
|
|
|
|
### DHCPv4 Configuration Merge
|
|
|
1. ~~Add capability to merge DHCPv4 configuration from database and from a file (#99)~~
|
|
|
1. ~~Merge DHCPv4 shared networks fetched from the CB into the configuration (#399)~~
|
|
|
1. ~~Merge DHCPv4 option definitions fetched from the CB into the configuration (#400)~~
|
|
|
1. ~~Merge DHCPv4 options fetched from the CB into the configuration (#401)~~
|
|
|
1. ~~Merge DHCPv4 global parameters fetched from the CB into the configuration (#402)~~
|
|
|
1. ~~Add periodic fetch of the incremental DHCPv4 configuration changes (#103)~~
|
|
|
1. ~~DHCPv4 server must interpret unspecified subnet and shared network parameters fetched from the DB (#490)~~
|
|
|
|
|
|
### DHCPv6 Configuration Merge
|
|
|
1. ~~Add capability to merge DHCPv6 configuration from database and from a file (#100)~~
|
|
|
1. ~~Merge DHCPv6 shared networks fetched from the CB into the configuration (#410)~~ (being done in #413)
|
|
|
1. ~~Merge DHCPv6 option definitions fetched from the CB into the configuration (#411)~~ (being done in #413)
|
|
|
1. ~~Merge DHCPv6 options fetched from the CB into the configuration (#412)~~ (being done in #413)
|
|
|
1. ~~Merge DHCPv6 global parameters fetched from the CB into the configuration (#413)~~
|
|
|
1. ~~Add periodic fetch of the incremental DHCPv6 configuration changes (#104)~~
|
|
|
1. ~~DHCPv6 server to delete elements of the local configuration that were deleted from the CB (#566)~~
|
|
|
|
|
|
### Data Management
|
|
|
1. ~~Create basic cb_cmds hooks library including basic management of subnets in the database (#105)~~
|
|
|
1. ~~Update cb_cmds with commands to delete configuration data for DHCPv4 (#405)~~
|
|
|
1. ~~Update cb_cmds with commands to retrieve configuration data for DHCPv4 (#406)~~
|
|
|
1. ~~Update remote-global-parmeter4-set (cb_cmds) to handle other parameter types than strings (#448)~~
|
|
|
1. ~~Update cb_cmds commands to refuse reservations in remote-subnet4-set (#424)~~
|
|
|
1. ~~Update cb_cmds with commands to add/update configuration data for DHCPv6 (#407)~~
|
|
|
1. ~~Update cb_cmds with commands to delete configuration data for DHCPv6 (#408)~~
|
|
|
1. ~~Update cb_cmds with commands to retrieve configuration data for DHCPv6 (#409)~~
|
|
|
1. ~~Remove setting default values for the subnet and shared network in the cb_cmds (#488)~~
|
|
|
|
|
|
## After 1.6.0 release:
|
|
|
1. Create PgSQL schema and upgrade scripts (#90)
|
|
|
1. Create CQL schema and upgrade scripts (#91)
|
|
|
1. Implement PgSQLConfigBackendDHCPv4 (#95)
|
|
|
1. Implement PgSQLConfigBackendDHCPv6 (#96)
|
|
|
1. Implement CQLConfigBackendDHCPv4 (#97)
|
|
|
1. Implement CQLConfigBackendDHCPv6 (#98)
|
|
|
|
|
|
### Optional Tasks
|
|
|
|
|
|
1. Add dhcp4_srv_bootstrap hook point into DHCPv4 server
|
|
|
1. Add dhcp6_srv_bootstrap hook point into DHCPv6 server
|
|
|
1. Adopt cb_cmds hooks library to be able to load it on Control Agent
|
|
|
1. Adopt host_cmds hooks library to be able to load it on Control Agent
|
|
|
1. Adopt other hooks libraries (options?) to be able to load them on Control Agent
|
|
|
|
|
|
# Notes
|
|
|
|
|
|
Andrei suggested:
|
|
|
|
|
|
* mention explicit indexes in DB schema.
|
|
|
* mention primary keys
|
|
|
|
|
|
# Vicky's comments
|
|
|
|
|
|
## Use cases for the db in the backend include
|
|
|
* I want to deploy an additional Kea server, based on the configuration of one I already have (to add capacity). This db configuration storage should enable me to clone an existing server and easily identify the things that have to be changed. I would think that wouldn't be too difficult just by copying the kea.conf file of an existing Kea server, but it might be a bit harder to determine what things need to be server-specific.
|
|
|
* I want to change something across a whole bunch of Kea servers - maybe I have a subnet that I need to reduce in scope and that subnet is on multiple Kea servers, or maybe I got some more addresses from somewhere and I want to increase the pool for guest wifi access. This db configuration storage should reduce the # of steps required to make the same change on multiple Kea servers.
|
|
|
* I want to deploy a second Kea server in load-sharing or active/standby mode and so I need to coordinate the dial plan between the two. We should aim to eventually make that kind of coordinated change easier with this db configuration design.
|
|
|
|
|
|
## Worries
|
|
|
* I think the reason that people loved putting the host reservations in the db backend was, they wanted to manage them directly in the database with other tools (SQL based tools) that they were already familiar with. As we put more of the configuration into the database, if people do manage it directly via SQL, the likelihood of their creating invalid configurations obviously goes way up.
|
|
|
|
|
|
Answer: people may choose to manipulate the data directly if that requires their deployment. However, we're going to provide REST commands to manipulate the data in the safe manner.
|
|
|
|
|
|
* Large enterprises will want fine grained permissions- who can edit which subnets, for example. I don't see how we could implement such a thing with the database layer between the Management layer and the Kea servers.
|
|
|
* IDs for the Kea servers - I am not sure what the server tags are. Are these basically server names, like BldgAFlr1, BldgAFLr2, BldgAFlr3, or site1, site1B, site2, site2B?
|
|
|
|
|
|
Answer: a tag can be either a server name or a site name or any other thing required by the deployment. If two server instances are using the same tag, they will get the same configuration information from the database.
|
|
|
|
|
|
# Footnotes |