Implemented DHCP6 Config Backend similar to the DHCPv4.
#include <dhcpsrv/pool.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/timer_mgr.h>
+#include <dhcpsrv/parsers/client_class_def_parser.h>
#include <util/buffer.h>
#include <util/boost_time_utils.h>
#include <util/multi_threading_mgr.h>
/// database.
enum StatementIndex {
CREATE_AUDIT_REVISION,
+ CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
GET_GLOBAL_PARAMETER6,
GET_ALL_GLOBAL_PARAMETERS6,
GET_MODIFIED_GLOBAL_PARAMETERS6,
GET_OPTION6_POOL_ID_CODE_SPACE,
GET_OPTION6_PD_POOL_ID_CODE_SPACE,
GET_OPTION6_SHARED_NETWORK_CODE_SPACE,
+ GET_CLIENT_CLASS6_NAME,
+ GET_ALL_CLIENT_CLASSES6,
+ GET_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ GET_MODIFIED_CLIENT_CLASSES6,
+ GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED,
GET_AUDIT_ENTRIES6_TIME,
GET_SERVER6,
GET_ALL_SERVERS6,
INSERT_SHARED_NETWORK6,
INSERT_SHARED_NETWORK6_SERVER,
INSERT_OPTION_DEF6,
+ INSERT_OPTION_DEF6_CLIENT_CLASS,
INSERT_OPTION_DEF6_SERVER,
INSERT_OPTION6,
INSERT_OPTION6_SERVER,
+ INSERT_CLIENT_CLASS6,
+ INSERT_CLIENT_CLASS6_SERVER,
+ INSERT_CLIENT_CLASS6_DEPENDENCY,
INSERT_SERVER6,
UPDATE_GLOBAL_PARAMETER6,
UPDATE_SUBNET6,
UPDATE_SHARED_NETWORK6,
UPDATE_OPTION_DEF6,
+ UPDATE_OPTION_DEF6_CLIENT_CLASS,
UPDATE_OPTION6,
UPDATE_OPTION6_SUBNET_ID,
UPDATE_OPTION6_POOL_ID,
UPDATE_OPTION6_PD_POOL_ID,
UPDATE_OPTION6_SHARED_NETWORK,
+ UPDATE_OPTION6_CLIENT_CLASS,
+ UPDATE_CLIENT_CLASS6,
UPDATE_SERVER6,
DELETE_GLOBAL_PARAMETER6,
DELETE_ALL_GLOBAL_PARAMETERS6,
DELETE_OPTION_DEF6_CODE_NAME,
DELETE_ALL_OPTION_DEFS6,
DELETE_ALL_OPTION_DEFS6_UNASSIGNED,
+ DELETE_OPTION_DEFS6_CLIENT_CLASS,
DELETE_OPTION6,
DELETE_ALL_GLOBAL_OPTIONS6_UNASSIGNED,
DELETE_OPTION6_SUBNET_ID,
DELETE_OPTION6_SHARED_NETWORK,
DELETE_OPTIONS6_SUBNET_ID_PREFIX,
DELETE_OPTIONS6_SHARED_NETWORK,
+ DELETE_OPTIONS6_CLIENT_CLASS,
+ DELETE_CLIENT_CLASS6_DEPENDENCY,
+ DELETE_CLIENT_CLASS6_SERVER,
+ DELETE_ALL_CLIENT_CLASSES6,
+ DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ DELETE_CLIENT_CLASS6,
+ DELETE_CLIENT_CLASS6_ANY,
DELETE_SERVER6,
DELETE_ALL_SERVERS6,
NUM_STATEMENTS
}
}
+ /// @brief Sends query to insert or update DHCP option in a client class.
+ ///
+ /// @param selector Server selector.
+ /// @param client_class Pointer to the client_class the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option..
+ void createUpdateOption6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const OptionDescriptorPtr& option) {
+
+ if (server_selector.amUnassigned()) {
+ isc_throw(NotImplemented, "managing configuration for no particular server"
+ " (unassigned) is unsupported at the moment");
+ }
+
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createInteger<uint16_t>(option->option_->getType()),
+ createOptionValueBinding(option),
+ MySqlBinding::condCreateString(option->formatted_value_),
+ MySqlBinding::condCreateString(option->space_name_),
+ MySqlBinding::createBool(option->persistent_),
+ MySqlBinding::createString(client_class->getName()),
+ MySqlBinding::createNull(),
+ MySqlBinding::createInteger<uint8_t>(2),
+ createInputContextBinding(option),
+ MySqlBinding::createNull(),
+ MySqlBinding::createNull(),
+ MySqlBinding::createTimestamp(option->getModificationTime()),
+ MySqlBinding::createNull(),
+ MySqlBinding::createString(client_class->getName()),
+ MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
+ MySqlBinding::condCreateString(option->space_name_)
+ };
+
+ // Create scoped audit revision. As long as this instance exists
+ // no new audit revisions are created in any subsequent calls.
+ ScopedAuditRevision
+ audit_revision(this,
+ MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "client class specific option set",
+ true);
+
+ if (conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::
+ UPDATE_OPTION6_CLIENT_CLASS,
+ in_bindings) == 0) {
+ // Remove the 3 bindings used only in case of update.
+ in_bindings.resize(in_bindings.size() - 3);
+ insertOption6(server_selector, in_bindings);
+ }
+ }
+
/// @brief Sends query to insert or update option definition.
///
/// @param server_selector Server selector.
MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER);
}
+ /// @brief Sends query to insert or update option definition
+ /// for a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param option_def Pointer to the option definition to be inserted or updated.
+ /// @param client_class Client class name.
+ void createUpdateOptionDef6(const ServerSelector& server_selector,
+ const OptionDefinitionPtr& option_def,
+ const std::string& client_class_name) {
+ createUpdateOptionDef(server_selector, option_def, DHCP6_OPTION_SPACE,
+ MySqlConfigBackendDHCPv6Impl::GET_OPTION_DEF6_CODE_SPACE,
+ MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS,
+ MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS,
+ MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER,
+ client_class_name);
+ }
+
/// @brief Sends query to delete option definition by code and
/// option space name.
///
in_bindings));
}
+ /// @brief Sends query to delete option definitions for a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the client class for which option
+ /// definitions should be deleted.
+ /// @return Number of deleted option definitions.
+ uint64_t deleteOptionDefs6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class) {
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createString(client_class->getName())
+ };
+
+ // Run DELETE.
+ return (deleteTransactional(DELETE_OPTION_DEFS6_CLIENT_CLASS, server_selector,
+ "deleting option definition for a client class",
+ "option definition deleted",
+ true,
+ in_bindings));
+ }
+
/// @brief Deletes global option.
///
/// @param server_selector Server selector.
in_bindings));
}
+ /// @brief Deletes options belonging to a client class from the database.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the client class for which options
+ /// should be deleted.
+ /// @return Number of deleted options.
+ uint64_t deleteOptions6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class) {
+
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createString(client_class->getName())
+ };
+
+ // Run DELETE.
+ return (deleteTransactional(DELETE_OPTIONS6_CLIENT_CLASS, server_selector,
+ "deleting options for a client class",
+ "client class specific options deleted",
+ true,
+ in_bindings));
+ }
+
+ /// @brief Common function to retrieve client classes.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param server_selector Server selector.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param [out] client_classes Reference to a container where fetched client
+ /// classes will be inserted.
+ void getClientClasses6(const StatementIndex& index,
+ const ServerSelector& server_selector,
+ const MySqlBindingCollection& in_bindings,
+ ClientClassDictionary& client_classes) {
+ MySqlBindingCollection out_bindings = {
+ MySqlBinding::createInteger<uint64_t>(), // id
+ MySqlBinding::createString(CLIENT_CLASS_NAME_BUF_LENGTH), // name
+ MySqlBinding::createString(CLIENT_CLASS_TEST_BUF_LENGTH), // test
+ MySqlBinding::createInteger<uint8_t>(), // required
+ MySqlBinding::createInteger<uint32_t>(), // valid lifetime
+ MySqlBinding::createInteger<uint32_t>(), // min valid lifetime
+ MySqlBinding::createInteger<uint32_t>(), // max valid lifetime
+ MySqlBinding::createInteger<uint8_t>(), // depend on known directly
+ MySqlBinding::createInteger<uint8_t>(), // depend on known indirectly
+ MySqlBinding::createTimestamp(), // modification_ts
+ MySqlBinding::createInteger<uint64_t>(), // option def: id
+ MySqlBinding::createInteger<uint16_t>(), // option def: code
+ MySqlBinding::createString(OPTION_NAME_BUF_LENGTH), // option def: name
+ MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option def: space
+ MySqlBinding::createInteger<uint8_t>(), // option def: type
+ MySqlBinding::createTimestamp(), // option def: modification_ts
+ MySqlBinding::createInteger<uint8_t>(), // option def: array
+ MySqlBinding::createString(OPTION_ENCAPSULATE_BUF_LENGTH), // option def: encapsulate
+ MySqlBinding::createString(OPTION_RECORD_TYPES_BUF_LENGTH), // option def: record_types
+ MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option def: user_context
+ MySqlBinding::createInteger<uint64_t>(), // option: option_id
+ MySqlBinding::createInteger<uint16_t>(), // option: code
+ MySqlBinding::createBlob(OPTION_VALUE_BUF_LENGTH), // option: value
+ MySqlBinding::createString(FORMATTED_OPTION_VALUE_BUF_LENGTH), // option: formatted_value
+ MySqlBinding::createString(OPTION_SPACE_BUF_LENGTH), // option: space
+ MySqlBinding::createInteger<uint8_t>(), // option: persistent
+ MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id
+ MySqlBinding::createInteger<uint8_t>(), // option: scope_id
+ MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
+ MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name
+ MySqlBinding::createInteger<uint64_t>(), // option: pool_id
+ MySqlBinding::createTimestamp(), // option: modification_ts
+ MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server tag
+ };
+
+ std::list<ClientClassDefPtr> class_list;
+ uint64_t last_option_id = 0;
+ uint64_t last_option_def_id = 0;
+ std::string last_tag;
+
+ conn_.selectQuery(index,
+ in_bindings, out_bindings,
+ [this, &class_list, &last_option_id, &last_option_def_id, &last_tag]
+ (MySqlBindingCollection& out_bindings) {
+ ClientClassDefPtr last_client_class;
+ if (!class_list.empty()) {
+ last_client_class = *class_list.rbegin();
+ }
+
+ if (!last_client_class || (last_client_class->getId() != out_bindings[0]->getInteger<uint64_t>())) {
+
+ last_option_id = 0;
+ last_option_def_id = 0;
+ last_tag.clear();
+
+ auto options = boost::make_shared<CfgOption>();
+ auto option_defs = boost::make_shared<CfgOptionDef>();
+ auto expression = boost::make_shared<Expression>();
+
+ last_client_class = boost::make_shared<ClientClassDef>(out_bindings[1]->getString(), expression, options);
+ last_client_class->setCfgOptionDef(option_defs);
+
+ // id
+ last_client_class->setId(out_bindings[0]->getInteger<uint64_t>());
+
+ // name
+ last_client_class->setName(out_bindings[1]->getString());
+
+ // test
+ if (!out_bindings[2]->amNull()) {
+ last_client_class->setTest(out_bindings[2]->getString());
+ }
+
+ // required
+ if (!out_bindings[3]->amNull()) {
+ last_client_class->setRequired(out_bindings[3]->getBool());
+ }
+
+ // valid lifetime: default, min, max
+ last_client_class->setValid(createTriplet(out_bindings[4], out_bindings[5], out_bindings[6]));
+
+ // depend on known directly or indirectly
+ last_client_class->setDependOnKnown(out_bindings[7]->getBool() || out_bindings[8]->getBool());
+
+ // modification_ts
+ last_client_class->setModificationTime(out_bindings[9]->getTimestamp());
+
+ class_list.push_back(last_client_class);
+ }
+
+ // server tag
+ if (!out_bindings[32]->amNull() &&
+ (last_tag != out_bindings[32]->getString())) {
+ last_tag = out_bindings[32]->getString();
+ if (!last_tag.empty() && !last_client_class->hasServerTag(ServerTag(last_tag))) {
+ last_client_class->setServerTag(last_tag);
+ }
+ }
+
+ // Parse client class specific option definition from 10 to 19.
+ if (!out_bindings[10]->amNull() &&
+ (last_option_def_id < out_bindings[10]->getInteger<uint64_t>())) {
+ last_option_def_id = out_bindings[10]->getInteger<uint64_t>();
+
+ auto def = processOptionDefRow(out_bindings.begin() + 10);
+ if (def) {
+ last_client_class->getCfgOptionDef()->add(def);
+ }
+ }
+
+ // Parse client class specific option from 20 to 31.
+ if (!out_bindings[20]->amNull() &&
+ (last_option_id < out_bindings[20]->getInteger<uint64_t>())) {
+ last_option_id = out_bindings[20]->getInteger<uint64_t>();
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 20);
+ if (desc) {
+ last_client_class->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+ });
+
+ tossNonMatchingElements(server_selector, class_list);
+
+ for (auto c : class_list) {
+ client_classes.addClass(c);
+ }
+ }
+
+ /// @brief Sends query to retrieve a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be retrieved.
+ /// @return Pointer to the client class or null if the class is not found.
+ ClientClassDefPtr getClientClass6(const ServerSelector& server_selector,
+ const std::string& name) {
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createString(name)
+ };
+ ClientClassDictionary client_classes;
+ getClientClasses6(MySqlConfigBackendDHCPv6Impl::GET_CLIENT_CLASS6_NAME,
+ server_selector, in_bindings, client_classes);
+ return (client_classes.getClasses()->empty() ? ClientClassDefPtr() :
+ (*client_classes.getClasses()->begin()));
+ }
+
+ /// @brief Sends query to retrieve all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @param [out] client_classes Reference to the client classes collection
+ /// where retrieved classes will be stored.
+ void getAllClientClasses6(const ServerSelector& server_selector,
+ ClientClassDictionary& client_classes) {
+ MySqlBindingCollection in_bindings;
+ getClientClasses6(server_selector.amUnassigned() ?
+ MySqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED :
+ MySqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6,
+ server_selector, in_bindings, client_classes);
+ }
+
+ /// @brief Sends query to retrieve modified client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @param modification_ts Lower bound modification timestamp.
+ /// @param [out] client_classes Reference to the client classes collection
+ /// where retrieved classes will be stored.
+ void getModifiedClientClasses6(const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_ts,
+ ClientClassDictionary& client_classes) {
+ if (server_selector.amAny()) {
+ isc_throw(InvalidOperation, "fetching modified client classes for ANY "
+ "server is not supported");
+ }
+
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createTimestamp(modification_ts)
+ };
+ getClientClasses6(server_selector.amUnassigned() ?
+ GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED :
+ GET_MODIFIED_CLIENT_CLASSES6,
+ server_selector,
+ in_bindings,
+ client_classes);
+ }
+
+ /// @brief Upserts client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Pointer to the upserted client class.
+ /// @param follow_client_class name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ void createUpdateClientClass6(const ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_client_class) {
+ // We need to evaluate class expression to see if it references any
+ // other classes (dependencies). As part of this evaluation we will
+ // also check if the client class depends on KNOWN/UNKNOWN built-in
+ // classes.
+ std::list<std::string> dependencies;
+ auto depend_on_known = false;
+ if (!client_class->getTest().empty()) {
+ ExpressionPtr expression;
+ ExpressionParser parser;
+ // Parse the test expression. The callback function is normally used to
+ // interrupt config file parsing when one of the classes refers to a
+ // non-existing client class. It returns false in this case. Here,
+ // we use the callback to capture client classes referenced by the
+ // upserted client class and record whether this class depends on
+ // KNOWN/UNKNOWN built-ins. The callback always returns true to avoid
+ // reporting the parsing error. The dependency check is performed later
+ // at the database level.
+ parser.parse(expression, Element::create(client_class->getTest()), AF_INET,
+ [&dependencies, &depend_on_known](const ClientClass& client_class) -> bool {
+ if (isClientClassBuiltIn(client_class)) {
+ if ((client_class == "KNOWN") || (client_class == "UNKNOWN")) {
+ depend_on_known = true;
+ }
+ } else {
+ dependencies.push_back(client_class);
+ }
+ return (true);
+ });
+ }
+
+
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createString(client_class->getName()),
+ MySqlBinding::createString(client_class->getTest()),
+ MySqlBinding::createBool(client_class->getRequired()),
+ MySqlBinding::createInteger<uint32_t>(client_class->getValid()),
+ MySqlBinding::createInteger<uint32_t>(client_class->getValid().getMin()),
+ MySqlBinding::createInteger<uint32_t>(client_class->getValid().getMax()),
+ MySqlBinding::createBool(depend_on_known),
+ (follow_client_class.empty() ? MySqlBinding::createNull() :
+ MySqlBinding::createString(follow_client_class)),
+ MySqlBinding::createTimestamp(client_class->getModificationTime()),
+ };
+
+ MySqlTransaction transaction(conn_);
+
+ ScopedAuditRevision audit_revision(this, MySqlConfigBackendDHCPv6Impl::CREATE_AUDIT_REVISION,
+ server_selector, "client class set", true);
+ // Keeps track of whether the client class is inserted or updated.
+ auto update = false;
+ try {
+ conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6, in_bindings);
+
+ } catch (const DuplicateEntry&) {
+ // Such class already exists.
+
+ // Delete options and option definitions. They will be re-created from the new class
+ // instance.
+ deleteOptions6(ServerSelector::ANY(), client_class);
+ deleteOptionDefs6(ServerSelector::ANY(), client_class);
+
+ // Try to update the class.
+ in_bindings.push_back(MySqlBinding::createString(client_class->getName()));
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6, in_bindings);
+
+ // Delete class associations with the servers and dependencies. We will re-create
+ // them according to the new class specification.
+ MySqlBindingCollection in_assoc_bindings = {
+ MySqlBinding::createString(client_class->getName())
+ };
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY,
+ in_assoc_bindings);
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER,
+ in_assoc_bindings);
+ update = true;
+ }
+
+ // Associate client class with the servers.
+ attachElementToServers(MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER,
+ server_selector,
+ MySqlBinding::createString(client_class->getName()),
+ MySqlBinding::createTimestamp(client_class->getModificationTime()));
+
+ // Iterate over the captured dependencies and try to insert them into the database.
+ for (auto dependency : dependencies) {
+ try {
+ MySqlBindingCollection in_dependency_bindings = {
+ MySqlBinding::createString(client_class->getName()),
+ MySqlBinding::createString(dependency)
+ };
+ // We deleted earlier dependencies, so we can simply insert new ones.
+ conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_DEPENDENCY,
+ in_dependency_bindings);
+ } catch (const std::exception& ex) {
+ isc_throw(InvalidOperation, "unmet dependency on client class: " << dependency);
+ }
+ }
+
+ // If we performed client class update we also have to verify that its dependency
+ // on KNOWN/UNKNOWN client classes hasn't changed.
+ if (update) {
+ MySqlBindingCollection in_check_bindings;
+ conn_.insertQuery(MySqlConfigBackendDHCPv6Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ in_check_bindings);
+ }
+
+ // (Re)create option definitions.
+ if (client_class->getCfgOptionDef()) {
+ auto option_defs = client_class->getCfgOptionDef()->getContainer();
+ auto option_spaces = option_defs.getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionDefContainerPtr defs = option_defs.getItems(option_space);
+ for (auto def = defs->begin(); def != defs->end(); ++def) {
+ createUpdateOptionDef6(server_selector, *def, client_class->getName());
+ }
+ }
+ }
+
+ // (Re)create options.
+ auto option_spaces = client_class->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = client_class->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy = OptionDescriptor::create(*desc);
+ desc_copy->space_name_ = option_space;
+ createUpdateOption6(server_selector, client_class, desc_copy);
+ }
+ }
+
+ // All ok. Commit the transaction.
+ transaction.commit();
+ }
+
+ /// @brief Removes client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Removed client class name.
+ /// @return Number of deleted client classes.
+ uint64_t deleteClientClass6(const ServerSelector& server_selector,
+ const std::string& name) {
+ int index = server_selector.amAny() ?
+ MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY :
+ MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6;
+
+ uint64_t result = deleteTransactional(index, server_selector,
+ "deleting client class",
+ "client class deleted",
+ true,
+ name);
+ return (result);
+ }
+
/// @brief Removes unassigned global parameters, global options and
/// option definitions.
///
"CALL createAuditRevisionDHCP6(?, ?, ?, ?)"
},
+ // Verify that dependency on KNOWN/UNKNOWN class has not changed.
+ { MySqlConfigBackendDHCPv6Impl::CHECK_CLIENT_CLASS_KNOWN_DEPENDENCY_CHANGE,
+ "CALL checkDHCPv6ClientClassKnownDependencyChange()"
+ },
+
// Select global parameter by name.
{ MySqlConfigBackendDHCPv6Impl::GET_GLOBAL_PARAMETER6,
MYSQL_GET_GLOBAL_PARAMETER(dhcp6, AND g.name = ?)
MYSQL_GET_OPTION6(AND o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?)
},
+ // Select a client class by name.
+ { MySqlConfigBackendDHCPv6Impl::GET_CLIENT_CLASS6_NAME,
+ MYSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.name = ?)
+ },
+
+ // Select all client classes.
+ { MySqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6,
+ MYSQL_GET_CLIENT_CLASS6_WITH_TAG()
+ },
+
+ // Select all unassigned client classes.
+ { MySqlConfigBackendDHCPv6Impl::GET_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ MYSQL_GET_CLIENT_CLASS6_UNASSIGNED()
+ },
+
+ // Select modified client classes.
+ { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6,
+ MYSQL_GET_CLIENT_CLASS6_WITH_TAG(WHERE c.modification_ts >= ?)
+ },
+
+ // Select modified client classes.
+ { MySqlConfigBackendDHCPv6Impl::GET_MODIFIED_CLIENT_CLASSES6_UNASSIGNED,
+ MYSQL_GET_CLIENT_CLASS6_UNASSIGNED(AND c.modification_ts >= ?)
+ },
+
// Retrieves the most recent audit entries.
{ MySqlConfigBackendDHCPv6Impl::GET_AUDIT_ENTRIES6_TIME,
MYSQL_GET_AUDIT_ENTRIES_TIME(dhcp6)
MYSQL_INSERT_OPTION_DEF(dhcp6)
},
+ // Insert option definition for client class.
+ { MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_CLIENT_CLASS,
+ MYSQL_INSERT_OPTION_DEF_CLIENT_CLASS(dhcp6)
+ },
+
// Insert association of the option definition with a server.
{ MySqlConfigBackendDHCPv6Impl::INSERT_OPTION_DEF6_SERVER,
MYSQL_INSERT_OPTION_DEF_SERVER(dhcp6)
MYSQL_INSERT_OPTION_SERVER(dhcp6)
},
+ // Insert client class.
+ { MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6,
+ "INSERT INTO dhcp6_client_class("
+ " name,"
+ " test,"
+ " only_if_required,"
+ " valid_lifetime,"
+ " min_valid_lifetime,"
+ " max_valid_lifetime,"
+ " depend_on_known_directly,"
+ " follow_class_name,"
+ " modification_ts"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
+ },
+ // Insert association of a client class with a server.
+ { MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_SERVER,
+ MYSQL_INSERT_CLIENT_CLASS_SERVER(dhcp6)
+ },
+ // Insert client class dependency.
+ { MySqlConfigBackendDHCPv6Impl::INSERT_CLIENT_CLASS6_DEPENDENCY,
+ MYSQL_INSERT_CLIENT_CLASS_DEPENDENCY(dhcp6)
+ },
+
// Insert server with server tag and description.
{ MySqlConfigBackendDHCPv6Impl::INSERT_SERVER6,
MYSQL_INSERT_SERVER(dhcp6)
MYSQL_UPDATE_OPTION_DEF(dhcp6)
},
+ // Update existing option definition.
+ { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION_DEF6_CLIENT_CLASS,
+ MYSQL_UPDATE_OPTION_DEF_CLIENT_CLASS(dhcp6)
+ },
+
// Update existing global option.
{ MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6,
MYSQL_UPDATE_OPTION6_WITH_TAG(AND o.scope_id = 0 AND o.code = ? AND o.space = ?)
MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 4 AND o.shared_network_name = ? AND o.code = ? AND o.space = ?)
},
+ // Update existing client class level option.
+ { MySqlConfigBackendDHCPv6Impl::UPDATE_OPTION6_CLIENT_CLASS,
+ MYSQL_UPDATE_OPTION6_NO_TAG(o.scope_id = 2 AND o.dhcp_client_class = ? AND o.code = ? AND o.space = ?)
+ },
+
+ { MySqlConfigBackendDHCPv6Impl::UPDATE_CLIENT_CLASS6,
+ "UPDATE dhcp6_client_class SET"
+ " name = ?,"
+ " test = ?,"
+ " only_if_required = ?,"
+ " valid_lifetime = ?,"
+ " min_valid_lifetime = ?,"
+ " max_valid_lifetime = ?,"
+ " depend_on_known_directly = ?,"
+ " follow_class_name = ?,"
+ " modification_ts = ? "
+ "WHERE name = ?"
+ },
+
// Update existing server, e.g. server description.
{ MySqlConfigBackendDHCPv6Impl::UPDATE_SERVER6,
MYSQL_UPDATE_SERVER(dhcp6)
MYSQL_DELETE_OPTION_DEF_UNASSIGNED(dhcp6)
},
+ // Delete client class specific option definitions.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_OPTION_DEFS6_CLIENT_CLASS,
+ MYSQL_DELETE_OPTION_DEFS_CLIENT_CLASS(dhcp6)
+ },
+
// Delete single global option.
{ MySqlConfigBackendDHCPv6Impl::DELETE_OPTION6,
MYSQL_DELETE_OPTION_WITH_TAG(dhcp6, AND o.scope_id = 0 AND o.code = ? AND o.space = ?)
MYSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 4 AND o.shared_network_name = ?)
},
+ // Delete options belonging to a client class.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_OPTIONS6_CLIENT_CLASS,
+ MYSQL_DELETE_OPTION_NO_TAG(dhcp6, WHERE o.scope_id = 2 AND o.dhcp_client_class = ?)
+ },
+
+ // Delete all dependencies of a client class.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_DEPENDENCY,
+ MYSQL_DELETE_CLIENT_CLASS_DEPENDENCY(dhcp6)
+ },
+
+ // Delete associations of a client class with server.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_SERVER,
+ MYSQL_DELETE_CLIENT_CLASS_SERVER(dhcp6),
+ },
+
+ // Delete all client classes.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6,
+ MYSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6)
+ },
+
+ // Delete all unassigned client classes.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED,
+ MYSQL_DELETE_CLIENT_CLASS_UNASSIGNED(dhcp6)
+ },
+
+ // Delete specified client class.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6,
+ MYSQL_DELETE_CLIENT_CLASS_WITH_TAG(dhcp6, AND name = ?)
+ },
+
+ // Delete any client class with a given name.
+ { MySqlConfigBackendDHCPv6Impl::DELETE_CLIENT_CLASS6_ANY,
+ MYSQL_DELETE_CLIENT_CLASS_ANY(dhcp6, AND name = ?)
+ },
+
// Delete a server by tag.
{ MySqlConfigBackendDHCPv6Impl::DELETE_SERVER6,
MYSQL_DELETE_SERVER(dhcp6)
return (parameters);
}
+ClientClassDefPtr
+MySqlConfigBackendDHCPv6::getClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name) const {
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_CLIENT_CLASS6)
+ .arg(name);
+ return (impl_->getClientClass6(server_selector, name));
+}
+
+ClientClassDictionary
+MySqlConfigBackendDHCPv6::getAllClientClasses6(const db::ServerSelector& server_selector) const {
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_CLIENT_CLASSES6);
+ ClientClassDictionary client_classes;
+ impl_->getAllClientClasses6(server_selector, client_classes);
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT)
+ .arg(client_classes.getClasses()->size());
+ return (client_classes);
+}
+
+ClientClassDictionary
+MySqlConfigBackendDHCPv6::getModifiedClientClasses6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6)
+ .arg(util::ptimeToText(modification_time));
+ ClientClassDictionary client_classes;
+ impl_->getModifiedClientClasses6(server_selector, modification_time, client_classes);
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT)
+ .arg(client_classes.getClasses()->size());
+ return (client_classes);
+}
+
AuditEntryCollection
MySqlConfigBackendDHCPv6::getRecentAuditEntries(const db::ServerSelector& server_selector,
const boost::posix_time::ptime& modification_time,
impl_->createUpdateGlobalParameter6(server_selector, value);
}
+void
+MySqlConfigBackendDHCPv6::createUpdateClientClass6(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_client_class) {
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6)
+ .arg(client_class->getName());
+ impl_->createUpdateClientClass6(server_selector, client_class, follow_client_class);
+}
+
void
MySqlConfigBackendDHCPv6::createUpdateServer6(const ServerPtr& server) {
LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_CREATE_UPDATE_SERVER6)
return (result);
}
+uint64_t
+MySqlConfigBackendDHCPv6::deleteClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name) {
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_CLIENT_CLASS6)
+ .arg(name);
+ auto result = impl_->deleteClientClass6(server_selector, name);
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT)
+ .arg(result);
+ return (result);
+}
+
+uint64_t
+MySqlConfigBackendDHCPv6::deleteAllClientClasses6(const db::ServerSelector& server_selector) {
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6);
+
+ int index = (server_selector.amUnassigned() ?
+ MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6_UNASSIGNED :
+ MySqlConfigBackendDHCPv6Impl::DELETE_ALL_CLIENT_CLASSES6);
+ uint64_t result = impl_->deleteTransactional(index, server_selector, "deleting all client classes",
+ "deleted all client classes", true);
+ LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT)
+ .arg(result);
+ return (result);
+}
+
uint64_t
MySqlConfigBackendDHCPv6::deleteServer6(const ServerTag& server_tag) {
LOG_DEBUG(mysql_cb_logger, DBGLVL_TRACE_BASIC, MYSQL_CB_DELETE_SERVER6)
-// Copyright (C) 2019-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2019-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
getModifiedGlobalParameters6(const db::ServerSelector& server_selector,
const boost::posix_time::ptime& modification_time) const;
+ /// @brief Retrieves a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Client class name.
+ /// @return Pointer to the retrieved client class.
+ virtual ClientClassDefPtr
+ getClientClass6(const db::ServerSelector& selector, const std::string& name) const;
+
+ /// @brief Retrieves all client classes.
+ ///
+ /// @param selector Server selector.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getAllClientClasses6(const db::ServerSelector& selector) const;
+
+ /// @brief Retrieves client classes modified after specified time.
+ ///
+ /// @param selector Server selector.
+ /// @param modification_time Modification time.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getModifiedClientClasses6(const db::ServerSelector& selector,
+ const boost::posix_time::ptime& modification_time) const;
+
/// @brief Retrieves the most recent audit entries.
///
/// @param selector Server selector.
createUpdateGlobalParameter6(const db::ServerSelector& server_selector,
const data::StampedValuePtr& value);
+ /// @brief Creates or updates DHCPv6 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Client class to be added or updated.
+ /// @param follow_client_class name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ virtual void
+ createUpdateClientClass6(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_client_class);
+
/// @brief Creates or updates a server.
///
/// @param server Instance of the server to be stored.
virtual uint64_t
deleteAllGlobalParameters6(const db::ServerSelector& server_selector);
+ /// @brief Deletes DHCPv6 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be deleted.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteAllClientClasses6(const db::ServerSelector& server_selector);
+
/// @brief Deletes a server from the backend.
///
/// @param server_tag Tag of the server to be deleted.
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4 = "MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4";
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6 = "MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6";
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 = "MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4";
+extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 = "MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6";
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 = "MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4";
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6 = "MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6";
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION4 = "MYSQL_CB_CREATE_UPDATE_OPTION4";
extern const isc::log::MessageID MYSQL_CB_DEINIT_OK = "MYSQL_CB_DEINIT_OK";
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4 = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4";
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT";
+extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6 = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6";
+extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT = "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT";
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 = "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4";
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT = "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT";
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6 = "MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6";
extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT = "MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT";
extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4 = "MYSQL_CB_DELETE_CLIENT_CLASS4";
extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT = "MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT";
+extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6 = "MYSQL_CB_DELETE_CLIENT_CLASS6";
+extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT = "MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT";
extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4 = "MYSQL_CB_DELETE_GLOBAL_PARAMETER4";
extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT = "MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT";
extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER6 = "MYSQL_CB_DELETE_GLOBAL_PARAMETER6";
extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT = "MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT";
extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4 = "MYSQL_CB_GET_ALL_CLIENT_CLASSES4";
extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT = "MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT";
+extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6 = "MYSQL_CB_GET_ALL_CLIENT_CLASSES6";
+extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT = "MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT";
extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 = "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4";
extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT = "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT";
extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6 = "MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6";
extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6 = "MYSQL_CB_GET_ALL_SUBNETS6";
extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6_RESULT = "MYSQL_CB_GET_ALL_SUBNETS6_RESULT";
extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS4 = "MYSQL_CB_GET_CLIENT_CLASS4";
+extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS6 = "MYSQL_CB_GET_CLIENT_CLASS6";
extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER4 = "MYSQL_CB_GET_GLOBAL_PARAMETER4";
extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER6 = "MYSQL_CB_GET_GLOBAL_PARAMETER6";
extern const isc::log::MessageID MYSQL_CB_GET_HOST4 = "MYSQL_CB_GET_HOST4";
extern const isc::log::MessageID MYSQL_CB_GET_HOST6 = "MYSQL_CB_GET_HOST6";
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4 = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4";
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT";
+extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6 = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6";
+extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT = "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT";
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4 = "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4";
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT = "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT";
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6 = "MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6";
"MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4", "create or update option by subnet id: %1",
"MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6", "create or update option by subnet id: %1",
"MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4", "create or update client class: %1",
+ "MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6", "create or update client class: %1",
"MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4", "create or update global parameter: %1",
"MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6", "create or update global parameter: %1",
"MYSQL_CB_CREATE_UPDATE_OPTION4", "create or update option",
"MYSQL_CB_DEINIT_OK", "unloading MYSQL CB hooks library successful",
"MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4", "delete all client classes",
"MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT", "deleted: %1 entries",
+ "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6", "delete all client classes",
+ "MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT", "deleted: %1 entries",
"MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4", "delete all global parameters",
"MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT", "deleted: %1 entries",
"MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6", "delete all global parameters",
"MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT", "deleted: %1 entries",
"MYSQL_CB_DELETE_CLIENT_CLASS4", "delete client class: %1",
"MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT", "deleted: %1 entries",
+ "MYSQL_CB_DELETE_CLIENT_CLASS6", "delete client class: %1",
+ "MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT", "deleted: %1 entries",
"MYSQL_CB_DELETE_GLOBAL_PARAMETER4", "delete global parameter: %1",
"MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT", "deleted: %1 entries",
"MYSQL_CB_DELETE_GLOBAL_PARAMETER6", "delete global parameter: %1",
"MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT", "deleted: %1 entries",
"MYSQL_CB_GET_ALL_CLIENT_CLASSES4", "retrieving all client classes",
"MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements",
+ "MYSQL_CB_GET_ALL_CLIENT_CLASSES6", "retrieving all client classes",
+ "MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements",
"MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4", "retrieving all global parameters",
"MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements",
"MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6", "retrieving all global parameters",
"MYSQL_CB_GET_ALL_SUBNETS6", "retrieving all subnets",
"MYSQL_CB_GET_ALL_SUBNETS6_RESULT", "retrieving: %1 elements",
"MYSQL_CB_GET_CLIENT_CLASS4", "retrieving client class: %1",
+ "MYSQL_CB_GET_CLIENT_CLASS6", "retrieving client class: %1",
"MYSQL_CB_GET_GLOBAL_PARAMETER4", "retrieving global parameter: %1",
"MYSQL_CB_GET_GLOBAL_PARAMETER6", "retrieving global parameter: %1",
"MYSQL_CB_GET_HOST4", "get host",
"MYSQL_CB_GET_HOST6", "get host",
"MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4", "retrieving modified client classes from: %1",
"MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT", "retrieving: %1 elements",
+ "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6", "retrieving modified client classes from: %1",
+ "MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT", "retrieving: %1 elements",
"MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4", "retrieving modified global parameters from: %1",
"MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT", "retrieving: %1 elements",
"MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6", "retrieving modified global parameters from: %1",
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION4;
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_BY_SUBNET_ID_OPTION6;
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4;
+extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6;
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4;
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER6;
extern const isc::log::MessageID MYSQL_CB_CREATE_UPDATE_OPTION4;
extern const isc::log::MessageID MYSQL_CB_DEINIT_OK;
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4;
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT;
+extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6;
+extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT;
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4;
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4_RESULT;
extern const isc::log::MessageID MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS6;
extern const isc::log::MessageID MYSQL_CB_DELETE_BY_SUBNET_ID_SUBNET6_RESULT;
extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4;
extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT;
+extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6;
+extern const isc::log::MessageID MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT;
extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4;
extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER4_RESULT;
extern const isc::log::MessageID MYSQL_CB_DELETE_GLOBAL_PARAMETER6;
extern const isc::log::MessageID MYSQL_CB_DELETE_SHARED_NETWORK_SUBNETS6_RESULT;
extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4;
extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT;
+extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6;
+extern const isc::log::MessageID MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT;
extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4;
extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4_RESULT;
extern const isc::log::MessageID MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS6;
extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6;
extern const isc::log::MessageID MYSQL_CB_GET_ALL_SUBNETS6_RESULT;
extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS4;
+extern const isc::log::MessageID MYSQL_CB_GET_CLIENT_CLASS6;
extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER4;
extern const isc::log::MessageID MYSQL_CB_GET_GLOBAL_PARAMETER6;
extern const isc::log::MessageID MYSQL_CB_GET_HOST4;
extern const isc::log::MessageID MYSQL_CB_GET_HOST6;
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4;
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT;
+extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6;
+extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT;
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4;
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4_RESULT;
extern const isc::log::MessageID MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS6;
% MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS4 create or update client class: %1
Debug message issued when triggered an action to create or update client class
+% MYSQL_CB_CREATE_UPDATE_CLIENT_CLASS6 create or update client class: %1
+Debug message issued when triggered an action to create or update client class
+
% MYSQL_CB_CREATE_UPDATE_GLOBAL_PARAMETER4 create or update global parameter: %1
Debug message issued when triggered an action to create or update global parameter
% MYSQL_CB_DELETE_ALL_CLIENT_CLASSES4_RESULT deleted: %1 entries
Debug message indicating the result of an action to delete all client classes
+% MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6 delete all client classes
+Debug message issued when triggered an action to delete all client classes
+
+% MYSQL_CB_DELETE_ALL_CLIENT_CLASSES6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete all client classes
+
% MYSQL_CB_DELETE_ALL_GLOBAL_PARAMETERS4 delete all global parameters
Debug message issued when triggered an action to delete all global parameters
% MYSQL_CB_DELETE_CLIENT_CLASS4_RESULT deleted: %1 entries
Debug message indicating the result of an action to delete client class
+% MYSQL_CB_DELETE_CLIENT_CLASS6 delete client class: %1
+Debug message issued when triggered an action to delete client class
+
+% MYSQL_CB_DELETE_CLIENT_CLASS6_RESULT deleted: %1 entries
+Debug message indicating the result of an action to delete client class
+
% MYSQL_CB_DELETE_GLOBAL_PARAMETER4 delete global parameter: %1
Debug message issued when triggered an action to delete global parameter
% MYSQL_CB_GET_ALL_CLIENT_CLASSES4_RESULT retrieving: %1 elements
Debug message indicating the result of an action to retrieve all client classes
+% MYSQL_CB_GET_ALL_CLIENT_CLASSES6 retrieving all client classes
+Debug message issued when triggered an action to retrieve all client classes
+
+% MYSQL_CB_GET_ALL_CLIENT_CLASSES6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve all client classes
+
% MYSQL_CB_GET_ALL_GLOBAL_PARAMETERS4 retrieving all global parameters
Debug message issued when triggered an action to retrieve all global parameters
% MYSQL_CB_GET_CLIENT_CLASS4 retrieving client class: %1
Debug message issued when triggered an action to retrieve a client class
+% MYSQL_CB_GET_CLIENT_CLASS6 retrieving client class: %1
+Debug message issued when triggered an action to retrieve a client class
+
% MYSQL_CB_GET_GLOBAL_PARAMETER4 retrieving global parameter: %1
Debug message issued when triggered an action to retrieve global parameter
% MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES4_RESULT retrieving: %1 elements
Debug message indicating the result of an action to retrieve modified client classes from specified time
+% MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6 retrieving modified client classes from: %1
+Debug message issued when triggered an action to retrieve modified client classes from specified time
+
+% MYSQL_CB_GET_MODIFIED_CLIENT_CLASSES6_RESULT retrieving: %1 elements
+Debug message indicating the result of an action to retrieve modified client classes from specified time
+
% MYSQL_CB_GET_MODIFIED_GLOBAL_PARAMETERS4 retrieving modified global parameters from: %1
Debug message issued when triggered an action to retrieve modified global parameters from specified time
#endif
+#ifndef MYSQL_GET_CLIENT_CLASS6_COMMON
+#define MYSQL_GET_CLIENT_CLASS6_COMMON(server_join, ...) \
+ "SELECT " \
+ " c.id," \
+ " c.name," \
+ " c.test," \
+ " c.only_if_required," \
+ " c.valid_lifetime," \
+ " c.min_valid_lifetime," \
+ " c.max_valid_lifetime," \
+ " c.depend_on_known_directly," \
+ " o.depend_on_known_indirectly, " \
+ " c.modification_ts," \
+ " d.id," \
+ " d.code," \
+ " d.name," \
+ " d.space," \
+ " d.type," \
+ " d.modification_ts," \
+ " d.is_array," \
+ " d.encapsulate," \
+ " d.record_types," \
+ " d.user_context," \
+ " x.option_id," \
+ " x.code," \
+ " x.value," \
+ " x.formatted_value," \
+ " x.space," \
+ " x.persistent," \
+ " x.dhcp6_subnet_id," \
+ " x.scope_id," \
+ " x.user_context," \
+ " x.shared_network_name," \
+ " x.pool_id," \
+ " x.modification_ts," \
+ " s.tag " \
+ "FROM dhcp6_client_class AS c " \
+ "INNER JOIN dhcp6_client_class_order AS o " \
+ " ON c.id = o.class_id " \
+ server_join \
+ "LEFT JOIN dhcp6_option_def AS d ON c.id = d.class_id " \
+ "LEFT JOIN dhcp6_options AS x ON x.scope_id = 2 AND c.name = x.dhcp_client_class " \
+ #__VA_ARGS__ \
+ " ORDER BY o.order_index, d.id, x.option_id"
+
+#define MYSQL_GET_CLIENT_CLASS6_WITH_TAG(...) \
+ MYSQL_GET_CLIENT_CLASS6_COMMON( \
+ "INNER JOIN dhcp6_client_class_server AS a " \
+ " ON c.id = a.class_id " \
+ "INNER JOIN dhcp6_server AS s " \
+ " ON a.server_id = s.id ", \
+ __VA_ARGS__)
+
+#define MYSQL_GET_CLIENT_CLASS6_UNASSIGNED(...) \
+ MYSQL_GET_CLIENT_CLASS6_COMMON( \
+ "LEFT JOIN dhcp6_client_class_server AS a " \
+ " ON c.id = a.class_id " \
+ "LEFT JOIN dhcp4_server AS s " \
+ " ON a.server_id = s.id ", \
+ WHERE a.class_id IS NULL __VA_ARGS__)
+
+#endif
+
#ifndef MYSQL_INSERT_GLOBAL_PARAMETER
#define MYSQL_INSERT_GLOBAL_PARAMETER(table_prefix) \
"INSERT INTO " #table_prefix "_global_parameter(" \
" record_types," \
" user_context," \
" class_id" \
- ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, (SELECT id FROM dhcp4_client_class WHERE name = ?))"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, (SELECT id FROM " #table_prefix "_client_class WHERE name = ?))"
#endif
#ifndef MYSQL_INSERT_OPTION_DEF_SERVER
/// @brief Constructor.
MySqlConfigBackendDHCPv6Test()
: test_subnets_(), test_networks_(), test_option_defs_(),
- test_options_(), test_servers_(), timestamps_(), cbptr_(),
- audit_entries_() {
+ test_options_(), test_client_classes_(), test_servers_(), timestamps_(),
+ cbptr_(), audit_entries_() {
// Ensure we have the proper schema with no transient data.
createMySQLSchema();
initTestSubnets();
initTestSharedNetworks();
initTestOptionDefs();
+ initTestClientClasses();
initTimestamps();
}
LibDHCP::setRuntimeOptionDefs(defs);
}
+ /// @brief Creates several client classes used in tests.
+ void initTestClientClasses() {
+ ExpressionPtr match_expr = boost::make_shared<Expression>();
+ CfgOptionPtr cfg_option = boost::make_shared<CfgOption>();
+ auto class1 = boost::make_shared<ClientClassDef>("foo", match_expr, cfg_option);
+ class1->setRequired(true);
+ class1->setValid(Triplet<uint32_t>(30, 60, 90));
+ test_client_classes_.push_back(class1);
+
+ auto class2 = boost::make_shared<ClientClassDef>("bar", match_expr, cfg_option);
+ class2->setTest("member('foo')");
+ test_client_classes_.push_back(class2);
+
+ auto class3 = boost::make_shared<ClientClassDef>("foobar", match_expr, cfg_option);
+ class3->setTest("member('foo') and member('bar')");
+ test_client_classes_.push_back(class3);
+ }
+
/// @brief Initialize posix time values used in tests.
void initTimestamps() {
// Current time minus 1 hour to make sure it is in the past.
/// @brief Holds pointers to options used in tests.
std::vector<OptionDescriptorPtr> test_options_;
+ /// @brief Holds pointers to classes used in tests.
+ std::vector<ClientClassDefPtr> test_client_classes_;
+
/// @brief Holds pointers to the servers used in tests.
std::vector<ServerPtr> test_servers_;
}
}
+// This test verifies that it is possible to create client classes, update them
+// and retrieve all classes for a given server.
+TEST_F(MySqlConfigBackendDHCPv6Test, setAndGetAllClientClasses6) {
+ // Create a server.
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
+ {
+ SCOPED_TRACE("server1 is created");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server1"));
+ }
+ // Create first class.
+ auto class1 = test_client_classes_[0];
+ ASSERT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+ {
+ SCOPED_TRACE("client class foo is created");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+ // Create second class.
+ auto class2 = test_client_classes_[1];
+ ASSERT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
+ {
+ SCOPED_TRACE("client class bar is created");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+ // Create third class.
+ auto class3 = test_client_classes_[2];
+ ASSERT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, ""));
+ {
+ SCOPED_TRACE("client class foobar is created");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+ // Update the third class to depend on the second class.
+ class3->setTest("member('foo')");
+ ASSERT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, ""));
+ {
+ SCOPED_TRACE("client class bar is updated");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::UPDATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+ // Only the first class should be returned for the server selector ALL.
+ auto client_classes = cbptr_->getAllClientClasses6(ServerSelector::ALL());
+ ASSERT_EQ(1, client_classes.getClasses()->size());
+ // All three classes should be returned for the server1.
+ client_classes = cbptr_->getAllClientClasses6(ServerSelector::ONE("server1"));
+ auto classes_list = client_classes.getClasses();
+ ASSERT_EQ(3, classes_list->size());
+ EXPECT_EQ("foo", (*classes_list->begin())->getName());
+ EXPECT_EQ("bar", (*(classes_list->begin() + 1))->getName());
+ EXPECT_EQ("foobar", (*(classes_list->begin() + 2))->getName());
+
+
+ // Move the third class between the first and second class.
+ ASSERT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, "foo"));
+
+ // Ensure that the classes order has changed.
+ client_classes = cbptr_->getAllClientClasses6(ServerSelector::ONE("server1"));
+ classes_list = client_classes.getClasses();
+ ASSERT_EQ(3, classes_list->size());
+ EXPECT_EQ("foo", (*classes_list->begin())->getName());
+ EXPECT_EQ("foobar", (*(classes_list->begin() + 1))->getName());
+ EXPECT_EQ("bar", (*(classes_list->begin() + 2))->getName());
+}
+
+// This test verifies that a single class can be retrieved from the database.
+TEST_F(MySqlConfigBackendDHCPv6Test, getClientClass6) {
+ // Create a server.
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
+
+ // Add classes.
+ auto class1 = test_client_classes_[0];
+ EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[0]->option_,
+ test_options_[0]->persistent_,
+ test_options_[0]->space_name_));
+ EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[1]->option_,
+ test_options_[1]->persistent_,
+ test_options_[1]->space_name_));
+
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+
+ auto class2 = test_client_classes_[1];
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
+
+ // Get the first client class and validate its contents.
+ ClientClassDefPtr client_class;
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
+ ASSERT_TRUE(client_class);
+ EXPECT_EQ("foo", client_class->getName());
+ EXPECT_TRUE(client_class->getRequired());
+ EXPECT_EQ(30, client_class->getValid().getMin());
+ EXPECT_EQ(60, client_class->getValid().get());
+ EXPECT_EQ(90, client_class->getValid().getMax());
+
+ // Validate options belonging to this class.
+ ASSERT_TRUE(client_class->getCfgOption());
+ OptionDescriptor returned_opt_new_posix_timezone =
+ client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
+ ASSERT_TRUE(returned_opt_new_posix_timezone.option_);
+
+ OptionDescriptor returned_opt_preference =
+ client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_PREFERENCE);
+ ASSERT_TRUE(returned_opt_preference.option_);
+
+ // Fetch the same class using different server selectors.
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ANY(),
+ class1->getName()));
+ EXPECT_TRUE(client_class);
+
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ONE("server1"),
+ class1->getName()));
+ EXPECT_TRUE(client_class);
+
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::UNASSIGNED(),
+ class1->getName()));
+ EXPECT_FALSE(client_class);
+
+ // Fetch the second client class using different selectors. This time the
+ // class should not be returned for the ALL server selector because it is
+ // associated with the server1.
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ALL(),
+ class2->getName()));
+ EXPECT_FALSE(client_class);
+
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ANY(),
+ class2->getName()));
+ EXPECT_TRUE(client_class);
+
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ONE("server1"),
+ class2->getName()));
+ EXPECT_TRUE(client_class);
+
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::UNASSIGNED(),
+ class2->getName()));
+ EXPECT_FALSE(client_class);
+}
+
+// This test verifies that client class specific DHCP options can be
+// modified during the class update.
+TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateClientClass6Options) {
+ // Add class with two options and two option definitions.
+ auto class1 = test_client_classes_[0];
+ EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[0]->option_,
+ test_options_[0]->persistent_,
+ test_options_[0]->space_name_));
+ EXPECT_NO_THROW(class1->getCfgOption()->add(test_options_[1]->option_,
+ test_options_[1]->persistent_,
+ test_options_[1]->space_name_));
+ auto cfg_option_def = boost::make_shared<CfgOptionDef>();
+ class1->setCfgOptionDef(cfg_option_def);
+ EXPECT_NO_THROW(class1->getCfgOptionDef()->add(test_option_defs_[0]));
+ EXPECT_NO_THROW(class1->getCfgOptionDef()->add(test_option_defs_[2]));
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+
+ // Fetch the class and the options from the database.
+ ClientClassDefPtr client_class;
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
+ ASSERT_TRUE(client_class);
+
+ // Validate options belonging to the class.
+ ASSERT_TRUE(client_class->getCfgOption());
+ OptionDescriptor returned_opt_new_posix_timezone =
+ client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_NEW_POSIX_TIMEZONE);
+ ASSERT_TRUE(returned_opt_new_posix_timezone.option_);
+
+ OptionDescriptor returned_opt_preference =
+ client_class->getCfgOption()->get(DHCP6_OPTION_SPACE, D6O_PREFERENCE);
+ ASSERT_TRUE(returned_opt_preference.option_);
+
+ // Validate option definitions belonging to the class.
+ ASSERT_TRUE(client_class->getCfgOptionDef());
+ auto returned_def_foo = client_class->getCfgOptionDef()->get(test_option_defs_[0]->getOptionSpaceName(),
+ test_option_defs_[0]->getCode());
+
+ ASSERT_TRUE(returned_def_foo);
+ EXPECT_EQ(1234, returned_def_foo->getCode());
+ EXPECT_EQ("foo", returned_def_foo->getName());
+ EXPECT_EQ(DHCP6_OPTION_SPACE, returned_def_foo->getOptionSpaceName());
+ EXPECT_EQ("espace", returned_def_foo->getEncapsulatedSpace());
+ EXPECT_EQ(OPT_STRING_TYPE, returned_def_foo->getType());
+ EXPECT_FALSE(returned_def_foo->getArrayType());
+
+ auto returned_def_fish = client_class->getCfgOptionDef()->get(test_option_defs_[2]->getOptionSpaceName(),
+ test_option_defs_[2]->getCode());
+ ASSERT_TRUE(returned_def_fish);
+ EXPECT_EQ(5235, returned_def_fish->getCode());
+ EXPECT_EQ("fish", returned_def_fish->getName());
+ EXPECT_EQ(DHCP6_OPTION_SPACE, returned_def_fish->getOptionSpaceName());
+ EXPECT_TRUE(returned_def_fish->getEncapsulatedSpace().empty());
+ EXPECT_EQ(OPT_RECORD_TYPE, returned_def_fish->getType());
+ EXPECT_TRUE(returned_def_fish->getArrayType());
+
+ // Replace client class specific option definitions. Leave only one option
+ // definition.
+ cfg_option_def = boost::make_shared<CfgOptionDef>();
+ class1->setCfgOptionDef(cfg_option_def);
+ EXPECT_NO_THROW(class1->getCfgOptionDef()->add(test_option_defs_[2]));
+
+ // Delete one of the options and update the class.
+ class1->getCfgOption()->del(test_options_[0]->space_name_,
+ test_options_[0]->option_->getType());
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+ EXPECT_NO_THROW(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
+ ASSERT_TRUE(client_class);
+
+ // Ensure that the first option definition is gone.
+ ASSERT_TRUE(client_class->getCfgOptionDef());
+ returned_def_foo = client_class->getCfgOptionDef()->get(test_option_defs_[0]->getOptionSpaceName(),
+ test_option_defs_[0]->getCode());
+ EXPECT_FALSE(returned_def_foo);
+
+ // The second option definition should be present.
+ returned_def_fish = client_class->getCfgOptionDef()->get(test_option_defs_[2]->getOptionSpaceName(),
+ test_option_defs_[2]->getCode());
+ EXPECT_TRUE(returned_def_fish);
+
+ // Make sure that the first option is gone.
+ ASSERT_TRUE(client_class->getCfgOption());
+ returned_opt_new_posix_timezone = client_class->getCfgOption()->get(DHCP6_OPTION_SPACE,
+ D6O_NEW_POSIX_TIMEZONE);
+ EXPECT_FALSE(returned_opt_new_posix_timezone.option_);
+
+ // The second option should be there.
+ returned_opt_preference = client_class->getCfgOption()->get(DHCP6_OPTION_SPACE,
+ D6O_PREFERENCE);
+ ASSERT_TRUE(returned_opt_preference.option_);
+}
+
+// This test verifies that modified client classes can be retrieved from the database.
+TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedClientClasses6) {
+ // Create server1.
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
+
+ // Add three classes to the database with different timestamps.
+ auto class1 = test_client_classes_[0];
+ class1->setModificationTime(timestamps_["yesterday"]);
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+
+ auto class2 = test_client_classes_[1];
+ class2->setModificationTime(timestamps_["today"]);
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class2, ""));
+
+ auto class3 = test_client_classes_[2];
+ class3->setModificationTime(timestamps_["tomorrow"]);
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class3, ""));
+
+ // Get modified client classes configured for all servers.
+ auto client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ALL(),
+ timestamps_["two days ago"]);
+ EXPECT_EQ(2, client_classes.getClasses()->size());
+
+ // Get modified client classes appropriate for server1. It includes classes
+ // for all servers and for the server1.
+ client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
+ timestamps_["two days ago"]);
+ EXPECT_EQ(3, client_classes.getClasses()->size());
+
+ // Get the classes again but use the timestamp equal to the modification
+ // time of the first class.
+ client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
+ timestamps_["yesterday"]);
+ EXPECT_EQ(3, client_classes.getClasses()->size());
+
+ // Get modified classes starting from today. It should return only two.
+ client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
+ timestamps_["today"]);
+ EXPECT_EQ(2, client_classes.getClasses()->size());
+
+ // Get client classes modified in the future. It should return none.
+ client_classes = cbptr_->getModifiedClientClasses6(ServerSelector::ONE("server1"),
+ timestamps_["after tomorrow"]);
+ EXPECT_EQ(0, client_classes.getClasses()->size());
+
+ // Getting modified client classes for any server is unsupported.
+ EXPECT_THROW(cbptr_->getModifiedClientClasses6(ServerSelector::ANY(),
+ timestamps_["two days ago"]),
+ InvalidOperation);
+}
+
+// This test verifies that a specified client class can be deleted.
+TEST_F(MySqlConfigBackendDHCPv6Test, deleteClientClass6) {
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
+ {
+ SCOPED_TRACE("server1 is created");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server1"));
+ }
+ {
+ SCOPED_TRACE("server1 is created");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server2"));
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
+ {
+ SCOPED_TRACE("server1 is created and available for server1");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server1"));
+ }
+ {
+ SCOPED_TRACE("server1 is created and available for server2");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server2"));
+ }
+
+ auto class1 = test_client_classes_[0];
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+ {
+ SCOPED_TRACE("client class foo is created and available for server1");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+ {
+ SCOPED_TRACE("client class foo is created and available for server 2");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server2"));
+ }
+
+ auto class2 = test_client_classes_[1];
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
+ {
+ SCOPED_TRACE("client class bar is created");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+
+ auto class3 = test_client_classes_[2];
+ class3->setTest("member('foo')");
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server2"), class3, ""));
+ {
+ SCOPED_TRACE("client class foobar is created");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server2"));
+ }
+
+ uint64_t result;
+ EXPECT_NO_THROW(result = cbptr_->deleteClientClass6(ServerSelector::ONE("server1"),
+ class2->getName()));
+ EXPECT_EQ(1, result);
+ {
+ SCOPED_TRACE("client class bar is deleted");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::DELETE,
+ "client class deleted",
+ ServerSelector::ONE("server1"));
+ }
+
+ EXPECT_NO_THROW(result = cbptr_->deleteClientClass6(ServerSelector::ONE("server2"),
+ class3->getName()));
+ EXPECT_EQ(1, result);
+ {
+ SCOPED_TRACE("client class foobar is deleted");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::DELETE,
+ "client class deleted",
+ ServerSelector::ONE("server2"));
+ }
+
+ EXPECT_NO_THROW(result = cbptr_->deleteClientClass6(ServerSelector::ANY(),
+ class1->getName()));
+ EXPECT_EQ(1, result);
+ {
+ SCOPED_TRACE("client class foo is deleted and no longer available for the server1");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::DELETE,
+ "client class deleted",
+ ServerSelector::ONE("server1"));
+ }
+ {
+ SCOPED_TRACE("client class foo is deleted and no longer available for the server2");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::DELETE,
+ "client class deleted",
+ ServerSelector::ONE("server2"));
+ }
+}
+
+// This test verifies that all client classes can be deleted using
+// a specified server selector.
+TEST_F(MySqlConfigBackendDHCPv6Test, deleteAllClientClasses6) {
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
+ {
+ SCOPED_TRACE("server1 is created");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server1"));
+ }
+ {
+ SCOPED_TRACE("server1 is created");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server2"));
+ }
+
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[2]));
+ {
+ SCOPED_TRACE("server1 is created and available for server1");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server1"));
+ }
+ {
+ SCOPED_TRACE("server1 is created and available for server2");
+ testNewAuditEntry("dhcp6_server",
+ AuditEntry::ModificationType::CREATE,
+ "server set",
+ ServerSelector::ONE("server2"));
+ }
+
+ auto class1 = test_client_classes_[0];
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+ {
+ SCOPED_TRACE("client class foo is created and available for server1");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+ {
+ SCOPED_TRACE("client class foo is created and available for server 2");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server2"));
+ }
+
+ auto class2 = test_client_classes_[1];
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server1"), class2, ""));
+ {
+ SCOPED_TRACE("client class bar is created");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server1"));
+ }
+
+ auto class3 = test_client_classes_[2];
+ class3->setTest("member('foo')");
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ONE("server2"), class3, ""));
+ {
+ SCOPED_TRACE("client class foobar is created");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::CREATE,
+ "client class set",
+ ServerSelector::ONE("server2"));
+ }
+
+ uint64_t result;
+
+ EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::UNASSIGNED()));
+ EXPECT_EQ(0, result);
+
+ EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server2")));
+ EXPECT_EQ(1, result);
+ {
+ SCOPED_TRACE("client classes for server2 deleted");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::DELETE,
+ "deleted all client classes",
+ ServerSelector::ONE("server2"));
+ }
+
+ EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server2")));
+ EXPECT_EQ(0, result);
+
+ EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server1")));
+ EXPECT_EQ(1, result);
+ {
+ SCOPED_TRACE("client classes for server1 deleted");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::DELETE,
+ "deleted all client classes",
+ ServerSelector::ONE("server1"));
+ }
+
+ EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ONE("server1")));
+ EXPECT_EQ(0, result);
+
+ EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ALL()));
+ EXPECT_EQ(1, result);
+ {
+ SCOPED_TRACE("client classes for all deleted");
+ testNewAuditEntry("dhcp6_client_class",
+ AuditEntry::ModificationType::DELETE,
+ "deleted all client classes",
+ ServerSelector::ONE("server1"));
+ }
+
+ EXPECT_NO_THROW(result = cbptr_->deleteAllClientClasses6(ServerSelector::ALL()));
+ EXPECT_EQ(0, result);
+
+ // Deleting multiple objects using ANY server tag is unsupported.
+ EXPECT_THROW(cbptr_->deleteAllClientClasses6(ServerSelector::ANY()), InvalidOperation);
+}
+
+// This test verifies that client class dependencies are tracked when the
+// classes are added to the database. It verifies that an attempt to update
+// a class violiting the dependencies results in an error.
+TEST_F(MySqlConfigBackendDHCPv6Test, clientClassDependencies6) {
+ // Create a server.
+ EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
+
+ // Create first class. It depends on KNOWN built-in class.
+ auto class1 = test_client_classes_[0];
+ class1->setTest("member('KNOWN')");
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""));
+
+ // Create second class which depends on the first class. This yelds indirect
+ // dependency on KNOWN class.
+ auto class2 = test_client_classes_[1];
+ class2->setTest("member('foo')");
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class2, ""));
+
+ // Create third class depending on the second class. This also yelds indirect
+ // dependency on KNOWN class.
+ auto class3 = test_client_classes_[2];
+ class3->setTest("member('bar')");
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class3, ""));
+
+ // Try to change the dependency of the first class. There are other classes
+ // having indirect dependency on KNOWN class via this class. Therefore, the
+ // update should be unsuccessful.
+ class1->setTest("member('HA_server1')");
+ EXPECT_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class1, ""),
+ DbOperationError);
+
+ // Try to change the dependency of the second class. This should result in
+ // an error because the third class depends on it.
+ class2->setTest("member('HA_server1')");
+ EXPECT_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class2, ""),
+ DbOperationError);
+
+ // Changing the indirect dependency of the third class should succeed, because
+ // no other classes depend on this class.
+ class3->setTest("member('HA_server1')");
+ EXPECT_NO_THROW(cbptr_->createUpdateClientClass6(ServerSelector::ALL(), class3, ""));
+}
+
/// This test verifies that audit entries can be retrieved from a given
/// timestamp and id including when two entries can get the same timestamp.
/// (either it is a common even and this should catch it, or it is a rare
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/client_class_def.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
#include <boost/shared_ptr.hpp>
getModifiedGlobalParameters6(const db::ServerSelector& selector,
const boost::posix_time::ptime& modification_time) const = 0;
+ /// @brief Retrieves a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Client class name.
+ /// @return Pointer to the retrieved client class.
+ virtual ClientClassDefPtr
+ getClientClass6(const db::ServerSelector& selector, const std::string& name) const = 0;
+
+ /// @brief Retrieves all client classes.
+ ///
+ /// @param selector Server selector.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getAllClientClasses6(const db::ServerSelector& selector) const = 0;
+
+ /// @brief Retrieves client classes modified after specified time.
+ ///
+ /// @param selector Server selector.
+ /// @param modification_time Modification time.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getModifiedClientClasses6(const db::ServerSelector& selector,
+ const boost::posix_time::ptime& modification_time) const = 0;
+
/// @brief Retrieves the most recent audit entries.
///
/// Allowed server selectors: ALL, ONE.
createUpdateGlobalParameter6(const db::ServerSelector& server_selector,
const data::StampedValuePtr& value) = 0;
+ /// @brief Creates or updates a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Client class to be added or updated.
+ /// @param follow_client_class name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ virtual void
+ createUpdateClientClass6(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_class_name) = 0;
+
/// @brief Creates or updates a server.
///
/// @param server Instance of the server to be stored.
virtual uint64_t
deleteAllGlobalParameters6(const db::ServerSelector& server_selector) = 0;
+ /// @brief Deletes a client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be deleted.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name) = 0;
+
+ /// @brief Deletes all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteAllClientClasses6(const db::ServerSelector& server_selector) = 0;
+
/// @brief Deletes a server from the backend.
///
/// @param server_tag Tag of the server to be deleted.
-// Copyright (C) 2019-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2019-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
return (globals);
}
+ClientClassDefPtr
+TestConfigBackendDHCPv6::getClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name) const {
+ auto client_class = classes_.findClass(name);
+ if (!client_class) {
+ return (client_class);
+ }
+ if (server_selector.amUnassigned()) {
+ return (client_class->getServerTags().empty() ? client_class : ClientClassDefPtr());
+ }
+ auto tags = server_selector.getTags();
+ for (auto tag : tags) {
+ if (client_class->hasServerTag(ServerTag(tag))) {
+ return (client_class);
+ }
+ }
+ return (client_class->hasAllServerTag() ? client_class : ClientClassDefPtr());
+}
+
+ClientClassDictionary
+TestConfigBackendDHCPv6::getAllClientClasses6(const db::ServerSelector& server_selector) const {
+ auto tags = server_selector.getTags();
+ ClientClassDictionary all_classes;
+ for (auto client_class : *classes_.getClasses()) {
+ auto non_const_client_class = boost::const_pointer_cast<ClientClassDef>(client_class);
+ if (server_selector.amAny()) {
+ all_classes.addClass(non_const_client_class);
+ continue;
+ }
+ if (server_selector.amUnassigned()) {
+ if (client_class->getServerTags().empty()) {
+ all_classes.addClass(non_const_client_class);
+ }
+ continue;
+ }
+ bool got = false;
+ for (auto tag : tags) {
+ if (client_class->hasServerTag(ServerTag(tag))) {
+ all_classes.addClass(non_const_client_class);
+ got = true;
+ break;
+ }
+ }
+ if (got) {
+ continue;
+ }
+ if (client_class->hasAllServerTag()) {
+ all_classes.addClass(non_const_client_class);
+ }
+ }
+ return (all_classes);
+}
+
+ClientClassDictionary
+TestConfigBackendDHCPv6::getModifiedClientClasses6(const db::ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time) const {
+ auto tags = server_selector.getTags();
+ ClientClassDictionary modified_classes;
+ for (auto client_class : *classes_.getClasses()) {
+ if (client_class->getModificationTime() >= modification_time) {
+ auto non_const_client_class = boost::const_pointer_cast<ClientClassDef>(client_class);
+ bool got = false;
+ for (auto tag : tags) {
+ if (client_class->hasServerTag(ServerTag(tag))) {
+ modified_classes.addClass(non_const_client_class);
+ got = true;
+ break;
+ }
+ }
+ if (got) {
+ continue;
+ }
+ if (client_class->hasAllServerTag()) {
+ modified_classes.addClass(non_const_client_class);
+ }
+ }
+ }
+ return (modified_classes);
+}
+
+void
+TestConfigBackendDHCPv6::createUpdateClientClass6(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_client_class) {
+ mergeServerTags(client_class, server_selector);
+
+ auto existing_class = classes_.findClass(client_class->getName());
+ if (existing_class) {
+ classes_.removeClass(client_class->getName());
+ }
+ auto non_const_client_class = boost::const_pointer_cast<ClientClassDef>(client_class);
+ classes_.addClass(non_const_client_class);
+}
+
AuditEntryCollection
TestConfigBackendDHCPv6::getRecentAuditEntries(const db::ServerSelector&,
const boost::posix_time::ptime&,
return (cnt);
}
+uint64_t
+TestConfigBackendDHCPv6::deleteClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name) {
+ auto existing_class = classes_.findClass(name);
+ if (!existing_class) {
+ return (0);
+ }
+ if ((server_selector.amUnassigned()) &&
+ !existing_class->getServerTags().empty()) {
+ return (0);
+ }
+ if (!server_selector.amAny()) {
+ bool got = false;
+ auto tags = server_selector.getTags();
+ for (auto tag : tags) {
+ if (existing_class->hasServerTag(ServerTag(tag))) {
+ got = true;
+ break;
+ }
+ }
+ if (!got && !existing_class->hasAllServerTag()) {
+ return (0);
+ }
+ }
+ classes_.removeClass(name);
+ return (1);
+}
+
+uint64_t
+TestConfigBackendDHCPv6::deleteAllClientClasses6(const db::ServerSelector& server_selector) {
+ std::list<std::string> class_names;
+ for (auto client_class : (*classes_.getClasses())) {
+ if (server_selector.amAny()) {
+ class_names.push_back(client_class->getName());
+ continue;
+ }
+ if (server_selector.amUnassigned()) {
+ if (client_class->getServerTags().empty()) {
+ class_names.push_back(client_class->getName());
+ }
+ continue;
+ }
+ bool got = false;
+ auto tags = server_selector.getTags();
+ for (auto tag : tags) {
+ if (client_class->hasServerTag(ServerTag(tag))) {
+ class_names.push_back(client_class->getName());
+ got = true;
+ break;
+ }
+ }
+ if (got) {
+ continue;
+ }
+ if (client_class->hasAllServerTag()) {
+ class_names.push_back(client_class->getName());
+ }
+ }
+
+ // Erase client classes.
+ for (auto name : class_names) {
+ classes_.removeClass(name);
+ }
+ return (class_names.size());
+}
+
uint64_t
TestConfigBackendDHCPv6::deleteServer6(const ServerTag& server_tag) {
auto& index = servers_.get<ServerTagIndexTag>();
getModifiedGlobalParameters6(const db::ServerSelector& server_selector,
const boost::posix_time::ptime& modification_time) const;
+ /// @brief Retrieves a client class by name.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Client class name.
+ /// @return Pointer to the retrieved client class.
+ virtual ClientClassDefPtr
+ getClientClass6(const db::ServerSelector& selector, const std::string& name) const;
+
+ /// @brief Retrieves all client classes.
+ ///
+ /// @param selector Server selector.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getAllClientClasses6(const db::ServerSelector& selector) const;
+
+ /// @brief Retrieves client classes modified after specified time.
+ ///
+ /// @param selector Server selector.
+ /// @param modification_time Modification time.
+ /// @return Collection of client classes.
+ virtual ClientClassDictionary
+ getModifiedClientClasses6(const db::ServerSelector& selector,
+ const boost::posix_time::ptime& modification_time) const;
+
/// @brief Retrieves the most recent audit entries.
///
/// @param server_selector Server selector.
createUpdateGlobalParameter6(const db::ServerSelector& server_selector,
const data::StampedValuePtr& value);
+ /// @brief Creates or updates DHCPv6 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param client_class Client class to be added or updated.
+ /// @param follow_client_class name of the class after which the
+ /// new or updated class should be positioned. An empty value
+ /// causes the class to be appended at the end of the class
+ /// hierarchy.
+ virtual void
+ createUpdateClientClass6(const db::ServerSelector& server_selector,
+ const ClientClassDefPtr& client_class,
+ const std::string& follow_client_class);
+
/// @brief Creates or updates a server.
///
/// @param server Instance of the server to be stored.
virtual uint64_t
deleteAllGlobalParameters6(const db::ServerSelector& server_selector);
+ /// @brief Deletes DHCPv6 client class.
+ ///
+ /// @param server_selector Server selector.
+ /// @param name Name of the class to be deleted.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteClientClass6(const db::ServerSelector& server_selector,
+ const std::string& name);
+
+ /// @brief Deletes all client classes.
+ ///
+ /// @param server_selector Server selector.
+ /// @return Number of deleted client classes.
+ virtual uint64_t
+ deleteAllClientClasses6(const db::ServerSelector& server_selector);
+
/// @brief Deletes a server from the backend.
///
/// @param server_tag Tag of the server to be deleted.
OptionDefContainer option_defs_;
OptionContainer options_;
data::StampedValueCollection globals_;
+ ClientClassDictionary classes_;
db::ServerCollection servers_;
/// @}
};