|
|
# Client Classes in Config Backend
|
|
|
|
|
|
## Summary
|
|
|
|
|
|
This document covers extensions to the original [Kea Config Backend Design](designs/configuration in db design) to facilitate storing client class configurations in the databases. These extensions are planned for Kea 2.0 release.
|
|
|
|
|
|
## Challenges
|
|
|
|
|
|
Unlike other Kea configuration parts, client class definitions are ordered. Ordering is required because classes can depend on each other. The dependencies are created using the `member` operator in the class test expression, e.g.:
|
|
|
|
|
|
```json
|
|
|
"client-classes": [
|
|
|
{
|
|
|
"name": "foo"
|
|
|
},
|
|
|
{
|
|
|
"name": "bar",
|
|
|
"test": "member('foo')"
|
|
|
}
|
|
|
]
|
|
|
```
|
|
|
|
|
|
In this example, the client class `bar` depends on `foo`; thus, `foo` must be defined before `bar`. The updated Config Backend schema must comprise the information about classes ordering and the dependencies between them. In addition, the schema must provide ways to change the arrangement easily, insert new class definitions between the existing definitions and reject the class insertion when it breaks the dependency chain.
|
|
|
|
|
|
## MySQL Schema Updates
|
|
|
|
|
|
The following sub-sections describe changes to be applied to the MySQL schema to facilitate storing client classes. For simplicity, only the DHCPv4 specific schema changes are described. The DHCPv6 specific changes would look very similar.
|
|
|
|
|
|
### Table dhcp4_client_class
|
|
|
|
|
|
```sql
|
|
|
CREATE TABLE IF NOT EXISTS dhcp4_client_class (
|
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
|
name VARCHAR(128) NOT NULL,
|
|
|
test TEXT,
|
|
|
next_server INT UNSIGNED DEFAULT NULL,
|
|
|
server_hostname VARCHAR(128) DEFAULT NULL,
|
|
|
boot_file_name VARCHAR(512) DEFAULT NULL,
|
|
|
only_if_required TINYINT NOT NULL DEFAULT '0',
|
|
|
valid_lifetime INT DEFAULT NULL,
|
|
|
min_valid_lifetime INT DEFAULT NULL,
|
|
|
max_valid_lifetime INT DEFAULT NULL,
|
|
|
depend_on_known_directly TINYINT NOT NULL DEFAULT '0',
|
|
|
follow_class_name VARCHAR(128) DEFAULT NULL,
|
|
|
modification_ts TIMESTAMP NOT NULL,
|
|
|
PRIMARY KEY (id),
|
|
|
UNIQUE KEY id_UNIQUE (id),
|
|
|
UNIQUE KEY name_UNIQUE (name),
|
|
|
KEY key_dhcp4_client_class_modification_ts (modification_ts)
|
|
|
) ENGINE=InnoDB;
|
|
|
```
|
|
|
|
|
|
The `dhcp4_client_class` table is a container for all DHCPv4 client classes defined within the Config Backend instance. It includes classes shared by all Kea servers and the classes defined for individual servers. The columns in this table correspond to the parameters known from the client class definitions in the Kea configuration files. Additional columns, e.g. `id` and `modification_ts`, are used to access the database information using SQL queries, like in other CB tables.
|
|
|
|
|
|
The `follow_class_name` does not contain any class-specific information. It provides a caller with a way to insert a new class at a certain position in the class hierarchy. It defaults to NULL, which results in appending the class at the end of the hierarchy.
|
|
|
|
|
|
A caller can set this column's value in the INSERT statement to the name of the existing class. The new class will be inserted after the specified class in the hierarchy. Please continue reading to learn what it means in terms of data organization within the database.
|
|
|
|
|
|
The `depend_on_known_directly` column indicates if the particular client class depends directly on the KNOWN or UNKNOWN built-in class. A caller must evaluate test expression looking for occurrences of `member('KNOWN')` or 'member('UNKNOWN')` expressions to set this value. Recording this value is important to ensure that the client class dependency chain is on these built-in classes is satisfied when any of the client classes are updated.
|
|
|
|
|
|
### Table dhcp4_client_class_order
|
|
|
|
|
|
In the previous section, we said that a class could be inserted at a specific position within the class hierarchy. In other words, it is possible to maintain an order of the classes and insert new classes between existing classes. Though, it is not the same as inserting a class at a specific position within the `dhcp4_client_class` table. Each new record in this table is assigned an auto-incrementing ID. This ID is NOT used for ordering the classes. The ordering is maintained in a new table, `dhcp4_client_class_order`.
|
|
|
|
|
|
```sql
|
|
|
CREATE TABLE IF NOT EXISTS dhcp4_client_class_order (
|
|
|
class_id BIGINT UNSIGNED NOT NULL,
|
|
|
order_index BIGINT UNSIGNED NOT NULL,
|
|
|
depend_on_known_indirectly TINYINT NOT NULL DEFAULT '0',
|
|
|
PRIMARY KEY (class_id),
|
|
|
KEY key_dhcp4_client_class_order_index (order_index),
|
|
|
CONSTRAINT fk_dhcp4_client_class_order_class_id FOREIGN KEY (class_id) REFERENCES dhcp4_client_class (id) ON DELETE CASCADE
|
|
|
) ENGINE=InnoDB;
|
|
|
```
|
|
|
|
|
|
This table has three columns. The `class_id` column has a foreign key referring to the `dhcp4_client_class` table and identifies a selected class. The `order_index` designates a position of that class in the class hierarchy. The higher the index, the further the class in the hierarchy. A class with an `order_index` value of 1 is the highest in the hierarchy and must not depend on other classes. All classes with a higher index may depend on this class.
|
|
|
|
|
|
Suppose the following classes hierarchy ordered by `class_id`:
|
|
|
|
|
|
| class_id | order_index |
|
|
|
| -------- | ----------- |
|
|
|
| 26 | 1 |
|
|
|
| 27 | 3 |
|
|
|
| 28 | 2 |
|
|
|
|
|
|
Class 26 is the topmost class. Class 27 and 28 are lower in the hierarchy and may depend on class 26. Class 28 is next in the hierarchy, and class 27 may depend on it. Class 28 must not depend on class 27 because it is higher in the hierarchy and so on.
|
|
|
|
|
|
To retrieve all classes in order, use a query similar to this:
|
|
|
|
|
|
```sql
|
|
|
SELECT * FROM dhcp4_client_class AS c
|
|
|
INNER JOIN dhcp4_client_class_order AS o
|
|
|
ON c.id = o.class_id
|
|
|
ORDER BY o.order_index;
|
|
|
```
|
|
|
|
|
|
The last column, `depend_on_known_indirectly` indicates if a client class depends on the KNOWN or UNKNOWN built-in class via other classes. Suppose there is a class `foo` that depends on `KNOWN`. If the class `bar` depends on `foo` it also indirectly depends on `KNOWN` built-in class. It should be recorded in this column.
|
|
|
|
|
|
The values of the `depend_on_known_indirectly` must not be set by a caller. They are set by the `setClientClass4Order stored procedure fired from the `dhcp4_client_class_AINS` trigger. Note that this column can't belong to the `dhcp4_client_class` table because a trigger fired for a table (`dhcp4_client_class` in this case) can't modify the contents of this table.
|
|
|
|
|
|
### Classes Arrangement with dhcp4_client_class_AINS Trigger
|
|
|
|
|
|
A Config Backend user will typically append a class at the end of the existing hierarchy. In some cases, the user may also insert a class between existing classes. In this case, the user should know the name of the class, after which the new class should be inserted. It should typically follow the last class on which the new class depends.
|
|
|
|
|
|
Suppose the following class hierarchy returned by a query joining the `dhcp4_client_class` and `dhcp4_client_class_order` tables:
|
|
|
|
|
|
| id | name | order_index |
|
|
|
| --- | ------ | ------------ |
|
|
|
| 26 | foo | 1 |
|
|
|
| 28 | bar | 2 |
|
|
|
| 27 | foobar | 3 |
|
|
|
|
|
|
It should be possible for the caller to make a query that results in the following behavior:
|
|
|
|
|
|
"Insert a class `abc` right after the class `bar` and before the class `foobar`."
|
|
|
|
|
|
It should result in the following new hierarchy:
|
|
|
|
|
|
| id | name | order_index |
|
|
|
| --- | ------ | ------------ |
|
|
|
| 26 | foo | 1 |
|
|
|
| 28 | bar | 2 |
|
|
|
| 29 | abc | 3 |
|
|
|
| 27 | foobar | 4 |
|
|
|
|
|
|
Please note, that the `order_index` value for the class `foobar` has been updated because class `abc` now uses the `order_index` of 3.
|
|
|
|
|
|
This behavior can be implemented using a trigger on the `dhcp4_client_class` table, which identifies appropriate `class_id` by the class name specified in `dhcp4_client_class.follow_class_name` column and inserts new record into the `dhcp4_client_class_order` table, updating the existing `order_index` values as necessary.
|
|
|
|
|
|
```sql
|
|
|
DELIMITER $$
|
|
|
CREATE PROCEDURE setClientClass4Order(IN id BIGINT UNSIGNED,
|
|
|
IN follow_class_name VARCHAR(128))
|
|
|
BEGIN
|
|
|
-- This variable will be optionally set if the follow_class_name
|
|
|
-- column value is specified.
|
|
|
DECLARE follow_class_index BIGINT UNSIGNED;
|
|
|
DECLARE msg TEXT;
|
|
|
IF follow_class_name IS NOT NULL THEN
|
|
|
-- Get the position of the class after which the new class should be added.
|
|
|
SET follow_class_index = (
|
|
|
SELECT o.order_index FROM dhcp4_client_class AS c
|
|
|
INNER JOIN dhcp4_client_class_order AS o
|
|
|
ON c.id = o.class_id
|
|
|
WHERE name = follow_class_name
|
|
|
);
|
|
|
IF follow_class_index IS NULL THEN
|
|
|
-- The class with a name specified with follow_class_name does
|
|
|
-- not exist.
|
|
|
SET msg = CONCAT('Class ', follow_class_name, ' does not exist.');
|
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
|
|
|
END IF;
|
|
|
-- We need to place the new class at the position of follow_class_index + 1.
|
|
|
-- There may be a class at this position already.
|
|
|
IF EXISTS(SELECT * FROM dhcp4_client_class_order WHERE order_index = follow_class_index + 1) THEN
|
|
|
-- There is a class at this position already. Let's move all classes
|
|
|
-- starting from this position by one to create a spot for the new
|
|
|
-- class.
|
|
|
UPDATE dhcp4_client_class_order
|
|
|
SET order_index = order_index + 1
|
|
|
WHERE order_index >= follow_class_index + 1
|
|
|
ORDER BY order_index DESC;
|
|
|
END IF;
|
|
|
ELSE
|
|
|
-- A caller did not specify the follow_class_name value. Let's append the
|
|
|
-- new class at the end of the hierarchy.
|
|
|
SET follow_class_index = (SELECT MAX(order_index) FROM dhcp4_client_class_order);
|
|
|
IF follow_class_index IS NULL THEN
|
|
|
-- Apparently, there are no classes. Let's start from 0.
|
|
|
SET follow_class_index = 0;
|
|
|
END IF;
|
|
|
END IF;
|
|
|
-- The depend_on_known_indirectly is set to 0 because this procedure is invoked
|
|
|
-- whenever the dhcp4_client_class record is updated. Such update may include
|
|
|
-- test expression changes impacting the dependency on KNOWN/UNKNOWN classes.
|
|
|
-- This value will be later adjusted when dependencies are inserted.
|
|
|
SET @depend_on_known_indirectly = (
|
|
|
SELECT depend_on_known_indirectly FROM dhcp4_client_class_order WHERE id = class_id
|
|
|
);
|
|
|
REPLACE INTO dhcp4_client_class_order(class_id, order_index, depend_on_known_indirectly)
|
|
|
VALUES (id, follow_class_index + 1, 0);
|
|
|
END $$
|
|
|
DELIMITER ;
|
|
|
|
|
|
DELIMITER $$
|
|
|
CREATE TRIGGER dhcp4_client_class_AINS AFTER INSERT ON dhcp4_client_class FOR EACH ROW BEGIN
|
|
|
CALL setClientClass4Order(NEW.id, NEW.follow_class_name);
|
|
|
CALL createAuditEntryDHCP4('dhcp4_client_class', NEW.id, "create");
|
|
|
END $$
|
|
|
DELIMITER ;
|
|
|
```
|
|
|
|
|
|
It may look unnecessary to create a separate table to arrange the classes rather than create the `order_index` column in the `dhcp4_client_class` table. There is a good reason for such a split, though. SQL triggers do not allow for modifying the data in the table to which the trigger belongs. It makes it impossible to use the triggers to update the `order_index` values of the existing records.
|
|
|
|
|
|
### Table dhcp4_client_class_dependency
|
|
|
|
|
|
New Kea API commands are required to manage client classes directly in the database. Suppose a user sends a command to add a new class. If this class depends on other classes, and some of them do not exist, the user should receive immediate feedback indicating that the new class can't be added. It implies that the dependency check must be performed at the database level before adding the class to the database. The database must hold information about dependencies between classes.
|
|
|
|
|
|
The following new table holds the information about dependencies between client classes.
|
|
|
|
|
|
```sql
|
|
|
CREATE TABLE IF NOT EXISTS dhcp4_client_class_dependency (
|
|
|
class_id BIGINT UNSIGNED NOT NULL,
|
|
|
dependency_id BIGINT UNSIGNED NOT NULL,
|
|
|
PRIMARY KEY (class_id,dependency_id),
|
|
|
KEY dhcp4_client_class_dependency_id_idx (dependency_id),
|
|
|
CONSTRAINT dhcp4_client_class_class_id FOREIGN KEY (class_id)
|
|
|
REFERENCES dhcp4_client_class (id) ON DELETE CASCADE,
|
|
|
CONSTRAINT dhcp4_client_class_dependency_id FOREIGN KEY (dependency_id)
|
|
|
REFERENCES dhcp4_client_class (id)
|
|
|
) ENGINE=InnoDB;
|
|
|
```
|
|
|
|
|
|
The `class_id` is an identifier of the class having a dependency on another class. The `dependency_id` is an identifier of a class on which the class depends. A class may depend on many classes except self. Many classes may depend on a given class.
|
|
|
|
|
|
We considered using a trigger to populate class dependencies automatically when a class is added to or updated in the `dhcp4_client_class` table. However, inferring the class dependencies from the `test` expression is a quite involved operation and requires regular expressions. MySQL supports regular expression from version 8. Some operating systems still include earlier MySQL versions. Therefore, we decided not to use triggers for inferring dependencies. Parsing dependencies will be performed in the `cb_cmds` hooks library, and the dependencies will be explicitly provided in the same transaction as the class definition. If the dependencies are not met, the whole transaction will be rolled back, and the new class won't be inserted.
|
|
|
|
|
|
A before-insert trigger on the `dhcp4_client_class_dependency` is responsible for checking the correctness of the dependencies.
|
|
|
|
|
|
```sql
|
|
|
DELIMITER $$
|
|
|
CREATE PROCEDURE checkDHCPv4ClientClassDependency(IN class_id BIGINT UNSIGNED,
|
|
|
IN dependency_id BIGINT UNSIGNED)
|
|
|
BEGIN
|
|
|
DECLARE class_index BIGINT UNSIGNED;
|
|
|
DECLARE dependency_index BIGINT UNSIGNED;
|
|
|
DECLARE err_msg TEXT;
|
|
|
|
|
|
-- We could check the same with a constraint but later in this
|
|
|
-- trigger we use this value to verify if the dependencies are
|
|
|
-- met.
|
|
|
IF class_id IS NULL THEN
|
|
|
SIGNAL SQLSTATE '45000'
|
|
|
SET MESSAGE_TEXT = 'Client class id must not be NULL.';
|
|
|
END IF;
|
|
|
IF dependency_id IS NULL THEN
|
|
|
SIGNAL SQLSTATE '45000'
|
|
|
SET MESSAGE_TEXT = 'Class dependency id must not be NULL.';
|
|
|
END IF;
|
|
|
-- Dependencies on self make no sense.
|
|
|
IF class_id = dependency_id THEN
|
|
|
SIGNAL SQLSTATE '45000'
|
|
|
SET MESSAGE_TEXT = 'Client class must not have dependency on self.';
|
|
|
END IF;
|
|
|
-- Check position of our class in the hierarchy.
|
|
|
SET class_index = (
|
|
|
SELECT o.order_index FROM dhcp4_client_class AS c
|
|
|
INNER JOIN dhcp4_client_class_order AS o
|
|
|
ON c.id = o.class_id
|
|
|
WHERE c.id = class_id);
|
|
|
IF class_index IS NULL THEN
|
|
|
SET err_msg = CONCAT('Client class with id ', class_id, ' does not exist.');
|
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
|
|
|
END IF;
|
|
|
-- Check position of the dependency.
|
|
|
SET dependency_index = (
|
|
|
SELECT o.order_index FROM dhcp4_client_class AS c
|
|
|
INNER JOIN dhcp4_client_class_order AS o ON c.id = o.class_id
|
|
|
WHERE c.id = dependency_id
|
|
|
);
|
|
|
IF dependency_index IS NULL THEN
|
|
|
SET err_msg = CONCAT('Client class with id ', dependency_id, ' does not exist.');
|
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
|
|
|
END IF;
|
|
|
-- The dependency must not be later than our class.
|
|
|
IF dependency_index > class_index THEN
|
|
|
SET err_msg = CONCAT('Client class with id ', class_id, ' must not depend on class defined later with id ', dependency_id);
|
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
|
|
|
END IF;
|
|
|
|
|
|
-- Check if all servers associated with the new class have dependent
|
|
|
-- classes configured. This catches the cases that class A belongs to
|
|
|
-- server1 and depends on class B which belongs only to server 2.
|
|
|
-- It is fine if the class B belongs to all servers in this case.
|
|
|
-- Make a SELECT on the dhcp4_client_class_server table to gather
|
|
|
-- all servers to which the class belongs. LEFT JOIN it with the
|
|
|
-- same table, selecting all records matching the dependency class
|
|
|
-- and the servers to which the new class belongs. If there are
|
|
|
-- any NULL records joined it implies that some dependencies are
|
|
|
-- not met (didn't find a dependency for at least one server).
|
|
|
IF EXISTS(
|
|
|
SELECT 1 FROM dhcp4_client_class_server AS t1
|
|
|
LEFT JOIN dhcp4_client_class_server AS t2
|
|
|
ON t2.class_id = dependency_id AND (t2.server_id = 1 OR t2.server_id = t1.server_id)
|
|
|
WHERE t1.class_id = class_id AND t2.server_id IS NULL
|
|
|
LIMIT 1
|
|
|
) THEN
|
|
|
SET err_msg = CONCAT('Unmet dependencies for client class with id ', class_id);
|
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = err_msg;
|
|
|
END IF;
|
|
|
END $$
|
|
|
DELIMITER ;
|
|
|
|
|
|
DELIMITER $$
|
|
|
CREATE TRIGGER dhcp4_client_class_check_dependency_BINS BEFORE INSERT ON dhcp4_client_class_dependency FOR EACH ROW
|
|
|
BEGIN
|
|
|
CALL checkDHCPv4ClientClassDependency(NEW.class_id, NEW.dependency_id);
|
|
|
END $$
|
|
|
DELIMITER ;
|
|
|
```
|
|
|
|
|
|
### Checking Dependency Changes on KNOWN
|
|
|
|
|
|
When client class is updated, e.g., due to the control command, it is essential to verify if the client class's dependency on KNOWN or UNKNOWN classes resulting from direct and indirect dependencies has changed. Such change must not be accepted unless no classes are depending on this class. Otherwise, changing the dependency on KNOWN or UNKNOWN may break the dependency chain for all classes. Note that updates influencing dependency on KNOWN or UNKNOWN classes are also not allowed in `class_cmds` hooks library.
|
|
|
|
|
|
The check should be conducted at the end of a transaction after all client class data were populated. A new stored procedure, `checkDHCPv4ClientClassKnownDependencyChange`, is added to run the checks. It must be invoked explicitly using `CALL` statement.
|
|
|
|
|
|
```sql
|
|
|
DELIMITER $$
|
|
|
CREATE PROCEDURE checkDHCPv4ClientClassKnownDependencyChange()
|
|
|
BEGIN
|
|
|
DECLARE depended TINYINT DEFAULT 0;
|
|
|
DECLARE depends TINYINT DEFAULT 0;
|
|
|
|
|
|
-- Session variables are set upon a client class update.
|
|
|
IF @client_class_id IS NOT NULL THEN
|
|
|
-- Check if any of the classes depend on this class. If not,
|
|
|
-- it is ok to change the dependency on KNOWN/UNKNOWN.
|
|
|
IF EXISTS(
|
|
|
SELECT 1 FROM dhcp4_client_class_dependency
|
|
|
WHERE dependency_id = @client_class_id LIMIT 1
|
|
|
) THEN
|
|
|
-- Using the session variables, determine whether the client class
|
|
|
-- depended on KNOWN/UNKNOWN before the update.
|
|
|
IF @depend_on_known_directly <> 0 OR @depend_on_known_indirectly <> 0 THEN
|
|
|
SET depended = 1;
|
|
|
END IF;
|
|
|
-- Check if the client class depends on KNOWN/UNKNOWN after the update.
|
|
|
SET depends = (
|
|
|
SELECT depend_on_known_directly FROM dhcp4_client_class
|
|
|
WHERE id = @client_class_id
|
|
|
);
|
|
|
-- If it doesn't depend directly, check indirect dependencies.
|
|
|
IF depends = 0 THEN
|
|
|
SET depends = (
|
|
|
SELECT depend_on_known_indirectly FROM dhcp4_client_class_order
|
|
|
WHERE class_id = @client_class_id
|
|
|
);
|
|
|
END IF;
|
|
|
-- The resulting dependency on KNOWN/UNKNOWN must not change.
|
|
|
IF depended <> depends THEN
|
|
|
SIGNAL SQLSTATE '45000'
|
|
|
SET MESSAGE_TEXT = 'Class dependency on KNOWN/UNKNOWN built-in classes must not change.';
|
|
|
END IF;
|
|
|
END IF;
|
|
|
END IF;
|
|
|
END $$
|
|
|
DELIMITER ;
|
|
|
```
|
|
|
|
|
|
### Table dhcp4_client_class_server
|
|
|
|
|
|
The `dhcp4_client_class_server` table associates client classes with the servers. Similar tables already exist for other configuration elements.
|
|
|
|
|
|
```sql
|
|
|
CREATE TABLE IF NOT EXISTS dhcp4_client_class_server (
|
|
|
class_id bigint unsigned NOT NULL,
|
|
|
server_id bigint unsigned NOT NULL,
|
|
|
modification_ts timestamp NULL DEFAULT NULL,
|
|
|
PRIMARY KEY (class_id,server_id),
|
|
|
KEY fk_dhcp4_client_class_server_id (server_id),
|
|
|
CONSTRAINT fk_dhcp4_client_class_class_id FOREIGN KEY (class_id)
|
|
|
REFERENCES dhcp4_client_class (id)
|
|
|
ON DELETE CASCADE,
|
|
|
CONSTRAINT fk_dhcp4_client_class_server_id FOREIGN KEY (server_id)
|
|
|
REFERENCES dhcp4_server (id)
|
|
|
) ENGINE=InnoDB;
|
|
|
```
|
|
|
|
|
|
### Extensions to dhcp4_option_def and dhcp4_options
|
|
|
|
|
|
Client classes may comprise class-specific option definitions and option values. Therefore, the `dhcp4_option_def` and `dhcp4_options` must be extended with a new nullable column `class_id` and appropriate foreign keys referencing client classes. Existing queries fetching global DHCP option definitions must be modified to exclude class-specific options definitions.
|
|
|
|
|
|
```sql
|
|
|
ALTER TABLE `dhcp4_option_def`
|
|
|
ADD COLUMN `class_id` BIGINT UNSIGNED NULL DEFAULT NULL,
|
|
|
ADD INDEX `fk_dhcp4_option_def_client_class_id_idx` (`class_id` ASC) VISIBLE;
|
|
|
;
|
|
|
ALTER TABLE `dhcp4_option_def`
|
|
|
ADD CONSTRAINT `fk_dhcp4_option_def_client_class_id`
|
|
|
FOREIGN KEY (`class_id`)
|
|
|
REFERENCES `kea_classes`.`dhcp4_client_class` (`id`)
|
|
|
ON DELETE CASCADE
|
|
|
ON UPDATE CASCADE;
|
|
|
```
|
|
|
|
|
|
```sql
|
|
|
ALTER TABLE `dhcp4_options`
|
|
|
ADD COLUMN `class_id` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `modification_ts`,
|
|
|
ADD INDEX `fk_dhcp4_options_client_class_idx` (`class_id` ASC) VISIBLE;
|
|
|
;
|
|
|
ALTER TABLE `dhcp4_options`
|
|
|
ADD CONSTRAINT `fk_dhcp4_options_client_class`
|
|
|
FOREIGN KEY (`class_id`)
|
|
|
REFERENCES `dhcp4_client_class` (`id`)
|
|
|
ON DELETE CASCADE
|
|
|
ON UPDATE CASCADE;
|
|
|
```
|
|
|
|
|
|
## PostgreSQL Schema Changes
|
|
|
|
|
|
Schema changes for PostgreSQL are out of scope for this document because, at the time of writing, the Configuration Backend does not support PostgreSQL.
|
|
|
|
|
|
## New API Commands
|
|
|
|
|
|
This section describes the new commands to be implemented in the `cb_cmds` hooks library, facilitating client classes management.
|
|
|
|
|
|
### remote-class4-list and remote-class6-list
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-class4-list"
|
|
|
"arguments": {
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "server1", "server2" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-class4-get and remote-class6-get
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-class4-get",
|
|
|
"arguments": {
|
|
|
"client-classes": [
|
|
|
{
|
|
|
"name": "ipxe_efi_x64"
|
|
|
}
|
|
|
],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-class4-set and remote-class6-set
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-class4-set",
|
|
|
"arguments": {
|
|
|
"client-classes": [
|
|
|
{
|
|
|
"name": "ipxe_efi_x64",
|
|
|
"test": "option[93].hex == 0x0009",
|
|
|
"next-server": "192.0.2.254",
|
|
|
"server-hostname": "hal9000",
|
|
|
"boot-file-name": "/dev/null",
|
|
|
"option-def": [
|
|
|
{
|
|
|
"name": "configfile",
|
|
|
"code": 209,
|
|
|
"type": "string"
|
|
|
}
|
|
|
],
|
|
|
"option-data": [ ],
|
|
|
}
|
|
|
],
|
|
|
"place-after": "foo-class",
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
"server-tags": [ "all", "server1" ]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### remote-class4-del and remote-class6-del
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"command": "remote-class4-del",
|
|
|
"arguments": {
|
|
|
"client-classes": [
|
|
|
{
|
|
|
"name": "ipxe_efi_x64"
|
|
|
}
|
|
|
],
|
|
|
"remote": {
|
|
|
"type": "mysql"
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
``` |
|
|
\ No newline at end of file |