2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-29 13:07:50 +00:00

[5533a] Rebased

This commit is contained in:
Francis Dupont 2018-02-23 23:48:32 +01:00
commit fe232dabca
72 changed files with 7802 additions and 5800 deletions

3
.gitmodules vendored
View File

@ -0,0 +1,3 @@
[submodule "premium"]
path = premium
url = ssh://fdupont@repo.isc.org/proj/git/prod/kea-premium.git

View File

@ -54,13 +54,17 @@
// reservations list, within the subnet (configuration file). If there are
// no reservations there, the server will try to retrieve reservations
// from this database.
"hosts-database": {
"type": "postgresql",
"name": "kea",
"user": "kea",
"password": "kea",
"host": "localhost"
},
// The database specification can go into one hosts-database entry for
// backward compatibility or be listed in hosts-databases list.
"hosts-databases": [
{
"type": "postgresql",
"name": "kea",
"user": "kea",
"password": "kea",
"host": "localhost"
}
],
// Define a subnet with a single pool of dynamic addresses. Addresses from
// this pool will be assigned to clients which don't have reservations in the

View File

@ -41,13 +41,17 @@
// reservations list, within the subnet (configuration file). If there are
// no reservations there, the server will try to retrieve reservations
// from this database.
"hosts-database": {
"type": "postgresql",
"name": "kea",
"user": "kea",
"password": "kea",
"host": "localhost"
},
// The database specification can go into one hosts-database entry for
// backward compatibility or be listed in hosts-databases list.
"hosts-databases": [
{
"type": "postgresql",
"name": "kea",
"user": "kea",
"password": "kea",
"host": "localhost"
}
],
// Define a subnet with a pool of dynamic addresses and a pool of dynamic
// prefixes. Addresses and prefixes from those pools will be assigned to

View File

@ -529,7 +529,13 @@ If a timeout is given though, it should be an integer greater than zero.
from the configuration file are checked first and external storage is checked
later, if necessary.</para>
<section xml:id="hosts-database-configuration4">
<para>Version 1.4 extends the host storage to multiple storages. Operations
are performed on host storages in the configuration order with a special
case for addition: read-only storages must be configured after a
required read-write storage, or host reservation addition will
always fail.</para>
<section xml:id="hosts-databases-configuration4">
<title>DHCPv4 Hosts Database Configuration</title>
<para>Hosts database configuration is controlled through the Dhcp4/hosts-database
@ -572,6 +578,16 @@ If a timeout is given though, it should be an integer greater than zero.
</screen>
If there is no password to the account, set the password to the empty string
"". (This is also the default.)</para>
<para>The multiple storage extension uses a similar syntax: a configuration
is placed into a "hosts-databases" list instead of into a "hosts-database"
entry as in:
<screen>
"Dhcp4": { "hosts-databases": [ { <userinput>"type": "mysql"</userinput>, ... }, ... ], ... }
</screen>
</para>
</section>
<section xml:id="read-only-database-configuration4">

View File

@ -525,7 +525,13 @@ If a timeout is given though, it should be an integer greater than zero.
from the configuration file are checked first and external storage is checked
later, if necessary.</para>
<section xml:id="hosts-database-configuration6">
<para>Version 1.4 extends the host storage to multiple storages. Operations
are performed on host storages in the configuration order with a special
case for addition: read-only storages must be configured after a
required read-write storage, or host reservation addition will
always fail.</para>
<section xml:id="hosts-databases-configuration6">
<title>DHCPv6 Hosts Database Configuration</title>
<para>Hosts database configuration is controlled through the Dhcp6/hosts-database
@ -565,6 +571,16 @@ If a timeout is given though, it should be an integer greater than zero.
</screen>
If there is no password to the account, set the password to the empty string
"". (This is also the default.)</para>
<para>The multiple storage extension uses a similar syntax: a configuration
is placed into a "hosts-databases" list instead of into a "hosts-database"
entry as in:
<screen>
"Dhcp6": { "hosts-databases": [ { <userinput>"type": "mysql"</userinput>, ... }, ... ], ... }
</screen>
</para>
</section>
<section xml:id="read-only-database-configuration6">

View File

@ -1083,9 +1083,9 @@ $
criteria). To use commands that change the reservation information
(currently these are reservation-add and reservation-del, but this
rule applies to other commands that may be implemented in the future),
hosts database must be specified (see hosts-database description in
<xref linkend="hosts-database-configuration4"/> and <xref linkend="hosts-database-configuration6"/>) and it must not operate in
read-only mode. If the hosts-database is not specified or is running
hosts database must be specified (see hosts-databases description in
<xref linkend="hosts-databases-configuration4"/> and <xref linkend="hosts-databases-configuration6"/>) and it must not operate in
read-only mode. If the hosts-databases are not specified or are running
in read-only mode, the host_cmds library will load, but any attempts
to use reservation-add or reservation-del will fail.
</para>
@ -1204,8 +1204,8 @@ Here is an example of complex IPv6 reservation:
<para>
As <command>reservation-add</command> is expected to store the host,
hosts-database parameter must be specified in your configuration and
the database must not run in read-only mode. In the future versions
hosts-databases parameter must be specified in your configuration and
databases must not run in read-only mode. In the future versions
it will be possible to modify the reservations read from a
configuration file. Please contact ISC if you are interested in this
functionality.

1
premium Submodule

@ -0,0 +1 @@
Subproject commit 7eae81e92f9ea28349f0c933a5123c20483bc078

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2016-2018 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
@ -294,6 +294,15 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"hosts-databases\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:
return isc::dhcp::Dhcp4Parser::make_HOSTS_DATABASES(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("hosts-databases", driver.loc_);
}
}
\"readonly\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::HOSTS_DATABASE:

File diff suppressed because it is too large Load Diff

View File

@ -372,131 +372,132 @@ namespace isc { namespace dhcp {
TOKEN_BOOT_FILE_NAME = 279,
TOKEN_LEASE_DATABASE = 280,
TOKEN_HOSTS_DATABASE = 281,
TOKEN_TYPE = 282,
TOKEN_MEMFILE = 283,
TOKEN_MYSQL = 284,
TOKEN_POSTGRESQL = 285,
TOKEN_CQL = 286,
TOKEN_USER = 287,
TOKEN_PASSWORD = 288,
TOKEN_HOST = 289,
TOKEN_PORT = 290,
TOKEN_PERSIST = 291,
TOKEN_LFC_INTERVAL = 292,
TOKEN_READONLY = 293,
TOKEN_CONNECT_TIMEOUT = 294,
TOKEN_CONTACT_POINTS = 295,
TOKEN_KEYSPACE = 296,
TOKEN_VALID_LIFETIME = 297,
TOKEN_RENEW_TIMER = 298,
TOKEN_REBIND_TIMER = 299,
TOKEN_DECLINE_PROBATION_PERIOD = 300,
TOKEN_SUBNET4 = 301,
TOKEN_SUBNET_4O6_INTERFACE = 302,
TOKEN_SUBNET_4O6_INTERFACE_ID = 303,
TOKEN_SUBNET_4O6_SUBNET = 304,
TOKEN_OPTION_DEF = 305,
TOKEN_OPTION_DATA = 306,
TOKEN_NAME = 307,
TOKEN_DATA = 308,
TOKEN_CODE = 309,
TOKEN_SPACE = 310,
TOKEN_CSV_FORMAT = 311,
TOKEN_ALWAYS_SEND = 312,
TOKEN_RECORD_TYPES = 313,
TOKEN_ENCAPSULATE = 314,
TOKEN_ARRAY = 315,
TOKEN_SHARED_NETWORKS = 316,
TOKEN_POOLS = 317,
TOKEN_POOL = 318,
TOKEN_USER_CONTEXT = 319,
TOKEN_COMMENT = 320,
TOKEN_SUBNET = 321,
TOKEN_INTERFACE = 322,
TOKEN_INTERFACE_ID = 323,
TOKEN_ID = 324,
TOKEN_RAPID_COMMIT = 325,
TOKEN_RESERVATION_MODE = 326,
TOKEN_DISABLED = 327,
TOKEN_OUT_OF_POOL = 328,
TOKEN_ALL = 329,
TOKEN_HOST_RESERVATION_IDENTIFIERS = 330,
TOKEN_CLIENT_CLASSES = 331,
TOKEN_TEST = 332,
TOKEN_CLIENT_CLASS = 333,
TOKEN_RESERVATIONS = 334,
TOKEN_DUID = 335,
TOKEN_HW_ADDRESS = 336,
TOKEN_CIRCUIT_ID = 337,
TOKEN_CLIENT_ID = 338,
TOKEN_HOSTNAME = 339,
TOKEN_FLEX_ID = 340,
TOKEN_RELAY = 341,
TOKEN_IP_ADDRESS = 342,
TOKEN_HOOKS_LIBRARIES = 343,
TOKEN_LIBRARY = 344,
TOKEN_PARAMETERS = 345,
TOKEN_EXPIRED_LEASES_PROCESSING = 346,
TOKEN_RECLAIM_TIMER_WAIT_TIME = 347,
TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 348,
TOKEN_HOLD_RECLAIMED_TIME = 349,
TOKEN_MAX_RECLAIM_LEASES = 350,
TOKEN_MAX_RECLAIM_TIME = 351,
TOKEN_UNWARNED_RECLAIM_CYCLES = 352,
TOKEN_DHCP4O6_PORT = 353,
TOKEN_CONTROL_SOCKET = 354,
TOKEN_SOCKET_TYPE = 355,
TOKEN_SOCKET_NAME = 356,
TOKEN_DHCP_DDNS = 357,
TOKEN_ENABLE_UPDATES = 358,
TOKEN_QUALIFYING_SUFFIX = 359,
TOKEN_SERVER_IP = 360,
TOKEN_SERVER_PORT = 361,
TOKEN_SENDER_IP = 362,
TOKEN_SENDER_PORT = 363,
TOKEN_MAX_QUEUE_SIZE = 364,
TOKEN_NCR_PROTOCOL = 365,
TOKEN_NCR_FORMAT = 366,
TOKEN_ALWAYS_INCLUDE_FQDN = 367,
TOKEN_OVERRIDE_NO_UPDATE = 368,
TOKEN_OVERRIDE_CLIENT_UPDATE = 369,
TOKEN_REPLACE_CLIENT_NAME = 370,
TOKEN_GENERATED_PREFIX = 371,
TOKEN_TCP = 372,
TOKEN_JSON = 373,
TOKEN_WHEN_PRESENT = 374,
TOKEN_NEVER = 375,
TOKEN_ALWAYS = 376,
TOKEN_WHEN_NOT_PRESENT = 377,
TOKEN_LOGGING = 378,
TOKEN_LOGGERS = 379,
TOKEN_OUTPUT_OPTIONS = 380,
TOKEN_OUTPUT = 381,
TOKEN_DEBUGLEVEL = 382,
TOKEN_SEVERITY = 383,
TOKEN_FLUSH = 384,
TOKEN_MAXSIZE = 385,
TOKEN_MAXVER = 386,
TOKEN_DHCP6 = 387,
TOKEN_DHCPDDNS = 388,
TOKEN_CONTROL_AGENT = 389,
TOKEN_TOPLEVEL_JSON = 390,
TOKEN_TOPLEVEL_DHCP4 = 391,
TOKEN_SUB_DHCP4 = 392,
TOKEN_SUB_INTERFACES4 = 393,
TOKEN_SUB_SUBNET4 = 394,
TOKEN_SUB_POOL4 = 395,
TOKEN_SUB_RESERVATION = 396,
TOKEN_SUB_OPTION_DEFS = 397,
TOKEN_SUB_OPTION_DEF = 398,
TOKEN_SUB_OPTION_DATA = 399,
TOKEN_SUB_HOOKS_LIBRARY = 400,
TOKEN_SUB_DHCP_DDNS = 401,
TOKEN_SUB_LOGGING = 402,
TOKEN_STRING = 403,
TOKEN_INTEGER = 404,
TOKEN_FLOAT = 405,
TOKEN_BOOLEAN = 406
TOKEN_HOSTS_DATABASES = 282,
TOKEN_TYPE = 283,
TOKEN_MEMFILE = 284,
TOKEN_MYSQL = 285,
TOKEN_POSTGRESQL = 286,
TOKEN_CQL = 287,
TOKEN_USER = 288,
TOKEN_PASSWORD = 289,
TOKEN_HOST = 290,
TOKEN_PORT = 291,
TOKEN_PERSIST = 292,
TOKEN_LFC_INTERVAL = 293,
TOKEN_READONLY = 294,
TOKEN_CONNECT_TIMEOUT = 295,
TOKEN_CONTACT_POINTS = 296,
TOKEN_KEYSPACE = 297,
TOKEN_VALID_LIFETIME = 298,
TOKEN_RENEW_TIMER = 299,
TOKEN_REBIND_TIMER = 300,
TOKEN_DECLINE_PROBATION_PERIOD = 301,
TOKEN_SUBNET4 = 302,
TOKEN_SUBNET_4O6_INTERFACE = 303,
TOKEN_SUBNET_4O6_INTERFACE_ID = 304,
TOKEN_SUBNET_4O6_SUBNET = 305,
TOKEN_OPTION_DEF = 306,
TOKEN_OPTION_DATA = 307,
TOKEN_NAME = 308,
TOKEN_DATA = 309,
TOKEN_CODE = 310,
TOKEN_SPACE = 311,
TOKEN_CSV_FORMAT = 312,
TOKEN_ALWAYS_SEND = 313,
TOKEN_RECORD_TYPES = 314,
TOKEN_ENCAPSULATE = 315,
TOKEN_ARRAY = 316,
TOKEN_SHARED_NETWORKS = 317,
TOKEN_POOLS = 318,
TOKEN_POOL = 319,
TOKEN_USER_CONTEXT = 320,
TOKEN_COMMENT = 321,
TOKEN_SUBNET = 322,
TOKEN_INTERFACE = 323,
TOKEN_INTERFACE_ID = 324,
TOKEN_ID = 325,
TOKEN_RAPID_COMMIT = 326,
TOKEN_RESERVATION_MODE = 327,
TOKEN_DISABLED = 328,
TOKEN_OUT_OF_POOL = 329,
TOKEN_ALL = 330,
TOKEN_HOST_RESERVATION_IDENTIFIERS = 331,
TOKEN_CLIENT_CLASSES = 332,
TOKEN_TEST = 333,
TOKEN_CLIENT_CLASS = 334,
TOKEN_RESERVATIONS = 335,
TOKEN_DUID = 336,
TOKEN_HW_ADDRESS = 337,
TOKEN_CIRCUIT_ID = 338,
TOKEN_CLIENT_ID = 339,
TOKEN_HOSTNAME = 340,
TOKEN_FLEX_ID = 341,
TOKEN_RELAY = 342,
TOKEN_IP_ADDRESS = 343,
TOKEN_HOOKS_LIBRARIES = 344,
TOKEN_LIBRARY = 345,
TOKEN_PARAMETERS = 346,
TOKEN_EXPIRED_LEASES_PROCESSING = 347,
TOKEN_RECLAIM_TIMER_WAIT_TIME = 348,
TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 349,
TOKEN_HOLD_RECLAIMED_TIME = 350,
TOKEN_MAX_RECLAIM_LEASES = 351,
TOKEN_MAX_RECLAIM_TIME = 352,
TOKEN_UNWARNED_RECLAIM_CYCLES = 353,
TOKEN_DHCP4O6_PORT = 354,
TOKEN_CONTROL_SOCKET = 355,
TOKEN_SOCKET_TYPE = 356,
TOKEN_SOCKET_NAME = 357,
TOKEN_DHCP_DDNS = 358,
TOKEN_ENABLE_UPDATES = 359,
TOKEN_QUALIFYING_SUFFIX = 360,
TOKEN_SERVER_IP = 361,
TOKEN_SERVER_PORT = 362,
TOKEN_SENDER_IP = 363,
TOKEN_SENDER_PORT = 364,
TOKEN_MAX_QUEUE_SIZE = 365,
TOKEN_NCR_PROTOCOL = 366,
TOKEN_NCR_FORMAT = 367,
TOKEN_ALWAYS_INCLUDE_FQDN = 368,
TOKEN_OVERRIDE_NO_UPDATE = 369,
TOKEN_OVERRIDE_CLIENT_UPDATE = 370,
TOKEN_REPLACE_CLIENT_NAME = 371,
TOKEN_GENERATED_PREFIX = 372,
TOKEN_TCP = 373,
TOKEN_JSON = 374,
TOKEN_WHEN_PRESENT = 375,
TOKEN_NEVER = 376,
TOKEN_ALWAYS = 377,
TOKEN_WHEN_NOT_PRESENT = 378,
TOKEN_LOGGING = 379,
TOKEN_LOGGERS = 380,
TOKEN_OUTPUT_OPTIONS = 381,
TOKEN_OUTPUT = 382,
TOKEN_DEBUGLEVEL = 383,
TOKEN_SEVERITY = 384,
TOKEN_FLUSH = 385,
TOKEN_MAXSIZE = 386,
TOKEN_MAXVER = 387,
TOKEN_DHCP6 = 388,
TOKEN_DHCPDDNS = 389,
TOKEN_CONTROL_AGENT = 390,
TOKEN_TOPLEVEL_JSON = 391,
TOKEN_TOPLEVEL_DHCP4 = 392,
TOKEN_SUB_DHCP4 = 393,
TOKEN_SUB_INTERFACES4 = 394,
TOKEN_SUB_SUBNET4 = 395,
TOKEN_SUB_POOL4 = 396,
TOKEN_SUB_RESERVATION = 397,
TOKEN_SUB_OPTION_DEFS = 398,
TOKEN_SUB_OPTION_DEF = 399,
TOKEN_SUB_OPTION_DATA = 400,
TOKEN_SUB_HOOKS_LIBRARY = 401,
TOKEN_SUB_DHCP_DDNS = 402,
TOKEN_SUB_LOGGING = 403,
TOKEN_STRING = 404,
TOKEN_INTEGER = 405,
TOKEN_FLOAT = 406,
TOKEN_BOOLEAN = 407
};
};
@ -711,6 +712,10 @@ namespace isc { namespace dhcp {
symbol_type
make_HOSTS_DATABASE (const location_type& l);
static inline
symbol_type
make_HOSTS_DATABASES (const location_type& l);
static inline
symbol_type
make_TYPE (const location_type& l);
@ -1416,12 +1421,12 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 886, ///< Last index in yytable_.
yynnts_ = 338, ///< Number of nonterminal symbols.
yylast_ = 903, ///< Last index in yytable_.
yynnts_ = 344, ///< Number of nonterminal symbols.
yyfinal_ = 28, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 152 ///< Number of tokens.
yyntokens_ = 153 ///< Number of tokens.
};
@ -1478,9 +1483,9 @@ namespace isc { namespace dhcp {
115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151
145, 146, 147, 148, 149, 150, 151, 152
};
const unsigned int user_token_number_max_ = 406;
const unsigned int user_token_number_max_ = 407;
const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_)
@ -1513,30 +1518,30 @@ namespace isc { namespace dhcp {
{
switch (other.type_get ())
{
case 167: // value
case 171: // map_value
case 209: // socket_type
case 212: // outbound_interface_value
case 222: // db_type
case 299: // hr_mode
case 445: // ncr_protocol_value
case 453: // replace_client_name_value
case 168: // value
case 172: // map_value
case 210: // socket_type
case 213: // outbound_interface_value
case 229: // db_type
case 306: // hr_mode
case 452: // ncr_protocol_value
case 460: // replace_client_name_value
value.copy< ElementPtr > (other.value);
break;
case 151: // "boolean"
case 152: // "boolean"
value.copy< bool > (other.value);
break;
case 150: // "floating point"
case 151: // "floating point"
value.copy< double > (other.value);
break;
case 149: // "integer"
case 150: // "integer"
value.copy< int64_t > (other.value);
break;
case 148: // "constant string"
case 149: // "constant string"
value.copy< std::string > (other.value);
break;
@ -1557,30 +1562,30 @@ namespace isc { namespace dhcp {
(void) v;
switch (this->type_get ())
{
case 167: // value
case 171: // map_value
case 209: // socket_type
case 212: // outbound_interface_value
case 222: // db_type
case 299: // hr_mode
case 445: // ncr_protocol_value
case 453: // replace_client_name_value
case 168: // value
case 172: // map_value
case 210: // socket_type
case 213: // outbound_interface_value
case 229: // db_type
case 306: // hr_mode
case 452: // ncr_protocol_value
case 460: // replace_client_name_value
value.copy< ElementPtr > (v);
break;
case 151: // "boolean"
case 152: // "boolean"
value.copy< bool > (v);
break;
case 150: // "floating point"
case 151: // "floating point"
value.copy< double > (v);
break;
case 149: // "integer"
case 150: // "integer"
value.copy< int64_t > (v);
break;
case 148: // "constant string"
case 149: // "constant string"
value.copy< std::string > (v);
break;
@ -1660,30 +1665,30 @@ namespace isc { namespace dhcp {
// Type destructor.
switch (yytype)
{
case 167: // value
case 171: // map_value
case 209: // socket_type
case 212: // outbound_interface_value
case 222: // db_type
case 299: // hr_mode
case 445: // ncr_protocol_value
case 453: // replace_client_name_value
case 168: // value
case 172: // map_value
case 210: // socket_type
case 213: // outbound_interface_value
case 229: // db_type
case 306: // hr_mode
case 452: // ncr_protocol_value
case 460: // replace_client_name_value
value.template destroy< ElementPtr > ();
break;
case 151: // "boolean"
case 152: // "boolean"
value.template destroy< bool > ();
break;
case 150: // "floating point"
case 151: // "floating point"
value.template destroy< double > ();
break;
case 149: // "integer"
case 150: // "integer"
value.template destroy< int64_t > ();
break;
case 148: // "constant string"
case 149: // "constant string"
value.template destroy< std::string > ();
break;
@ -1710,30 +1715,30 @@ namespace isc { namespace dhcp {
super_type::move(s);
switch (this->type_get ())
{
case 167: // value
case 171: // map_value
case 209: // socket_type
case 212: // outbound_interface_value
case 222: // db_type
case 299: // hr_mode
case 445: // ncr_protocol_value
case 453: // replace_client_name_value
case 168: // value
case 172: // map_value
case 210: // socket_type
case 213: // outbound_interface_value
case 229: // db_type
case 306: // hr_mode
case 452: // ncr_protocol_value
case 460: // replace_client_name_value
value.move< ElementPtr > (s.value);
break;
case 151: // "boolean"
case 152: // "boolean"
value.move< bool > (s.value);
break;
case 150: // "floating point"
case 151: // "floating point"
value.move< double > (s.value);
break;
case 149: // "integer"
case 150: // "integer"
value.move< int64_t > (s.value);
break;
case 148: // "constant string"
case 149: // "constant string"
value.move< std::string > (s.value);
break;
@ -1807,7 +1812,7 @@ namespace isc { namespace dhcp {
375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
405, 406
405, 406, 407
};
return static_cast<token_type> (yytoken_number_[type]);
}
@ -1962,6 +1967,12 @@ namespace isc { namespace dhcp {
return symbol_type (token::TOKEN_HOSTS_DATABASE, l);
}
Dhcp4Parser::symbol_type
Dhcp4Parser::make_HOSTS_DATABASES (const location_type& l)
{
return symbol_type (token::TOKEN_HOSTS_DATABASES, l);
}
Dhcp4Parser::symbol_type
Dhcp4Parser::make_TYPE (const location_type& l)
{
@ -2715,7 +2726,7 @@ namespace isc { namespace dhcp {
#line 14 "dhcp4_parser.yy" // lalr1.cc:377
} } // isc::dhcp
#line 2719 "dhcp4_parser.h" // lalr1.cc:377
#line 2730 "dhcp4_parser.h" // lalr1.cc:377

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2016-2018 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
@ -68,6 +68,7 @@ using namespace std;
LEASE_DATABASE "lease-database"
HOSTS_DATABASE "hosts-database"
HOSTS_DATABASES "hosts-databases"
TYPE "type"
MEMFILE "memfile"
MYSQL "mysql"
@ -421,6 +422,7 @@ global_param: valid_lifetime
| interfaces_config
| lease_database
| hosts_database
| hosts_databases
| host_reservation_identifiers
| client_classes
| option_def_list
@ -568,6 +570,34 @@ hosts_database: HOSTS_DATABASE {
ctx.leave();
};
hosts_databases: HOSTS_DATABASES {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("hosts-databases", l);
ctx.stack_.push_back(l);
ctx.enter(ctx.HOSTS_DATABASE);
} COLON LSQUARE_BRACKET database_list RSQUARE_BRACKET {
ctx.stack_.pop_back();
ctx.leave();
};
database_list: %empty
| not_empty_database_list
;
not_empty_database_list: database
| not_empty_database_list COMMA database
;
database: LCURLY_BRACKET {
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} database_map_params RCURLY_BRACKET {
// The type parameter is required
ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
database_map_params: database_map_param
| database_map_params COMMA database_map_param
;

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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
@ -412,19 +412,28 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
// Please move at the end when migration will be finished.
if (config_pair.first == "lease-database") {
DbAccessParser parser(DbAccessParser::LEASE_DB);
DbAccessParser parser(CfgDbAccess::LEASE_DB);
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
}
if (config_pair.first == "hosts-database") {
DbAccessParser parser(DbAccessParser::HOSTS_DB);
DbAccessParser parser(CfgDbAccess::HOSTS_DB);
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
}
if (config_pair.first == "hosts-databases") {
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
for (size_t i = 0; i < config_pair.second->size(); ++i) {
DbAccessParser parser(CfgDbAccess::HOSTS_DB + i);
parser.parse(cfg_db_access, config_pair.second->get(i));
}
continue;
}
if (config_pair.first == "subnet4") {
SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
Subnets4ListConfigParser subnets_parser;

View File

@ -1,4 +1,4 @@
// Generated 201801182315
// Generated 201802120036
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 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
@ -223,7 +223,7 @@ public:
/// Used while parsing Dhcp4/lease-database structures.
LEASE_DATABASE,
/// Used while parsing Dhcp4/hosts-database structures.
/// Used while parsing Dhcp4/hosts-database[s] structures.
HOSTS_DATABASE,
/// Used while parsing Dhcp4/*-database/type.

View File

@ -1,4 +1,4 @@
// Generated 201801182315
// Generated 201802120036
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@ -1,4 +1,4 @@
// Generated 201801182315
// Generated 201802120036
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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
@ -131,6 +131,28 @@ const char* PARSER_CONFIGS[] = {
" } ]"
"}",
// Configuration 4: two host databases
"{"
" \"interfaces-config\": {"
" \"interfaces\": [\"*\" ]"
" },"
" \"valid-lifetime\": 4000,"
" \"rebind-timer\": 2000,"
" \"renew-timer\": 1000,"
" \"hosts-databases\": [ {"
" \"type\": \"mysql\","
" \"name\": \"keatest1\","
" \"user\": \"keatest\","
" \"password\": \"keatest\""
" },{"
" \"type\": \"mysql\","
" \"name\": \"keatest2\","
" \"user\": \"keatest\","
" \"password\": \"keatest\""
" }"
" ]"
"}",
// Last Configuration for comments
"{"
" \"comment\": \"A DHCPv4 server\","
@ -5757,10 +5779,28 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) {
EXPECT_TRUE(classes.empty());
}
// This test checks multiple host data sources.
TEST_F(Dhcp4ParserTest, hostsDatabases) {
string config = PARSER_CONFIGS[4];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");
// Check database config
ConstCfgDbAccessPtr cfgdb =
CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
ASSERT_TRUE(cfgdb);
const std::vector<std::string>& hal = cfgdb->getHostDbAccessStringList();
ASSERT_EQ(2, hal.size());
// Keywords are in alphabetical order
EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", hal[0]);
EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", hal[1]);
}
// This test checks comments. Please keep it last.
TEST_F(Dhcp4ParserTest, comments) {
string config = PARSER_CONFIGS[4];
string config = PARSER_CONFIGS[5];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018 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
@ -1719,6 +1719,30 @@ const char* EXTRACTED_CONFIGS[] = {
" }\n",
// CONFIGURATION 60
"{\n"
" \"hosts-databases\": [\n"
" {\n"
" \"name\": \"keatest1\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" },\n"
" {\n"
" \"name\": \"keatest2\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" }\n"
" ],\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ \"*\" ],\n"
" \"re-detect\": false\n"
" },\n"
" \"rebind-timer\": 2000,\n"
" \"renew-timer\": 1000,\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 61
"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
" \"client-classes\": [\n"
" {\n"
@ -6683,6 +6707,63 @@ const char* UNPARSED_CONFIGS[] = {
" }\n",
// CONFIGURATION 60
"{\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"always-include-fqdn\": false,\n"
" \"enable-updates\": false,\n"
" \"generated-prefix\": \"myhost\",\n"
" \"max-queue-size\": 1024,\n"
" \"ncr-format\": \"JSON\",\n"
" \"ncr-protocol\": \"UDP\",\n"
" \"override-client-update\": false,\n"
" \"override-no-update\": false,\n"
" \"qualifying-suffix\": \"\",\n"
" \"replace-client-name\": \"never\",\n"
" \"sender-ip\": \"0.0.0.0\",\n"
" \"sender-port\": 0,\n"
" \"server-ip\": \"127.0.0.1\",\n"
" \"server-port\": 53001\n"
" },\n"
" \"dhcp4o6-port\": 0,\n"
" \"echo-client-id\": true,\n"
" \"expired-leases-processing\": {\n"
" \"flush-reclaimed-timer-wait-time\": 25,\n"
" \"hold-reclaimed-time\": 3600,\n"
" \"max-reclaim-leases\": 100,\n"
" \"max-reclaim-time\": 250,\n"
" \"reclaim-timer-wait-time\": 10,\n"
" \"unwarned-reclaim-cycles\": 5\n"
" },\n"
" \"hooks-libraries\": [ ],\n"
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
" \"hosts-databases\": [\n"
" {\n"
" \"name\": \"keatest1\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" },\n"
" {\n"
" \"name\": \"keatest2\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" }\n"
" ],\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ \"*\" ],\n"
" \"re-detect\": false\n"
" },\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"shared-networks\": [ ],\n"
" \"subnet4\": [ ]\n"
" }\n",
// CONFIGURATION 61
"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
" \"client-classes\": [\n"
" {\n"

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018 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
@ -124,7 +124,7 @@ outputFormatted(const std::string& config) {
}
}
};
} // namespace
namespace isc {
namespace dhcp {
@ -155,9 +155,9 @@ extractConfig(const std::string& config) {
++extract_count;
}
};
};
};
} // namespace test
} // namespace dhcp
} // namespace isc
namespace {

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2016-2018 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
@ -457,6 +457,15 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"hosts-databases\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
return isc::dhcp::Dhcp6Parser::make_HOSTS_DATABASES(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("hosts-databases", driver.loc_);
}
}
\"readonly\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::HOSTS_DATABASE:

File diff suppressed because it is too large Load Diff

View File

@ -360,147 +360,148 @@ namespace isc { namespace dhcp {
TOKEN_RE_DETECT = 268,
TOKEN_LEASE_DATABASE = 269,
TOKEN_HOSTS_DATABASE = 270,
TOKEN_TYPE = 271,
TOKEN_MEMFILE = 272,
TOKEN_MYSQL = 273,
TOKEN_POSTGRESQL = 274,
TOKEN_CQL = 275,
TOKEN_USER = 276,
TOKEN_PASSWORD = 277,
TOKEN_HOST = 278,
TOKEN_PORT = 279,
TOKEN_PERSIST = 280,
TOKEN_LFC_INTERVAL = 281,
TOKEN_READONLY = 282,
TOKEN_CONNECT_TIMEOUT = 283,
TOKEN_CONTACT_POINTS = 284,
TOKEN_KEYSPACE = 285,
TOKEN_PREFERRED_LIFETIME = 286,
TOKEN_VALID_LIFETIME = 287,
TOKEN_RENEW_TIMER = 288,
TOKEN_REBIND_TIMER = 289,
TOKEN_DECLINE_PROBATION_PERIOD = 290,
TOKEN_SUBNET6 = 291,
TOKEN_OPTION_DEF = 292,
TOKEN_OPTION_DATA = 293,
TOKEN_NAME = 294,
TOKEN_DATA = 295,
TOKEN_CODE = 296,
TOKEN_SPACE = 297,
TOKEN_CSV_FORMAT = 298,
TOKEN_ALWAYS_SEND = 299,
TOKEN_RECORD_TYPES = 300,
TOKEN_ENCAPSULATE = 301,
TOKEN_ARRAY = 302,
TOKEN_POOLS = 303,
TOKEN_POOL = 304,
TOKEN_PD_POOLS = 305,
TOKEN_PREFIX = 306,
TOKEN_PREFIX_LEN = 307,
TOKEN_EXCLUDED_PREFIX = 308,
TOKEN_EXCLUDED_PREFIX_LEN = 309,
TOKEN_DELEGATED_LEN = 310,
TOKEN_USER_CONTEXT = 311,
TOKEN_COMMENT = 312,
TOKEN_SUBNET = 313,
TOKEN_INTERFACE = 314,
TOKEN_INTERFACE_ID = 315,
TOKEN_ID = 316,
TOKEN_RAPID_COMMIT = 317,
TOKEN_RESERVATION_MODE = 318,
TOKEN_DISABLED = 319,
TOKEN_OUT_OF_POOL = 320,
TOKEN_ALL = 321,
TOKEN_SHARED_NETWORKS = 322,
TOKEN_MAC_SOURCES = 323,
TOKEN_RELAY_SUPPLIED_OPTIONS = 324,
TOKEN_HOST_RESERVATION_IDENTIFIERS = 325,
TOKEN_CLIENT_CLASSES = 326,
TOKEN_TEST = 327,
TOKEN_CLIENT_CLASS = 328,
TOKEN_RESERVATIONS = 329,
TOKEN_IP_ADDRESSES = 330,
TOKEN_PREFIXES = 331,
TOKEN_DUID = 332,
TOKEN_HW_ADDRESS = 333,
TOKEN_HOSTNAME = 334,
TOKEN_FLEX_ID = 335,
TOKEN_RELAY = 336,
TOKEN_IP_ADDRESS = 337,
TOKEN_HOOKS_LIBRARIES = 338,
TOKEN_LIBRARY = 339,
TOKEN_PARAMETERS = 340,
TOKEN_EXPIRED_LEASES_PROCESSING = 341,
TOKEN_RECLAIM_TIMER_WAIT_TIME = 342,
TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 343,
TOKEN_HOLD_RECLAIMED_TIME = 344,
TOKEN_MAX_RECLAIM_LEASES = 345,
TOKEN_MAX_RECLAIM_TIME = 346,
TOKEN_UNWARNED_RECLAIM_CYCLES = 347,
TOKEN_SERVER_ID = 348,
TOKEN_LLT = 349,
TOKEN_EN = 350,
TOKEN_LL = 351,
TOKEN_IDENTIFIER = 352,
TOKEN_HTYPE = 353,
TOKEN_TIME = 354,
TOKEN_ENTERPRISE_ID = 355,
TOKEN_DHCP4O6_PORT = 356,
TOKEN_CONTROL_SOCKET = 357,
TOKEN_SOCKET_TYPE = 358,
TOKEN_SOCKET_NAME = 359,
TOKEN_DHCP_DDNS = 360,
TOKEN_ENABLE_UPDATES = 361,
TOKEN_QUALIFYING_SUFFIX = 362,
TOKEN_SERVER_IP = 363,
TOKEN_SERVER_PORT = 364,
TOKEN_SENDER_IP = 365,
TOKEN_SENDER_PORT = 366,
TOKEN_MAX_QUEUE_SIZE = 367,
TOKEN_NCR_PROTOCOL = 368,
TOKEN_NCR_FORMAT = 369,
TOKEN_ALWAYS_INCLUDE_FQDN = 370,
TOKEN_OVERRIDE_NO_UPDATE = 371,
TOKEN_OVERRIDE_CLIENT_UPDATE = 372,
TOKEN_REPLACE_CLIENT_NAME = 373,
TOKEN_GENERATED_PREFIX = 374,
TOKEN_UDP = 375,
TOKEN_TCP = 376,
TOKEN_JSON = 377,
TOKEN_WHEN_PRESENT = 378,
TOKEN_NEVER = 379,
TOKEN_ALWAYS = 380,
TOKEN_WHEN_NOT_PRESENT = 381,
TOKEN_LOGGING = 382,
TOKEN_LOGGERS = 383,
TOKEN_OUTPUT_OPTIONS = 384,
TOKEN_OUTPUT = 385,
TOKEN_DEBUGLEVEL = 386,
TOKEN_SEVERITY = 387,
TOKEN_FLUSH = 388,
TOKEN_MAXSIZE = 389,
TOKEN_MAXVER = 390,
TOKEN_DHCP4 = 391,
TOKEN_DHCPDDNS = 392,
TOKEN_CONTROL_AGENT = 393,
TOKEN_TOPLEVEL_JSON = 394,
TOKEN_TOPLEVEL_DHCP6 = 395,
TOKEN_SUB_DHCP6 = 396,
TOKEN_SUB_INTERFACES6 = 397,
TOKEN_SUB_SUBNET6 = 398,
TOKEN_SUB_POOL6 = 399,
TOKEN_SUB_PD_POOL = 400,
TOKEN_SUB_RESERVATION = 401,
TOKEN_SUB_OPTION_DEFS = 402,
TOKEN_SUB_OPTION_DEF = 403,
TOKEN_SUB_OPTION_DATA = 404,
TOKEN_SUB_HOOKS_LIBRARY = 405,
TOKEN_SUB_DHCP_DDNS = 406,
TOKEN_SUB_LOGGING = 407,
TOKEN_STRING = 408,
TOKEN_INTEGER = 409,
TOKEN_FLOAT = 410,
TOKEN_BOOLEAN = 411
TOKEN_HOSTS_DATABASES = 271,
TOKEN_TYPE = 272,
TOKEN_MEMFILE = 273,
TOKEN_MYSQL = 274,
TOKEN_POSTGRESQL = 275,
TOKEN_CQL = 276,
TOKEN_USER = 277,
TOKEN_PASSWORD = 278,
TOKEN_HOST = 279,
TOKEN_PORT = 280,
TOKEN_PERSIST = 281,
TOKEN_LFC_INTERVAL = 282,
TOKEN_READONLY = 283,
TOKEN_CONNECT_TIMEOUT = 284,
TOKEN_CONTACT_POINTS = 285,
TOKEN_KEYSPACE = 286,
TOKEN_PREFERRED_LIFETIME = 287,
TOKEN_VALID_LIFETIME = 288,
TOKEN_RENEW_TIMER = 289,
TOKEN_REBIND_TIMER = 290,
TOKEN_DECLINE_PROBATION_PERIOD = 291,
TOKEN_SUBNET6 = 292,
TOKEN_OPTION_DEF = 293,
TOKEN_OPTION_DATA = 294,
TOKEN_NAME = 295,
TOKEN_DATA = 296,
TOKEN_CODE = 297,
TOKEN_SPACE = 298,
TOKEN_CSV_FORMAT = 299,
TOKEN_ALWAYS_SEND = 300,
TOKEN_RECORD_TYPES = 301,
TOKEN_ENCAPSULATE = 302,
TOKEN_ARRAY = 303,
TOKEN_POOLS = 304,
TOKEN_POOL = 305,
TOKEN_PD_POOLS = 306,
TOKEN_PREFIX = 307,
TOKEN_PREFIX_LEN = 308,
TOKEN_EXCLUDED_PREFIX = 309,
TOKEN_EXCLUDED_PREFIX_LEN = 310,
TOKEN_DELEGATED_LEN = 311,
TOKEN_USER_CONTEXT = 312,
TOKEN_COMMENT = 313,
TOKEN_SUBNET = 314,
TOKEN_INTERFACE = 315,
TOKEN_INTERFACE_ID = 316,
TOKEN_ID = 317,
TOKEN_RAPID_COMMIT = 318,
TOKEN_RESERVATION_MODE = 319,
TOKEN_DISABLED = 320,
TOKEN_OUT_OF_POOL = 321,
TOKEN_ALL = 322,
TOKEN_SHARED_NETWORKS = 323,
TOKEN_MAC_SOURCES = 324,
TOKEN_RELAY_SUPPLIED_OPTIONS = 325,
TOKEN_HOST_RESERVATION_IDENTIFIERS = 326,
TOKEN_CLIENT_CLASSES = 327,
TOKEN_TEST = 328,
TOKEN_CLIENT_CLASS = 329,
TOKEN_RESERVATIONS = 330,
TOKEN_IP_ADDRESSES = 331,
TOKEN_PREFIXES = 332,
TOKEN_DUID = 333,
TOKEN_HW_ADDRESS = 334,
TOKEN_HOSTNAME = 335,
TOKEN_FLEX_ID = 336,
TOKEN_RELAY = 337,
TOKEN_IP_ADDRESS = 338,
TOKEN_HOOKS_LIBRARIES = 339,
TOKEN_LIBRARY = 340,
TOKEN_PARAMETERS = 341,
TOKEN_EXPIRED_LEASES_PROCESSING = 342,
TOKEN_RECLAIM_TIMER_WAIT_TIME = 343,
TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 344,
TOKEN_HOLD_RECLAIMED_TIME = 345,
TOKEN_MAX_RECLAIM_LEASES = 346,
TOKEN_MAX_RECLAIM_TIME = 347,
TOKEN_UNWARNED_RECLAIM_CYCLES = 348,
TOKEN_SERVER_ID = 349,
TOKEN_LLT = 350,
TOKEN_EN = 351,
TOKEN_LL = 352,
TOKEN_IDENTIFIER = 353,
TOKEN_HTYPE = 354,
TOKEN_TIME = 355,
TOKEN_ENTERPRISE_ID = 356,
TOKEN_DHCP4O6_PORT = 357,
TOKEN_CONTROL_SOCKET = 358,
TOKEN_SOCKET_TYPE = 359,
TOKEN_SOCKET_NAME = 360,
TOKEN_DHCP_DDNS = 361,
TOKEN_ENABLE_UPDATES = 362,
TOKEN_QUALIFYING_SUFFIX = 363,
TOKEN_SERVER_IP = 364,
TOKEN_SERVER_PORT = 365,
TOKEN_SENDER_IP = 366,
TOKEN_SENDER_PORT = 367,
TOKEN_MAX_QUEUE_SIZE = 368,
TOKEN_NCR_PROTOCOL = 369,
TOKEN_NCR_FORMAT = 370,
TOKEN_ALWAYS_INCLUDE_FQDN = 371,
TOKEN_OVERRIDE_NO_UPDATE = 372,
TOKEN_OVERRIDE_CLIENT_UPDATE = 373,
TOKEN_REPLACE_CLIENT_NAME = 374,
TOKEN_GENERATED_PREFIX = 375,
TOKEN_UDP = 376,
TOKEN_TCP = 377,
TOKEN_JSON = 378,
TOKEN_WHEN_PRESENT = 379,
TOKEN_NEVER = 380,
TOKEN_ALWAYS = 381,
TOKEN_WHEN_NOT_PRESENT = 382,
TOKEN_LOGGING = 383,
TOKEN_LOGGERS = 384,
TOKEN_OUTPUT_OPTIONS = 385,
TOKEN_OUTPUT = 386,
TOKEN_DEBUGLEVEL = 387,
TOKEN_SEVERITY = 388,
TOKEN_FLUSH = 389,
TOKEN_MAXSIZE = 390,
TOKEN_MAXVER = 391,
TOKEN_DHCP4 = 392,
TOKEN_DHCPDDNS = 393,
TOKEN_CONTROL_AGENT = 394,
TOKEN_TOPLEVEL_JSON = 395,
TOKEN_TOPLEVEL_DHCP6 = 396,
TOKEN_SUB_DHCP6 = 397,
TOKEN_SUB_INTERFACES6 = 398,
TOKEN_SUB_SUBNET6 = 399,
TOKEN_SUB_POOL6 = 400,
TOKEN_SUB_PD_POOL = 401,
TOKEN_SUB_RESERVATION = 402,
TOKEN_SUB_OPTION_DEFS = 403,
TOKEN_SUB_OPTION_DEF = 404,
TOKEN_SUB_OPTION_DATA = 405,
TOKEN_SUB_HOOKS_LIBRARY = 406,
TOKEN_SUB_DHCP_DDNS = 407,
TOKEN_SUB_LOGGING = 408,
TOKEN_STRING = 409,
TOKEN_INTEGER = 410,
TOKEN_FLOAT = 411,
TOKEN_BOOLEAN = 412
};
};
@ -671,6 +672,10 @@ namespace isc { namespace dhcp {
symbol_type
make_HOSTS_DATABASE (const location_type& l);
static inline
symbol_type
make_HOSTS_DATABASES (const location_type& l);
static inline
symbol_type
make_TYPE (const location_type& l);
@ -1440,12 +1445,12 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 931, ///< Last index in yytable_.
yynnts_ = 352, ///< Number of nonterminal symbols.
yylast_ = 933, ///< Last index in yytable_.
yynnts_ = 358, ///< Number of nonterminal symbols.
yyfinal_ = 30, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 157 ///< Number of tokens.
yyntokens_ = 158 ///< Number of tokens.
};
@ -1503,9 +1508,9 @@ namespace isc { namespace dhcp {
125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
155, 156
155, 156, 157
};
const unsigned int user_token_number_max_ = 411;
const unsigned int user_token_number_max_ = 412;
const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_)
@ -1538,29 +1543,29 @@ namespace isc { namespace dhcp {
{
switch (other.type_get ())
{
case 173: // value
case 177: // map_value
case 221: // db_type
case 297: // hr_mode
case 431: // duid_type
case 464: // ncr_protocol_value
case 472: // replace_client_name_value
case 174: // value
case 178: // map_value
case 228: // db_type
case 304: // hr_mode
case 438: // duid_type
case 471: // ncr_protocol_value
case 479: // replace_client_name_value
value.copy< ElementPtr > (other.value);
break;
case 156: // "boolean"
case 157: // "boolean"
value.copy< bool > (other.value);
break;
case 155: // "floating point"
case 156: // "floating point"
value.copy< double > (other.value);
break;
case 154: // "integer"
case 155: // "integer"
value.copy< int64_t > (other.value);
break;
case 153: // "constant string"
case 154: // "constant string"
value.copy< std::string > (other.value);
break;
@ -1581,29 +1586,29 @@ namespace isc { namespace dhcp {
(void) v;
switch (this->type_get ())
{
case 173: // value
case 177: // map_value
case 221: // db_type
case 297: // hr_mode
case 431: // duid_type
case 464: // ncr_protocol_value
case 472: // replace_client_name_value
case 174: // value
case 178: // map_value
case 228: // db_type
case 304: // hr_mode
case 438: // duid_type
case 471: // ncr_protocol_value
case 479: // replace_client_name_value
value.copy< ElementPtr > (v);
break;
case 156: // "boolean"
case 157: // "boolean"
value.copy< bool > (v);
break;
case 155: // "floating point"
case 156: // "floating point"
value.copy< double > (v);
break;
case 154: // "integer"
case 155: // "integer"
value.copy< int64_t > (v);
break;
case 153: // "constant string"
case 154: // "constant string"
value.copy< std::string > (v);
break;
@ -1683,29 +1688,29 @@ namespace isc { namespace dhcp {
// Type destructor.
switch (yytype)
{
case 173: // value
case 177: // map_value
case 221: // db_type
case 297: // hr_mode
case 431: // duid_type
case 464: // ncr_protocol_value
case 472: // replace_client_name_value
case 174: // value
case 178: // map_value
case 228: // db_type
case 304: // hr_mode
case 438: // duid_type
case 471: // ncr_protocol_value
case 479: // replace_client_name_value
value.template destroy< ElementPtr > ();
break;
case 156: // "boolean"
case 157: // "boolean"
value.template destroy< bool > ();
break;
case 155: // "floating point"
case 156: // "floating point"
value.template destroy< double > ();
break;
case 154: // "integer"
case 155: // "integer"
value.template destroy< int64_t > ();
break;
case 153: // "constant string"
case 154: // "constant string"
value.template destroy< std::string > ();
break;
@ -1732,29 +1737,29 @@ namespace isc { namespace dhcp {
super_type::move(s);
switch (this->type_get ())
{
case 173: // value
case 177: // map_value
case 221: // db_type
case 297: // hr_mode
case 431: // duid_type
case 464: // ncr_protocol_value
case 472: // replace_client_name_value
case 174: // value
case 178: // map_value
case 228: // db_type
case 304: // hr_mode
case 438: // duid_type
case 471: // ncr_protocol_value
case 479: // replace_client_name_value
value.move< ElementPtr > (s.value);
break;
case 156: // "boolean"
case 157: // "boolean"
value.move< bool > (s.value);
break;
case 155: // "floating point"
case 156: // "floating point"
value.move< double > (s.value);
break;
case 154: // "integer"
case 155: // "integer"
value.move< int64_t > (s.value);
break;
case 153: // "constant string"
case 154: // "constant string"
value.move< std::string > (s.value);
break;
@ -1828,7 +1833,7 @@ namespace isc { namespace dhcp {
375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
405, 406, 407, 408, 409, 410, 411
405, 406, 407, 408, 409, 410, 411, 412
};
return static_cast<token_type> (yytoken_number_[type]);
}
@ -1917,6 +1922,12 @@ namespace isc { namespace dhcp {
return symbol_type (token::TOKEN_HOSTS_DATABASE, l);
}
Dhcp6Parser::symbol_type
Dhcp6Parser::make_HOSTS_DATABASES (const location_type& l)
{
return symbol_type (token::TOKEN_HOSTS_DATABASES, l);
}
Dhcp6Parser::symbol_type
Dhcp6Parser::make_TYPE (const location_type& l)
{
@ -2766,7 +2777,7 @@ namespace isc { namespace dhcp {
#line 14 "dhcp6_parser.yy" // lalr1.cc:377
} } // isc::dhcp
#line 2770 "dhcp6_parser.h" // lalr1.cc:377
#line 2781 "dhcp6_parser.h" // lalr1.cc:377

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2016-2018 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
@ -56,6 +56,7 @@ using namespace std;
LEASE_DATABASE "lease-database"
HOSTS_DATABASE "hosts-database"
HOSTS_DATABASES "hosts-databases"
TYPE "type"
MEMFILE "memfile"
MYSQL "mysql"
@ -425,6 +426,7 @@ global_param: preferred_lifetime
| interfaces_config
| lease_database
| hosts_database
| hosts_databases
| mac_sources
| relay_supplied_options
| host_reservation_identifiers
@ -538,6 +540,34 @@ hosts_database: HOSTS_DATABASE {
ctx.leave();
};
hosts_databases: HOSTS_DATABASES {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("hosts-databases", l);
ctx.stack_.push_back(l);
ctx.enter(ctx.HOSTS_DATABASE);
} COLON LSQUARE_BRACKET database_list RSQUARE_BRACKET {
ctx.stack_.pop_back();
ctx.leave();
};
database_list: %empty
| not_empty_database_list
;
not_empty_database_list: database
| not_empty_database_list COMMA database
;
database: LCURLY_BRACKET {
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} database_map_params RCURLY_BRACKET {
// The type parameter is required
ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
database_map_params: database_map_param
| database_map_params COMMA database_map_param
;

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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
@ -525,19 +525,29 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
// Please move at the end when migration will be finished.
if (config_pair.first == "lease-database") {
DbAccessParser parser(DbAccessParser::LEASE_DB);
DbAccessParser parser(CfgDbAccess::LEASE_DB);
CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
}
if (config_pair.first == "hosts-database") {
DbAccessParser parser(DbAccessParser::HOSTS_DB);
DbAccessParser parser(CfgDbAccess::HOSTS_DB);
CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
}
// For now only support empty or singleton, ignoring extra entries.
if (config_pair.first == "hosts-databases") {
CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
for (size_t i = 0; i < config_pair.second->size(); ++i) {
DbAccessParser parser(CfgDbAccess::HOSTS_DB + i);
parser.parse(cfg_db_access, config_pair.second->get(i));
}
continue;
}
if (config_pair.first == "subnet6") {
Subnets6ListConfigParser subnets_parser;
// parse() returns number of subnets parsed. We may log it one day.

View File

@ -1,4 +1,4 @@
// Generated 201801182315
// Generated 201802120036
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 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
@ -221,7 +221,7 @@ public:
/// Used while parsing Dhcp6/lease-database structures.
LEASE_DATABASE,
/// Used while parsing Dhcp6/hosts-database structures.
/// Used while parsing Dhcp6/hosts-database[s] structures.
HOSTS_DATABASE,
/// Used while parsing Dhcp6/*-database/type.

View File

@ -1,4 +1,4 @@
// Generated 201801182315
// Generated 201802120036
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@ -1,4 +1,4 @@
// Generated 201801182315
// Generated 201802120036
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++

View File

@ -208,6 +208,29 @@ const char* PARSER_CONFIGS[] = {
" } ]"
"}",
// Configuration 7: two host databases
"{"
" \"interfaces-config\": {"
" \"interfaces\": [\"*\" ]"
" },"
" \"valid-lifetime\": 4000,"
" \"preferred-lifetime\": 3000,"
" \"rebind-timer\": 2000,"
" \"renew-timer\": 1000,"
" \"hosts-databases\": [ {"
" \"type\": \"mysql\","
" \"name\": \"keatest1\","
" \"user\": \"keatest\","
" \"password\": \"keatest\""
" },{"
" \"type\": \"mysql\","
" \"name\": \"keatest2\","
" \"user\": \"keatest\","
" \"password\": \"keatest\""
" }"
" ]"
"}",
// Last configuration for comments
"{"
" \"comment\": \"A DHCPv6 server\","
@ -6314,10 +6337,28 @@ TEST_F(Dhcp6ParserTest, sharedNetworksRapidCommitMix) {
"shared-network or the shared-network itself used rapid-commit true");
}
// This test checks multiple host data sources.
TEST_F(Dhcp6ParserTest, hostsDatabases) {
string config = PARSER_CONFIGS[7];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");
// Check database config
ConstCfgDbAccessPtr cfgdb =
CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
ASSERT_TRUE(cfgdb);
const std::vector<std::string>& hal = cfgdb->getHostDbAccessStringList();
ASSERT_EQ(2, hal.size());
// Keywords are in alphabetical order
EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", hal[0]);
EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", hal[1]);
}
// This test checks comments. Please keep it last.
TEST_F(Dhcp6ParserTest, comments) {
string config = PARSER_CONFIGS[7];
string config = PARSER_CONFIGS[8];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");

View File

@ -1584,6 +1584,31 @@ const char* EXTRACTED_CONFIGS[] = {
" }\n",
// CONFIGURATION 53
"{\n"
" \"hosts-databases\": [\n"
" {\n"
" \"name\": \"keatest1\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" },\n"
" {\n"
" \"name\": \"keatest2\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" }\n"
" ],\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ \"*\" ],\n"
" \"re-detect\": false\n"
" },\n"
" \"preferred-lifetime\": 3000,\n"
" \"rebind-timer\": 2000,\n"
" \"renew-timer\": 1000,\n"
" \"valid-lifetime\": 4000\n"
" }\n",
// CONFIGURATION 54
"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
" \"client-classes\": [\n"
" {\n"
@ -6240,6 +6265,72 @@ const char* UNPARSED_CONFIGS[] = {
" }\n",
// CONFIGURATION 53
"{\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"always-include-fqdn\": false,\n"
" \"enable-updates\": false,\n"
" \"generated-prefix\": \"myhost\",\n"
" \"max-queue-size\": 1024,\n"
" \"ncr-format\": \"JSON\",\n"
" \"ncr-protocol\": \"UDP\",\n"
" \"override-client-update\": false,\n"
" \"override-no-update\": false,\n"
" \"qualifying-suffix\": \"\",\n"
" \"replace-client-name\": \"never\",\n"
" \"sender-ip\": \"0.0.0.0\",\n"
" \"sender-port\": 0,\n"
" \"server-ip\": \"127.0.0.1\",\n"
" \"server-port\": 53001\n"
" },\n"
" \"dhcp4o6-port\": 0,\n"
" \"expired-leases-processing\": {\n"
" \"flush-reclaimed-timer-wait-time\": 25,\n"
" \"hold-reclaimed-time\": 3600,\n"
" \"max-reclaim-leases\": 100,\n"
" \"max-reclaim-time\": 250,\n"
" \"reclaim-timer-wait-time\": 10,\n"
" \"unwarned-reclaim-cycles\": 5\n"
" },\n"
" \"hooks-libraries\": [ ],\n"
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\" ],\n"
" \"hosts-databases\": [\n"
" {\n"
" \"name\": \"keatest1\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" },\n"
" {\n"
" \"name\": \"keatest2\",\n"
" \"password\": \"keatest\",\n"
" \"type\": \"mysql\",\n"
" \"user\": \"keatest\"\n"
" }\n"
" ],\n"
" \"interfaces-config\": {\n"
" \"interfaces\": [ \"*\" ],\n"
" \"re-detect\": false\n"
" },\n"
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"mac-sources\": [ \"any\" ],\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"relay-supplied-options\": [ \"65\" ],\n"
" \"server-id\": {\n"
" \"enterprise-id\": 0,\n"
" \"htype\": 0,\n"
" \"identifier\": \"\",\n"
" \"persist\": true,\n"
" \"time\": 0,\n"
" \"type\": \"LLT\"\n"
" },\n"
" \"shared-networks\": [ ],\n"
" \"subnet6\": [ ]\n"
" }\n",
// CONFIGURATION 54
"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
" \"client-classes\": [\n"
" {\n"
@ -6459,7 +6550,7 @@ outputFormatted(const std::string& config) {
}
}
}
} // namespace
namespace isc {
namespace dhcp {

View File

@ -125,7 +125,7 @@ outputFormatted(const std::string& config) {
}
}
};
} // namespace
namespace isc {
namespace dhcp {
@ -156,9 +156,9 @@ extractConfig(const std::string& config) {
++extract_count;
}
};
};
};
} // namespace test
} // namespace dhcp
} // namespace isc
namespace {

View File

@ -89,6 +89,7 @@ libkea_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libkea_dhcpsrv_la_SOURCES += alloc_engine_log.cc alloc_engine_log.h
libkea_dhcpsrv_la_SOURCES += assignable_network.h
libkea_dhcpsrv_la_SOURCES += base_host_data_source.h
libkea_dhcpsrv_la_SOURCES += cache_host_data_source.h
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
libkea_dhcpsrv_la_SOURCES += cfg_4o6.cc cfg_4o6.h
libkea_dhcpsrv_la_SOURCES += cfg_db_access.cc cfg_db_access.h
@ -248,6 +249,7 @@ libkea_dhcpsrv_include_HEADERS = \
alloc_engine_log.h \
assignable_network.h \
base_host_data_source.h \
cache_host_data_source.h \
callout_handle_store.h \
cfg_4o6.h \
cfg_db_access.h \

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -14,6 +14,8 @@
#include <exceptions/exceptions.h>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace isc {
namespace dhcp {
@ -245,7 +247,8 @@ public:
/// is identified by HW address, another one by DUID.
///
/// @param host Pointer to the new @c Host object being added.
virtual void add(const HostPtr& host) = 0;
/// @return true if addition was successful.
virtual bool add(const HostPtr& host) = 0;
/// @brief Attempts to delete a host by (subnet-id, address)
///
@ -310,6 +313,9 @@ public:
/// @brief HostDataSource pointer
typedef boost::shared_ptr<BaseHostDataSource> HostDataSourcePtr;
/// @brief HostDataSource list
typedef std::vector<HostDataSourcePtr> HostDataSourceList;
}
}

View File

@ -0,0 +1,64 @@
// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the End User License
// Agreement. See COPYING file in the premium/ directory.
#ifndef CACHE_HOST_DATA_SOURCE_H
#define CACHE_HOST_DATA_SOURCE_H
#include <dhcpsrv/base_host_data_source.h>
namespace isc {
namespace dhcp {
/// @brief Abstract interface extending base simple data source for host
/// reservations to host cache.
/// Only the insert() method is required to use the cache.
class CacheHostDataSource : public virtual BaseHostDataSource {
public:
/// @brief Default destructor implementation.
virtual ~CacheHostDataSource() { }
/// @brief Insert a host into the cache.
///
/// Does the same than @c add() but with a different purpose.
///
/// @param host Pointer to the new @c Host object being inserted.
/// @param[in,out] overwrite -1 if accepting conflicts, 0 if removing
/// conflicting entries, set to the number of removed entries.
/// @return true when succeeded.
virtual bool insert(const ConstHostPtr& host, int& overwrite) = 0;
/// @brief Remove a host from the cache.
///
/// Does the same than @c del, @c del4 or @c del6 but with
/// a more uniform interface and a different purpose.
///
/// @param host Pointer to the existing @c Host object being removed.
/// @return true when found and removed.
virtual bool remove(const HostPtr& host) = 0;
/// @brief Flush entries.
///
/// @param count number of entries to remove, 0 means all.
virtual void flush(size_t count) = 0;
/// @brief Return the number of entries.
///
/// @return the current number of active entries in the cache.
virtual size_t size() const = 0;
/// @brief Return the maximum number of entries.
///
/// @return the maximum number of entries, 0 means unbound.
virtual size_t capacity() const = 0;
};
/// @brief CacheHostDataSource pointer.
typedef boost::shared_ptr<CacheHostDataSource> CacheHostDataSourcePtr;
} // end of namespace isc::dhcp
} // end of namespace isc
#endif // CACHE_HOST_DATA_SOURCE_H

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2018 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
@ -21,21 +21,31 @@ namespace isc {
namespace dhcp {
CfgDbAccess::CfgDbAccess()
: appended_parameters_(), lease_db_access_("type=memfile"),
host_db_access_() {
: appended_parameters_(), db_access_(2) {
db_access_[LEASE_DB] = "type=memfile";
}
std::string
CfgDbAccess::getLeaseDbAccessString() const {
return (getAccessString(lease_db_access_));
return (getAccessString(db_access_[LEASE_DB]));
}
std::string
CfgDbAccess::getHostDbAccessString() const {
return (getAccessString(host_db_access_));
return (getAccessString(db_access_[HOSTS_DB]));
}
std::vector<std::string>
CfgDbAccess::getHostDbAccessStringList() const {
std::vector<std::string> ret;
for (size_t idx = HOSTS_DB; idx < db_access_.size(); ++idx) {
if (!db_access_[idx].empty()) {
ret.push_back(getAccessString(db_access_[idx]));
}
}
return (ret);
}
void
CfgDbAccess::createManagers() const {
@ -44,10 +54,15 @@ CfgDbAccess::createManagers() const {
LeaseMgrFactory::create(getLeaseDbAccessString());
// Recreate host data source.
HostDataSourceFactory::destroy();
if (!host_db_access_.empty()) {
HostMgr::create(getHostDbAccessString());
HostMgr::create();
auto host_db_access_list = getHostDbAccessStringList();
for (auto it = host_db_access_list.begin();
it != host_db_access_list.end(); ++it) {
HostMgr::addSource(*it);
}
// Check for a host cache.
HostMgr::checkCacheSource(true);
}
std::string

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2018 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
@ -10,6 +10,7 @@
#include <cc/cfg_to_element.h>
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
namespace isc {
namespace dhcp {
@ -21,6 +22,9 @@ namespace dhcp {
/// passed to the @ref isc::dhcp::LeaseMgrFactory::create function.
class CfgDbAccess {
public:
/// @brief Specifies the database types
static const size_t LEASE_DB = 0;
static const size_t HOSTS_DB = 1;
/// @brief Constructor.
CfgDbAccess();
@ -44,7 +48,7 @@ public:
///
/// @param lease_db_access New lease database access string.
void setLeaseDbAccessString(const std::string& lease_db_access) {
lease_db_access_ = lease_db_access;
db_access_[LEASE_DB] = lease_db_access;
}
/// @brief Retrieves host database access string.
@ -57,10 +61,23 @@ public:
///
/// @param host_db_access New host database access string.
void setHostDbAccessString(const std::string& host_db_access) {
host_db_access_ = host_db_access;
db_access_[HOSTS_DB] = host_db_access;
}
/// @brief Creates instance of lease manager and host data source
/// @brief Retrieves host database access string.
///
/// @return Database access strings with additional parameters
/// specified with @ref CfgDbAccess::setAppendedParameters
std::vector<std::string> getHostDbAccessStringList() const;
/// @brief Pushes host database access string.
///
/// @param db_access New host database access string.
void pushHostDbAccessString(const std::string& db_access) {
db_access_.push_back(db_access);
}
/// @brief Creates instance of lease manager and host data sources
/// according to the configuration specified.
void createManagers() const;
@ -82,11 +99,8 @@ protected:
/// strings.
std::string appended_parameters_;
/// @brief Holds lease database access string.
std::string lease_db_access_;
/// @brief Holds host database access string.
std::string host_db_access_;
/// @brief Holds database access strings.
std::vector<std::string> db_access_;
};
@ -107,7 +121,7 @@ struct CfgLeaseDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
///
/// @result a pointer to a configuration
virtual isc::data::ElementPtr toElement() const {
return (CfgDbAccess::toElementDbAccessString(lease_db_access_));
return (CfgDbAccess::toElementDbAccessString(db_access_[LEASE_DB]));
}
};
@ -121,7 +135,15 @@ struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
///
/// @result a pointer to a configuration
virtual isc::data::ElementPtr toElement() const {
return (CfgDbAccess::toElementDbAccessString(host_db_access_));
isc::data::ElementPtr result = isc::data::Element::createList();
for (size_t idx = HOSTS_DB; idx < db_access_.size(); ++idx) {
isc::data::ElementPtr entry =
CfgDbAccess::toElementDbAccessString(db_access_[idx]);
if (entry->size() > 0) {
result->add(entry);
}
}
return (result);
}
};

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -549,7 +549,7 @@ CfgHosts::getHostInternal(const SubnetID& subnet_id, const bool subnet6,
return (host);
}
void
bool
CfgHosts::add(const HostPtr& host) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_ADD_HOST)
.arg(host ? host->toText() : "(no-host)");
@ -569,6 +569,8 @@ CfgHosts::add(const HostPtr& host) {
add4(host);
add6(host);
return (true);
}
void

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -318,9 +318,10 @@ public:
///
/// @param host Pointer to the new @c Host object being added.
///
/// @return always return true as additions are successful or throw.
/// @throw DuplicateHost If a host for a particular HW address or DUID
/// has already been added to the IPv4 or IPv6 subnet.
virtual void add(const HostPtr& host);
virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by address.
///

View File

@ -1782,11 +1782,13 @@ CqlHostDataSource::~CqlHostDataSource() {
delete impl_;
}
void
bool
CqlHostDataSource::add(const HostPtr& host) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_ADD);
impl_->add(host);
return (true);
}
ConstHostCollection

View File

@ -98,7 +98,8 @@ public:
/// Host, where one instance is identified by different identifier types.
///
/// @param host pointer to the new @ref Host being added.
virtual void add(const HostPtr& host) override;
/// @return true as addition is successful or throws.
virtual bool add(const HostPtr& host) override;
/// @brief Retrieves a single @ref Host connected to an IPv4 subnet.
///

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -92,7 +92,8 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len,
dhcp6_client_classes_(dhcp6_client_classes),
next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
server_host_name_(server_host_name), boot_file_name_(boot_file_name),
host_id_(0), cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
host_id_(0), cfg_option4_(new CfgOption()),
cfg_option6_(new CfgOption()), negative_(false) {
// Initialize host identifier.
setIdentifier(identifier, identifier_len, identifier_type);
@ -125,7 +126,8 @@ Host::Host(const std::string& identifier, const std::string& identifier_name,
dhcp6_client_classes_(dhcp6_client_classes),
next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
server_host_name_(server_host_name), boot_file_name_(boot_file_name),
host_id_(0), cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
host_id_(0), cfg_option4_(new CfgOption()),
cfg_option6_(new CfgOption()), negative_(false) {
// Initialize host identifier.
setIdentifier(identifier, identifier_name);
@ -589,6 +591,11 @@ Host::toText() const {
<< "=" << *cclass;
}
// Add negative cached.
if (negative_) {
s << " negative cached";
}
return (s.str());
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -546,6 +546,18 @@ public:
return (host_id_);
}
/// @brief Sets the negative cached flag.
///
/// @param negative New valie for negative cache flag.
void setNegative(bool negative) {
negative_ = negative;
}
/// @brief Return the negative cache flag value.
bool getNegative() const {
return (negative_);
}
/// @brief Unparses (converts to Element representation) IPv4 host
///
/// @return Element representation of the host
@ -604,6 +616,9 @@ private:
CfgOptionPtr cfg_option4_;
/// @brief Pointer to the DHCPv6 option data configuration for this host.
CfgOptionPtr cfg_option6_;
/// @brief Negative cached flag.
bool negative_;
};
/// @brief Pointer to the @c Host object.

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 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
@ -38,14 +38,11 @@ using namespace std;
namespace isc {
namespace dhcp {
HostDataSourcePtr&
HostDataSourceFactory::getHostDataSourcePtr() {
static HostDataSourcePtr hostDataSourcePtr;
return (hostDataSourcePtr);
}
map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
void
HostDataSourceFactory::create(const std::string& dbaccess) {
HostDataSourceFactory::add(HostDataSourceList& sources,
const string& dbaccess) {
// Parse the access string and create a redacted string for logging.
DatabaseConnection::ParameterMap parameters =
DatabaseConnection::parse(dbaccess);
@ -57,62 +54,146 @@ HostDataSourceFactory::create(const std::string& dbaccess) {
"contain the 'type' keyword");
}
std::string db_type = it->second;
string db_type = it->second;
auto index = map_.find(db_type);
#ifdef HAVE_MYSQL
if (db_type == "mysql") {
LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
getHostDataSourcePtr().reset(new MySqlHostDataSource(parameters));
return;
// No match?
if (index == map_.end()) {
isc_throw(InvalidType, "Hosts database access parameter 'type': " <<
db_type << " is invalid");
}
#endif
#ifdef HAVE_PGSQL
if (db_type == "postgresql") {
LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
getHostDataSourcePtr().reset(new PgSqlHostDataSource(parameters));
return;
// Call the factory and push the pointer on sources.
sources.push_back(boost::shared_ptr<BaseHostDataSource>(index->second(parameters)));
// Check the factory did not return NULL.
if (!sources.back()) {
sources.pop_back();
isc_throw(Unexpected, "Hosts database " << db_type <<
" factory returned NULL");
}
#endif
#ifdef HAVE_CQL
if (db_type == "cql") {
LOG_INFO(dhcpsrv_logger, DHCPSRV_CQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
getHostDataSourcePtr().reset(new CqlHostDataSource(parameters));
return;
}
#endif
// Get here on no match.
isc_throw(InvalidType, "Hosts database access parameter 'type': " <<
db_type << " is invalid");
}
void
HostDataSourceFactory::destroy() {
// Destroy current host data source instance. This is a no-op if no host
// data source is available.
if (getHostDataSourcePtr()) {
bool
HostDataSourceFactory::del(HostDataSourceList& sources,
const string& db_type) {
for (auto it = sources.begin(); it != sources.end(); ++it) {
if ((*it)->getType() != db_type) {
continue;
}
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE)
.arg(getHostDataSourcePtr()->getType());
.arg(db_type);
sources.erase(it);
return (true);
}
getHostDataSourcePtr().reset();
return (false);
}
#if 0
BaseHostDataSource&
HostDataSourceFactory::instance() {
BaseHostDataSource* hdsptr = getHostDataSourcePtr().get();
if (hdsptr == NULL) {
isc_throw(NoHostDataSourceManager,
"no current host data source instance is available");
bool
HostDataSourceFactory::registerFactory(const string& db_type,
const Factory& factory) {
if (map_.count(db_type)) {
return (false);
}
map_.insert(pair<string, Factory>(db_type, factory));
return (true);
}
bool
HostDataSourceFactory::deregisterFactory(const string& db_type) {
auto index = map_.find(db_type);
if (index != map_.end()) {
map_.erase(index);
return (true);
} else {
return (false);
}
return (*hdsptr);
}
#endif
} // namespace dhcp
} // namespace isc
//
// Register database backends
//
using namespace isc::dhcp;
namespace {
#ifdef HAVE_MYSQL
struct MySqlHostDataSourceInit {
// Constructor registers
MySqlHostDataSourceInit() {
HostDataSourceFactory::registerFactory("mysql", factory);
}
// Destructor deregisters
~MySqlHostDataSourceInit() {
HostDataSourceFactory::deregisterFactory("mysql");
}
// Factory class method
static BaseHostDataSource*
factory(const DatabaseConnection::ParameterMap& parameters) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
return (new MySqlHostDataSource(parameters));
}
};
// Database backend will be registered at object initialization
MySqlHostDataSourceInit mysql_init_;
#endif
#ifdef HAVE_PGSQL
struct PgSqlHostDataSourceInit {
// Constructor registers
PgSqlHostDataSourceInit() {
HostDataSourceFactory::registerFactory("postgresql", factory);
}
// Destructor deregisters
~PgSqlHostDataSourceInit() {
HostDataSourceFactory::deregisterFactory("postgresql");
}
// Factory class method
static BaseHostDataSource*
factory(const DatabaseConnection::ParameterMap& parameters) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
return (new PgSqlHostDataSource(parameters));
}
};
// Database backend will be registered at object initialization
PgSqlHostDataSourceInit pgsql_init_;
#endif
#ifdef HAVE_CQL
struct CqlHostDataSourceInit {
// Constructor registers
CqlHostDataSourceInit() {
HostDataSourceFactory::registerFactory("cql", factory);
}
// Destructor deregisters
~CqlHostDataSourceInit() {
HostDataSourceFactory::deregisterFactory("cql");
}
// Factory class method
static BaseHostDataSource*
factory(const DatabaseConnection::ParameterMap& parameters) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_CQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
return (new CqlHostDataSource(parameters));
}
};
// Database backend will be registered at object initialization
CqlHostDataSourceInit cql_init_;
#endif
} // end of anonymous namespace

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 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
@ -11,8 +11,10 @@
#include <dhcpsrv/database_connection.h>
#include <exceptions/exceptions.h>
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>
#include <string>
#include <map>
namespace isc {
namespace dhcp {
@ -38,21 +40,18 @@ public:
class HostDataSourceFactory {
public:
/// @brief Create an instance of a host data source.
/// @brief Create and add an instance of a host data source.
///
/// Each database backend has its own host data source type. This static
/// method sets the "current" host data source to be an object of the
/// appropriate type. The actual host data source is returned by the
/// "instance" method.
///
/// @note When called, the current host data source is <b>always</b> destroyed
/// and a new one created - even if the parameters are the same.
/// method adds an object of the appropriate type to a list of
/// host data sources.
///
/// dbaccess is a generic way of passing parameters. Parameters are passed
/// in the "name=value" format, separated by spaces. The data MUST include
/// a keyword/value pair of the form "type=dbtype" giving the database
/// type, e.q. "mysql" or "sqlite3".
///
/// @param sources host data source list.
/// @param dbaccess Database access parameters. These are in the form of
/// "keyword=value" pairs, separated by spaces. They are backend-
/// -end specific, although must include the "type" keyword which
@ -62,21 +61,47 @@ public:
/// keyword.
/// @throw isc::dhcp::InvalidType The "type" keyword in dbaccess does not
/// identify a supported backend.
static void create(const std::string& dbaccess);
static void add(HostDataSourceList& sources, const std::string& dbaccess);
/// @brief Destroy host data source
/// @brief Delete a host data source.
///
/// Destroys the current host data source object. This should have the effect
/// of closing the database connection. The method is a no-op if no
/// host data source is available.
static void destroy();
/// Delete the first instance of a host data source of the given type.
/// This should have the effect of closing the database connection.
///
/// @param sources host data source list.
/// @param db_type database backend type.
/// @return true when found and removed, false when not found.
static bool del(HostDataSourceList& sources, const std::string& db_type);
/// @brief Hold pointer to host data source instance
/// @brief Type of host data source factory
///
/// Holds a pointer to the singleton host data source. The singleton
/// is encapsulated in this method to avoid a "static initialization
/// fiasco" if defined in an external static variable.
static HostDataSourcePtr& getHostDataSourcePtr();
/// A factory takes a parameter map and returns a pointer to a host
/// data source. In case of failure it must throw and not return NULL.
typedef boost::function<BaseHostDataSource*(const DatabaseConnection::ParameterMap&)> Factory;
/// @brief Register a host data source factory
///
/// Associate the factory to a database type in the map.
///
/// @param db_type database type
/// @param factory host data source factory
/// @return true if the factory was successfully added to the map, false
/// if it already exists.
static bool registerFactory(const std::string& db_type,
const Factory& factory);
/// @brief Deregister a host data source factory
///
/// Disassociate the factory to a database type in the map.
///
/// @param db_type database type
/// @return true if the factory was successfully removed from the map,
/// false if it was not found.
static bool deregisterFactory(const std::string& db_type);
private:
/// @brief Factory map
static std::map<std::string, Factory> map_;
};

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -37,24 +37,53 @@ HostMgr::getHostMgrPtr() {
}
void
HostMgr::create(const std::string& access) {
HostMgr::create() {
getHostMgrPtr().reset(new HostMgr());
}
if (!access.empty()) {
// If the user specified parameters, let's pass them to the create
// method. It will destroy any prior instances and will create
// the new one.
HostDataSourceFactory::create(access);
} else {
// Ok, no parameters were specified. We should destroy the existing
// instance.
HostDataSourceFactory::destroy();
void
HostMgr::addSource(const std::string& access) {
HostDataSourceFactory::add(getHostMgrPtr()->alternate_sources_, access);
}
bool
HostMgr::delSource(const std::string& db_type) {
return (HostDataSourceFactory::del(getHostMgrPtr()->alternate_sources_, db_type));
}
void
HostMgr::delAllSources() {
getHostMgrPtr()->alternate_sources_.clear();
}
HostDataSourcePtr
HostMgr::getHostDataSource() const {
if (alternate_sources_.empty()) {
return (HostDataSourcePtr());
}
return (alternate_sources_[0]);
}
// Now store the host data source pointer. It may be NULL. That's ok as
// NULL value indicates that there's no host data source configured.
getHostMgrPtr()->alternate_source_ =
HostDataSourceFactory::getHostDataSourcePtr();
bool
HostMgr::checkCacheSource(bool logging) {
if (getHostMgrPtr()->cache_ptr_) {
return (true);
}
HostDataSourceList& sources = getHostMgrPtr()->alternate_sources_;
if (sources.empty()) {
return (false);
}
CacheHostDataSourcePtr cache_ptr =
boost::dynamic_pointer_cast<CacheHostDataSource>(sources[0]);
if (cache_ptr) {
getHostMgrPtr()->cache_ptr_ = cache_ptr;
if (logging) {
LOG_INFO(hosts_logger, HOSTS_CFG_CACHE_HOST_DATA_SOURCE)
.arg(cache_ptr->getType());
}
return (true);
}
return (false);
}
HostMgr&
@ -69,8 +98,9 @@ HostMgr::instance() {
ConstHostCollection
HostMgr::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
ConstHostCollection hosts = getCfgHosts()->getAll(hwaddr, duid);
if (alternate_source_) {
ConstHostCollection hosts_plus = alternate_source_->getAll(hwaddr, duid);
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
ConstHostCollection hosts_plus = (*it)->getAll(hwaddr, duid);
hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
}
return (hosts);
@ -83,10 +113,10 @@ HostMgr::getAll(const Host::IdentifierType& identifier_type,
ConstHostCollection hosts = getCfgHosts()->getAll(identifier_type,
identifier_begin,
identifier_len);
if (alternate_source_) {
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
ConstHostCollection hosts_plus =
alternate_source_->getAll(identifier_type, identifier_begin,
identifier_len);
(*it)->getAll(identifier_type, identifier_begin, identifier_len);
hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
}
return (hosts);
@ -96,8 +126,9 @@ HostMgr::getAll(const Host::IdentifierType& identifier_type,
ConstHostCollection
HostMgr::getAll4(const IOAddress& address) const {
ConstHostCollection hosts = getCfgHosts()->getAll4(address);
if (alternate_source_) {
ConstHostCollection hosts_plus = alternate_source_->getAll4(address);
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
ConstHostCollection hosts_plus = (*it)->getAll4(address);
hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
}
return (hosts);
@ -107,18 +138,78 @@ ConstHostPtr
HostMgr::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
const DuidPtr& duid) const {
ConstHostPtr host = getCfgHosts()->get4(subnet_id, hwaddr, duid);
if (!host && alternate_source_) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_HWADDR_DUID)
.arg(subnet_id)
.arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)")
.arg(duid ? duid->toText() : "(duid)");
if (host || alternate_sources_.empty()) {
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_HWADDR_DUID)
.arg(subnet_id)
.arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)")
.arg(duid ? duid->toText() : "(duid)");
for (auto it = alternate_sources_.begin();
!host && it != alternate_sources_.end(); ++it) {
if (duid) {
host = alternate_source_->get4(subnet_id, HWAddrPtr(), duid);
host = (*it)->get4(subnet_id, HWAddrPtr(), duid);
}
if (!host && hwaddr) {
host = alternate_source_->get4(subnet_id, hwaddr, DuidPtr());
host = (*it)->get4(subnet_id, hwaddr, DuidPtr());
}
if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
cache(host);
}
}
if (host && host->getNegative()) {
return (ConstHostPtr());
}
return (host);
}
ConstHostPtr
HostMgr::get4Any(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
ConstHostPtr host = getCfgHosts()->get4(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host || alternate_sources_.empty()) {
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
host = (*it)->get4(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_HOST)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type,
identifier_begin,
identifier_len))
.arg((*it)->getType())
.arg(host->toText());
if (cache_ptr_ && (it != alternate_sources_.begin())) {
cache(host);
}
return (host);
}
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_NULL)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
if (negative_caching_) {
cacheNegative(subnet_id, SubnetID(0),
identifier_type, identifier_begin, identifier_len);
}
return (host);
}
@ -128,49 +219,34 @@ HostMgr::get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
ConstHostPtr host = getCfgHosts()->get4(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (!host && alternate_source_) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
host = alternate_source_->get4(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_HOST)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len))
.arg(host->toText());
} else {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_NULL)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
}
ConstHostPtr host = get4Any(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host && host->getNegative()) {
return (ConstHostPtr());
}
return (host);
}
ConstHostPtr
HostMgr::get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
ConstHostPtr host = getCfgHosts()->get4(subnet_id, address);
if (!host && alternate_source_) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4)
.arg(subnet_id)
.arg(address.toText());
host = alternate_source_->get4(subnet_id, address);
if (host || alternate_sources_.empty()) {
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4)
.arg(subnet_id)
.arg(address.toText());
for (auto it = alternate_sources_.begin();
!host && it != alternate_sources_.end(); ++it) {
host = (*it)->get4(subnet_id, address);
if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
cache(host);
}
}
if (host && host->getNegative()) {
return (ConstHostPtr());
}
return (host);
}
@ -180,18 +256,29 @@ ConstHostPtr
HostMgr::get6(const SubnetID& subnet_id, const DuidPtr& duid,
const HWAddrPtr& hwaddr) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, duid, hwaddr);
if (!host && alternate_source_) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_DUID_HWADDR)
.arg(subnet_id)
.arg(duid ? duid->toText() : "(duid)")
.arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)");
if (host || alternate_sources_.empty()) {
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_DUID_HWADDR)
.arg(subnet_id)
.arg(duid ? duid->toText() : "(duid)")
.arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)");
for (auto it = alternate_sources_.begin();
!host && it != alternate_sources_.end(); ++it) {
if (duid) {
host = alternate_source_->get6(subnet_id, duid, HWAddrPtr());
host = (*it)->get6(subnet_id, duid, HWAddrPtr());
}
if (!host && hwaddr) {
host = alternate_source_->get6(subnet_id, DuidPtr(), hwaddr);
host = (*it)->get6(subnet_id, DuidPtr(), hwaddr);
}
if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
cache(host);
}
}
if (host && host->getNegative()) {
return (ConstHostPtr());
}
return (host);
}
@ -199,13 +286,77 @@ HostMgr::get6(const SubnetID& subnet_id, const DuidPtr& duid,
ConstHostPtr
HostMgr::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
ConstHostPtr host = getCfgHosts()->get6(prefix, prefix_len);
if (!host && alternate_source_) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_PREFIX)
.arg(prefix.toText())
.arg(static_cast<int>(prefix_len));
host = alternate_source_->get6(prefix, prefix_len);
if (host || alternate_sources_.empty()) {
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_PREFIX)
.arg(prefix.toText())
.arg(static_cast<int>(prefix_len));
for (auto it = alternate_sources_.begin();
!host && it != alternate_sources_.end(); ++it) {
host = (*it)->get6(prefix, prefix_len);
if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
cache(host);
}
}
if (host && host->getNegative()) {
return (ConstHostPtr());
}
return (host);
}
ConstHostPtr
HostMgr::get6Any(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host || alternate_sources_.empty()) {
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
host = (*it)->get6(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type,
identifier_begin,
identifier_len))
.arg((*it)->getType())
.arg(host->toText());
if (cache_ptr_ && (it != alternate_sources_.begin())) {
cache(host);
}
return (host);
}
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_NULL)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
if (negative_caching_) {
cacheNegative(SubnetID(0), subnet_id,
identifier_type, identifier_begin, identifier_len);
}
return (host);
}
@ -214,36 +365,10 @@ HostMgr::get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (!host && alternate_source_) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
host = alternate_source_->get6(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len))
.arg(host->toText());
} else {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_NULL)
.arg(subnet_id)
.arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
identifier_len));
}
ConstHostPtr host = get6Any(subnet_id, identifier_type,
identifier_begin, identifier_len);
if (host && host->getNegative()) {
return (ConstHostPtr());
}
return (host);
}
@ -252,57 +377,121 @@ ConstHostPtr
HostMgr::get6(const SubnetID& subnet_id,
const asiolink::IOAddress& addr) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, addr);
if (!host && alternate_source_) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6)
.arg(subnet_id)
.arg(addr.toText());
host = alternate_source_->get6(subnet_id, addr);
if (host || alternate_sources_.empty()) {
return (host);
}
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6)
.arg(subnet_id)
.arg(addr.toText());
for (auto it = alternate_sources_.begin();
!host && it != alternate_sources_.end(); ++it) {
host = (*it)->get6(subnet_id, addr);
if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
cache(host);
}
}
if (host && host->getNegative()) {
return (ConstHostPtr());
}
return (host);
}
void
bool
HostMgr::add(const HostPtr& host) {
if (!alternate_source_) {
if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "Unable to add new host because there is "
"no hosts-database configured.");
}
alternate_source_->add(host);
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
if ((*it)->add(host)) {
return (true);
}
}
// This should never happen as at least one backend implements addition.
return (false);
}
bool
HostMgr::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) {
if (!alternate_source_) {
if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
"no hosts-database configured.");
}
return (alternate_source_->del(subnet_id, addr));
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
if ((*it)->del(subnet_id, addr)) {
return (true);
}
}
return (false);
}
bool
HostMgr::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const size_t identifier_len) {
if (!alternate_source_) {
if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
"no hosts-database configured.");
}
return (alternate_source_->del4(subnet_id, identifier_type,
identifier_begin, identifier_len));
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
if ((*it)->del4(subnet_id, identifier_type,
identifier_begin, identifier_len)) {
return (true);
}
}
return (false);
}
bool
HostMgr::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const size_t identifier_len) {
if (!alternate_source_) {
if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "unable to delete a host because there is "
"no alternate host data source present");
}
return (alternate_source_->del6(subnet_id, identifier_type,
identifier_begin, identifier_len));
for (auto it = alternate_sources_.begin();
it != alternate_sources_.end(); ++it) {
if ((*it)->del6(subnet_id, identifier_type,
identifier_begin, identifier_len)) {
return (true);
}
}
return (false);
}
void
HostMgr::cache(ConstHostPtr host) const {
if (cache_ptr_) {
// Replace any existing value.
int overwrite = 0;
// Don't check the result as it does not matter?
cache_ptr_->insert(host, overwrite);
}
}
void
HostMgr::cacheNegative(const SubnetID& ipv4_subnet_id,
const SubnetID& ipv6_subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
if (cache_ptr_ && negative_caching_) {
HostPtr host(new Host(identifier_begin, identifier_len,
identifier_type,
ipv4_subnet_id, ipv6_subnet_id,
IOAddress::IPV4_ZERO_ADDRESS()));
host->setNegative(true);
// Don't replace any existing value.
int overwrite = -1;
// nor matter if it fails.
cache_ptr_->insert(host, overwrite);
}
}
} // end of isc::dhcp namespace

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -10,6 +10,7 @@
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <dhcpsrv/base_host_data_source.h>
#include <dhcpsrv/cache_host_data_source.h>
#include <dhcpsrv/host.h>
#include <dhcpsrv/subnet_id.h>
#include <boost/noncopyable.hpp>
@ -33,42 +34,62 @@ namespace dhcp {
/// configuration, accessible through the @c CfgHosts object in the @c CfgMgr.
/// The @c CfgHosts object holds all reservations specified in the DHCP server
/// configuration file. If a particular reservation is not found in the
/// @c CfgHosts object, the @c HostMgr will try to find it using the alternate
/// host data storage. The alternate host data storage is usually a database
/// @c CfgHosts object, the @c HostMgr will try to find it using alternate
/// host data storages. An alternate host data storage is usually a database
/// (e.g. SQL database), accessible through a dedicated host data source
/// object (a.k.a. database backend). This datasource is responsible for
/// managing the connection with the database and forming appropriate queries
/// to retrieve (or update) the information about the reservations.
///
/// The use of the alternate host data source is optional and usually requires
/// The use of alternate host data sources is optional and usually requires
/// additional configuration to be specified by the server administrator.
/// For example, for the SQL database the user's credentials, database address,
/// and database name are required. The @c HostMgr passes these parameters
/// to an appropriate datasource which is responsible for opening a connection
/// and maintaining it.
///
/// It is possible to switch to a different alternate data source or disable
/// the use of the alternate datasource, e.g. as a result of server's
/// It is possible to switch to different alternate data sources or disable
/// the use of alternate datasources, e.g. as a result of server's
/// reconfiguration. However, the use of the primary host data source (i.e.
/// reservations specified in the configuration file) can't be disabled.
///
/// @todo Implement alternate host data sources: MySQL, PostgreSQL, etc.
class HostMgr : public boost::noncopyable, public BaseHostDataSource {
public:
/// @brief Creates new instance of the @c HostMgr.
///
/// If an instance of the @c HostMgr already exists, it will be replaced
/// by the new instance. Thus, any instances of the alternate host data
/// by the new instance. Thus, any instances of alternate host data
/// sources will be dropped.
///
static void create();
/// @brief Add an alternate host data source.
///
/// @param access Host data source access parameters for the alternate
/// host data source. It holds "keyword=value" pairs, separated by spaces.
/// The supported values are specific to the alternate data source in use.
/// However, the "type" parameter will be common and it will specify which
/// data source is to be used. Currently, no parameters are supported
/// and the parameter is ignored.
static void create(const std::string& access = "");
static void addSource(const std::string& access);
/// @brief Delete an alternate host data source.
///
/// @param db_type_type database backend type.
/// @return true when found and removed, false when not found.
static bool delSource(const std::string& db_type);
/// @brief Delete all alternate host data source.
static void delAllSources();
/// @brief Check for the cache host data source.
///
/// Checks if the first host data source implements
/// the cache abstract class and sets cache_ptr_.
///
/// @param logging When true (not the default) emit an informational log.
/// @return true if the first host data source is a cache.
static bool checkCacheSource(bool logging = false);
/// @brief Returns a sole instance of the @c HostMgr.
///
@ -159,6 +180,28 @@ public:
get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
const DuidPtr& duid = DuidPtr()) const;
/// @brief Returns any host connected to the IPv4 subnet.
///
/// This method returns a single reservation for a particular host as
/// documented in the @c BaseHostDataSource::get4 even when the
/// reservation is marked as from negative caching. This allows to
/// overload negative caching with extra information in the user
/// context.
///
/// @param subnet_id Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return Const @c Host object for which reservation has been made using
/// the specified identifier.
virtual ConstHostPtr
get4Any(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Returns a host connected to the IPv4 subnet.
///
/// This method returns a single reservation for a particular host as
@ -206,6 +249,28 @@ public:
get6(const SubnetID& subnet_id, const DuidPtr& duid,
const HWAddrPtr& hwaddr = HWAddrPtr()) const;
/// @brief Returns any host connected to the IPv6 subnet.
///
/// This method returns a host connected to the IPv6 subnet as described
/// in the @c BaseHostDataSource::get6 even when the
/// reservation is marked as from negative caching. This allows to
/// overload negative caching with extra information in the user
/// context.
///
/// @param subnet_id Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return Const @c Host object for which reservation has been made using
/// the specified identifier.
virtual ConstHostPtr
get6Any(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Returns a host connected to the IPv6 subnet.
///
/// This method returns a host connected to the IPv6 subnet as described
@ -250,40 +315,8 @@ public:
/// in use.
///
/// @param host Pointer to the new @c Host object being added.
virtual void add(const HostPtr& host);
/// @brief Return backend type
///
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
///
/// @return Type of the backend.
virtual std::string getType() const {
return (std::string("host_mgr"));
}
/// @brief Returns pointer to the host data source
///
/// May return NULL
/// @return pointer to the host data source (or NULL)
HostDataSourcePtr getHostDataSource() const {
return (alternate_source_);
}
/// @brief Sets the alternate host data source.
///
/// Note: This should be used only for testing. Do not use
/// in production. Normal control flow assumes that
/// HostMgr::create(...) is called and it instantiates
/// appropriate host data source. However, some tests
/// (e.g. host_cmds) implement their own very simple
/// data source. It's not production ready by any means,
/// so it does not belong in host_data_source_factory.cc.
/// The testing nature of this method is reflected in its name.
///
/// @param source new source to be set (may be NULL)
void setTestHostDataSource(const HostDataSourcePtr& source) {
alternate_source_ = source;
}
/// @return true if addition was successful.
virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by address.
///
@ -322,15 +355,76 @@ public:
del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const size_t identifier_len);
/// @brief Return backend type
///
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
///
/// @return Type of the backend.
virtual std::string getType() const {
return (std::string("host_mgr"));
}
/// @brief Returns the host data source list.
///
/// @return reference to the host data source list.
HostDataSourceList& getHostDataSourceList() {
return (alternate_sources_);
}
/// @brief Returns the first host data source.
///
/// May return NULL if the host data source list is empty.
/// @return pointer to the first host data source (or NULL).
HostDataSourcePtr getHostDataSource() const;
/// @brief Returns the negative caching flag.
///
/// @return the negative caching flag.
bool getNegativeCaching() const {
return (negative_caching_);
}
/// @brief Sets the negative caching flag.
///
void setNegativeCaching(bool negative_caching) {
negative_caching_ = negative_caching;
}
protected:
/// @brief The negative caching flag.
///
/// When true and the first data source is a cache negative answers
/// to get[46] for aubnet and identifier are cached.
bool negative_caching_;
/// @brief Cache an answer.
///
/// @param host Pointer to the missied host.
virtual void cache(ConstHostPtr host) const;
/// @brief Cache a negative answer.
///
/// @param ipv4_subnet_id Identifier of the IPv4 subnet.
/// @param ipv6_subnet_id Identifier of the IPv6 subnet.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of the Identifier.
/// @param identifier_len Identifier length.
virtual void cacheNegative(const SubnetID& ipv4_subnet_id,
const SubnetID& ipv6_subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
private:
/// @brief Private default constructor.
HostMgr() { }
HostMgr() : negative_caching_(false) { }
/// @brief Pointer to an alternate host data source.
///
/// If this pointer is NULL, the source is not in use.
HostDataSourcePtr alternate_source_;
/// @brief List of alternate host data sources.
HostDataSourceList alternate_sources_;
/// @brief Pointer to the cache.
CacheHostDataSourcePtr cache_ptr_;
/// @brief Returns a pointer to the currently used instance of the
/// @c HostMgr.

View File

@ -1,4 +1,4 @@
# Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
# Copyright (C) 2015-2018 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
@ -11,6 +11,10 @@ This debug message is issued when new host (with reservations) is added to
the server's configuration. The argument describes the host and its
reservations in detail.
% HOSTS_CFG_CACHE_HOST_DATA_SOURCE get host cache data source: %1
This informational message is issued when a host cache data source is
detected by the host manager.
% HOSTS_CFG_CLOSE_HOST_DATA_SOURCE Closing host data source: %1
This is a normal message being printed when the server closes host data
source connection.
@ -134,24 +138,24 @@ subnet id and specific host identifier.
This debug message is issued when no host was found using the specified
subnet id and host identifier.
% HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4 trying alternate source for host using subnet id %1 and address %2
% HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4 trying alternate sources for host using subnet id %1 and address %2
This debug message is issued when the Host Manager doesn't find the
host connected to the specific subnet and having the reservation for
the specific IPv4 address, and it is starting to search for this host
in the alternate host data source.
in alternate host data sources.
% HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_HWADDR_DUID trying alternate source for host using subnet id %1, HWADDR %2, DUID%3
% HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_HWADDR_DUID trying alternate sources for host using subnet id %1, HWADDR %2, DUID%3
This debug message is issued when the Host Manager doesn't find the
host connected to the specific subnet and identified by the HW address
or DUID, and it is starting to search for this host in the alternate
host data source.
or DUID, and it is starting to search for this host in alternate
host data sources.
% HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER get one host with IPv4 reservation for subnet id %1, identified by %2
This debug message is issued when starting to retrieve a host holding
IPv4 reservation, which is connected to a specific subnet and
is identified by a specific unique identifier.
% HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_HOST using subnet id %1 and identifier %2, found host: %3
% HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_HOST using subnet id %1 and identifier %2, found in %3 host: %4
This debug message includes the details of a host returned by an
alternate hosts data source using a subnet id and specific host
identifier.
@ -160,32 +164,32 @@ identifier.
This debug message is issued when no host was found using the specified
subnet id and host identifier.
% HOSTS_MGR_ALTERNATE_GET6_PREFIX trying alternate source for host using prefix %1/%2
% HOSTS_MGR_ALTERNATE_GET6_PREFIX trying alternate sources for host using prefix %1/%2
This debug message is issued when the Host Manager doesn't find the
host connected to the specific subnet and having the reservation for
the specified prefix, and it is starting to search for this host in
the alternate host data source.
alternate host data sources.
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6 trying alternate source for host using subnet id %1 and IPv6 address %2
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6 trying alternate sources for host using subnet id %1 and IPv6 address %2
This debug message is issued when the Host Manager doesn't find the
host connected to the specific subnet and having the reservation for
the specified IPv6 address, and it is starting to search for this
host in the alternate host data source.
host in alternate host data sources.
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_DUID_HWADDR trying alternate source for host using subnet id %1, DUID %2, HWADDR %3
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_DUID_HWADDR trying alternate sources for host using subnet id %1, DUID %2, HWADDR %3
This debug message is issued when the Host Manager doesn't find the
host connected to the specific subnet and identified by the specified
DUID or HW Address, and it is starting to search for this host in the
alternate host data source.
DUID or HW Address, and it is starting to search for this host in
alternate host data sources.
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER get one host with IPv6 reservation for subnet id %1, identified by %2
This debug message is issued when starting to retrieve a host holding
IPv4 reservation, which is connected to a specific subnet and
is identified by a specific unique identifier.
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST using subnet id %1 and identifier %2, found host: %3
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST using subnet id %1 and identifier %2, found in %3 host: %4
This debug message includes the details of a host returned by an
alternate hosts data source using a subnet id and specific host
alternate host data source using a subnet id and specific host
identifier.
% HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_NULL host not found using subnet id %1 and identifier %2

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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
@ -103,9 +103,10 @@ database. This object must implement the \ref isc::dhcp::BaseHostDataSource
interface and its implementation is specific to the type of storage
holding the reservations. For example, the host data source managing
host reservations in the MySQL database is required to establish
connection to the MySQL database and issue specific queries. Once
implemented, the \ref isc::dhcp::HostMgr::create method must be updated
to create an instance of this datasource. Note, that this instance is
connection to the MySQL database and issue specific queries. A factory
method creating an instance of a base host data source object must be
registered (at global object initialization for built-in backends,
dynamically for backends loaded at run-time). Note, that this instance is
created as "alternate host data source" as opposed to the primary data
source which returns host reservations specified in the configuration file.
The primary data source is implemented internally in the

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 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
@ -2562,7 +2562,7 @@ MySqlHostDataSource::~MySqlHostDataSource() {
delete impl_;
}
void
bool
MySqlHostDataSource::add(const HostPtr& host) {
// If operating in read-only mode, throw exception.
impl_->checkReadOnly();
@ -2607,6 +2607,8 @@ MySqlHostDataSource::add(const HostPtr& host) {
// Everything went fine, so explicitly commit the transaction.
transaction.commit();
return (true);
}
bool

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 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
@ -223,7 +223,8 @@ public:
/// one instance is identified by HW address, another one by DUID.
///
/// @param host Pointer to the new @c Host object being added.
virtual void add(const HostPtr& host);
/// @return true as addition is successful or throws.
virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by (subnet-id, address)
///

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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
@ -30,7 +30,7 @@ namespace dhcp {
// Factory function to build the parser
DbAccessParser::DbAccessParser(DBType db_type)
DbAccessParser::DbAccessParser(size_t db_type)
: values_(), type_(db_type) {
}
@ -110,7 +110,8 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
// a. Check if the "type" keyword exists and thrown an exception if not.
StringPairMap::const_iterator type_ptr = values_copy.find("type");
if (type_ptr == values_copy.end()) {
isc_throw(DhcpConfigError, (type_ == LEASE_DB ? "lease" : "host")
isc_throw(DhcpConfigError,
(type_ == CfgDbAccess::LEASE_DB ? "lease" : "host")
<< " database access parameters must "
"include the keyword 'type' to determine type of database "
"to be accessed (" << database_config->getPosition() << ")");
@ -167,10 +168,12 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
values_.swap(values_copy);
// 5. Save the database access string in the Configuration Manager.
if (type_ == LEASE_DB) {
if (type_ == CfgDbAccess::LEASE_DB) {
cfg_db->setLeaseDbAccessString(getDbAccessString());
} else if (type_ == HOSTS_DB) {
} else if (type_ == CfgDbAccess::HOSTS_DB) {
cfg_db->setHostDbAccessString(getDbAccessString());
} else if (type_ > CfgDbAccess::HOSTS_DB) {
cfg_db->pushHostDbAccessString(getDbAccessString());
}
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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
@ -28,12 +28,6 @@ namespace dhcp {
class DbAccessParser: public isc::data::SimpleParser {
public:
/// @brief Specifies the database type
typedef enum {
LEASE_DB = 1,
HOSTS_DB = 2
} DBType;
/// @brief Keyword and associated value
typedef std::pair<std::string, std::string> StringPair;
@ -43,7 +37,7 @@ public:
/// @brief Constructor
///
/// @param db_type Specifies database type (lease or hosts)
explicit DbAccessParser(DBType db_type);
explicit DbAccessParser(size_t db_type);
/// The destructor.
virtual ~DbAccessParser()
@ -98,7 +92,7 @@ private:
std::map<std::string, std::string> values_; ///< Stored parameter values
DBType type_; ///< Database type (leases or hosts)
size_t type_; ///< Database type (leases or hosts)
};
}; // namespace dhcp

View File

@ -1934,7 +1934,7 @@ PgSqlHostDataSource::~PgSqlHostDataSource() {
delete impl_;
}
void
bool
PgSqlHostDataSource::add(const HostPtr& host) {
// If operating in read-only mode, throw exception.
impl_->checkReadOnly();
@ -1977,6 +1977,8 @@ PgSqlHostDataSource::add(const HostPtr& host) {
// Everything went fine, so explicitly commit the transaction.
transaction.commit();
return (true);
}
bool

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2018 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
@ -247,9 +247,10 @@ public:
/// -# Address and Prefix Length must be unique (DuplicateEntry)
///
/// @param host Pointer to the new @c Host object being added.
/// @return true as addition is successful or throws.
/// @throw DuplicateEntry or DbOperationError dependent on the constraint
/// violation
virtual void add(const HostPtr& host);
virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by (subnet-id, address)
///

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -342,12 +342,11 @@ SrvConfig::toElement() const {
// Set lease-database
CfgLeaseDbAccess lease_db(*cfg_db_access_);
dhcp->set("lease-database", lease_db.toElement());
// Set hosts-database
// Set hosts-databases
CfgHostDbAccess host_db(*cfg_db_access_);
// @todo accept empty map
ConstElementPtr hosts_database = host_db.toElement();
if (hosts_database->size() > 0) {
dhcp->set("hosts-database", hosts_database);
ConstElementPtr hosts_databases = host_db.toElement();
if (hosts_databases->size() > 0) {
dhcp->set("hosts-databases", hosts_databases);
}
// Set host-reservation-identifiers
ConstElementPtr host_ids;

View File

@ -91,6 +91,7 @@ libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc
libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += host_data_source_factory_unittest.cc
libdhcpsrv_unittests_SOURCES += host_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += host_unittest.cc
libdhcpsrv_unittests_SOURCES += host_reservation_parser_unittest.cc
@ -103,7 +104,6 @@ libdhcpsrv_unittests_SOURCES += lease_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += logging_unittest.cc
libdhcpsrv_unittests_SOURCES += logging_info_unittest.cc
libdhcpsrv_unittests_SOURCES += generic_lease_mgr_unittest.cc generic_lease_mgr_unittest.h
libdhcpsrv_unittests_SOURCES += generic_host_data_source_unittest.cc generic_host_data_source_unittest.h
libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += dhcp_parsers_unittest.cc
if HAVE_MYSQL

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2018 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
@ -30,7 +30,7 @@ TEST(CfgDbAccessTest, defaults) {
runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
EXPECT_TRUE(cfg.getHostDbAccessString().empty());
runToElementTest<CfgHostDbAccess>("{ }", CfgHostDbAccess(cfg));
runToElementTest<CfgHostDbAccess>("[ ]", CfgHostDbAccess(cfg));
}
// This test verifies that it is possible to set the lease database
@ -65,7 +65,7 @@ TEST(CfgDbAccessTest, setHostDbAccessString) {
EXPECT_EQ("type=mysql", cfg.getHostDbAccessString());
// Check unparse
std::string expected = "{ \"type\": \"mysql\" }";
std::string expected = "[ { \"type\": \"mysql\" } ]";
runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
// Append additional parameter.
@ -80,6 +80,39 @@ TEST(CfgDbAccessTest, setHostDbAccessString) {
EXPECT_TRUE(cfg.getHostDbAccessString().empty());
}
// This test verifies that it is possible to set multiple host
// database string.
TEST(CfgDbAccessTest, pushHostDbAccessString) {
CfgDbAccess cfg;
ASSERT_NO_THROW(cfg.setHostDbAccessString("type=mysql"));
EXPECT_EQ("type=mysql", cfg.getHostDbAccessString());
// Push two other strings
ASSERT_NO_THROW(cfg.pushHostDbAccessString("type=foo"));
ASSERT_NO_THROW(cfg.pushHostDbAccessString("type=bar"));
// Check unparse
std::string expected = "[ { \"type\": \"mysql\" }, ";
expected += "{ \"type\": \"foo\" }, { \"type\": \"bar\" } ]";
runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
// Check access strings
std::vector<std::string> hal = cfg.getHostDbAccessStringList();
ASSERT_EQ(3, hal.size());
EXPECT_EQ("type=mysql", hal[0]);
EXPECT_EQ("type=foo", hal[1]);
EXPECT_EQ("type=bar", hal[2]);
// Reset the first string so it will be ignored.
ASSERT_NO_THROW(cfg.setHostDbAccessString(""));
expected = "[ { \"type\": \"foo\" }, { \"type\": \"bar\" } ]";
runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
hal = cfg.getHostDbAccessStringList();
ASSERT_EQ(2, hal.size());
EXPECT_EQ("type=foo", hal[0]);
EXPECT_EQ("type=bar", hal[1]);
}
// Tests that lease manager can be created from a specified configuration.
TEST(CfgDbAccessTest, createLeaseMgr) {
CfgDbAccess cfg;
@ -129,8 +162,8 @@ TEST_F(CfgMySQLDbAccessTest, createManagers) {
});
ASSERT_NO_THROW({
HostDataSourcePtr& host_data_source =
HostDataSourceFactory::getHostDataSourcePtr();
const HostDataSourcePtr& host_data_source =
HostMgr::instance().getHostDataSource();
ASSERT_TRUE(host_data_source);
EXPECT_EQ("mysql", host_data_source->getType());
});
@ -142,8 +175,8 @@ TEST_F(CfgMySQLDbAccessTest, createManagers) {
ASSERT_NO_THROW(HostMgr::instance());
ASSERT_NO_THROW({
HostDataSourcePtr& host_data_source =
HostDataSourceFactory::getHostDataSourcePtr();
const HostDataSourcePtr& host_data_source =
HostMgr::instance().getHostDataSource();
ASSERT_TRUE(host_data_source);
EXPECT_EQ("mysql", host_data_source->getType());
});

View File

@ -22,8 +22,9 @@
#include <dhcpsrv/cql_host_data_source.h>
#include <dhcpsrv/cql_lease_mgr.h>
#include <dhcpsrv/host.h>
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
#include <dhcpsrv/tests/test_utils.h>
#include <dhcpsrv/testutils/cql_schema.h>
#include <dhcpsrv/testutils/host_data_source_utils.h>
@ -54,7 +55,8 @@ public:
// Connect to the database
try {
HostDataSourceFactory::create(validCqlConnectionString());
HostMgr::create();
HostMgr::addSource(validCqlConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test"
"*** environment is broken and must be fixed before"
@ -64,7 +66,7 @@ public:
throw;
}
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief Destroys the HDS and the schema.
@ -75,7 +77,8 @@ public:
// Rollback should never fail, as Cassandra doesn't support transactions
// (commit and rollback are both no-op).
}
HostDataSourceFactory::destroy();
HostMgr::delAllSources();
hdsptr_.reset();
destroyCqlSchema(false, true);
}
@ -103,9 +106,9 @@ public:
/// Parameter is ignored for CQL backend as the v4 and v6 leases share
/// the same database.
void reopen(Universe) {
HostDataSourceFactory::destroy();
HostDataSourceFactory::create(validCqlConnectionString());
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
HostMgr::create();
HostMgr::addSource(validCqlConnectionString());
hdsptr_ = HostMgr::instance().getHostDataSource();
}
};
@ -124,9 +127,9 @@ TEST(CqlHostDataSource, OpenDatabase) {
// Check that lease manager open the database opens correctly and tidy up.
// If it fails, print the error message.
try {
HostDataSourceFactory::create(validCqlConnectionString());
EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
HostMgr::create();
EXPECT_NO_THROW(HostMgr::addSource(validCqlConnectionString()));
HostMgr::delSource("cql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
@ -139,9 +142,9 @@ TEST(CqlHostDataSource, OpenDatabase) {
try {
std::string connection_string = validCqlConnectionString() + std::string(" ") +
std::string(VALID_TIMEOUT);
HostDataSourceFactory::create(connection_string);
EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
HostMgr::create();
EXPECT_NO_THROW(HostMgr::addSource(connection_string));
HostMgr::delSource("cql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
@ -151,39 +154,39 @@ TEST(CqlHostDataSource, OpenDatabase) {
// Check that attempting to get an instance of the host data source when
// none is set throws an exception.
EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
EXPECT_FALSE(HostMgr::instance().getHostDataSource());
// Check that wrong specification of backend throws an exception.
// (This is really a check on HostDataSourceFactory, but is convenient to
// perform here.)
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
InvalidParameter);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
InvalidType);
// Check that invalid login data does not cause an exception, CQL should use
// default values.
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
// Check that invalid timeouts throw DbOperationError.
EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
EXPECT_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
DbOperationError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
EXPECT_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
DbOperationError);
// Check that CQL allows the hostname to not be specified.
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
// Tidy up after the test

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2018 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
@ -195,7 +195,7 @@ public:
/// @brief Constructor
///
/// @brief Keyword/value collection of database access parameters
TestDbAccessParser(DbAccessParser::DBType type)
TestDbAccessParser(size_t type)
: DbAccessParser(type)
{}
@ -243,7 +243,7 @@ TEST_F(DbAccessParserTest, validTypeMemfile) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
}
@ -257,7 +257,7 @@ TEST_F(DbAccessParserTest, hosts) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::HOSTS_DB);
TestDbAccessParser parser(CfgDbAccess::HOSTS_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
}
@ -273,7 +273,7 @@ TEST_F(DbAccessParserTest, emptyKeyword) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
}
@ -290,7 +290,7 @@ TEST_F(DbAccessParserTest, persistV4Memfile) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(),
@ -309,7 +309,7 @@ TEST_F(DbAccessParserTest, persistV6Memfile) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(),
@ -328,7 +328,7 @@ TEST_F(DbAccessParserTest, validLFCInterval) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid LFC Interval", parser.getDbAccessParameters(),
config);
@ -346,7 +346,7 @@ TEST_F(DbAccessParserTest, negativeLFCInterval) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
@ -362,7 +362,7 @@ TEST_F(DbAccessParserTest, largeLFCInterval) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
@ -378,7 +378,7 @@ TEST_F(DbAccessParserTest, validTimeout) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid timeout", parser.getDbAccessParameters(),
config);
@ -396,7 +396,7 @@ TEST_F(DbAccessParserTest, negativeTimeout) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
@ -412,7 +412,7 @@ TEST_F(DbAccessParserTest, largeTimeout) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
@ -428,7 +428,7 @@ TEST_F(DbAccessParserTest, validPort) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid port", parser.getDbAccessParameters(),
config);
@ -446,7 +446,7 @@ TEST_F(DbAccessParserTest, negativePort) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
@ -462,7 +462,7 @@ TEST_F(DbAccessParserTest, largePort) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
@ -480,7 +480,7 @@ TEST_F(DbAccessParserTest, validTypeMysql) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid mysql", parser.getDbAccessParameters(), config);
}
@ -498,7 +498,7 @@ TEST_F(DbAccessParserTest, missingTypeKeyword) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
@ -549,7 +549,7 @@ TEST_F(DbAccessParserTest, incrementalChanges) {
"name", "keatest",
NULL};
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
// First configuration string should cause a representation of that string
// to be held.
@ -613,7 +613,7 @@ TEST_F(DbAccessParserTest, getDbAccessString) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
// Get the database access string
@ -639,7 +639,7 @@ TEST_F(DbAccessParserTest, validReadOnly) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid readonly parameter",
@ -661,9 +661,35 @@ TEST_F(DbAccessParserTest, invalidReadOnly) {
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
TestDbAccessParser parser(DbAccessParser::LEASE_DB);
TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
// Check that multiple host storages are correctly parsed.
TEST_F(DbAccessParserTest, multipleHost) {
const char* config1[] = {"type", "mysql",
"name", "keatest1",
NULL};
const char* config2[] = {"type", "mysql",
"name", "keatest2",
NULL};
string json_config1 = toJson(config1);
string json_config2 = toJson(config2);
ConstElementPtr json_elements1 = Element::fromJSON(json_config1);
ConstElementPtr json_elements2 = Element::fromJSON(json_config2);
TestDbAccessParser parser1(2);
TestDbAccessParser parser2(3);
EXPECT_NO_THROW(parser1.parse(json_elements1));
EXPECT_NO_THROW(parser2.parse(json_elements2));
checkAccessString("First config",
parser1.getDbAccessParameters(),
config1);
checkAccessString("Second config",
parser2.getDbAccessParameters(),
config2);
}
}; // Anonymous namespace

View File

@ -0,0 +1,178 @@
// Copyright (C) 2018 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/testutils/memory_host_data_source.h>
#include <exceptions/exceptions.h>
#include <gtest/gtest.h>
#include <iostream>
#include <sstream>
using namespace std;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
namespace {
// @brief Register memFactory
bool registerFactory() {
return (HostDataSourceFactory::registerFactory("mem", memFactory));
}
// @brief Derive mem1 class
class Mem1HostDataSource : public MemHostDataSource {
public:
virtual string getType() const {
return ("mem1");
}
};
// @brief Factory of mem1
BaseHostDataSource*
mem1Factory(const DatabaseConnection::ParameterMap&) {
return (new Mem1HostDataSource());
}
// @brief Register mem1Factory
bool registerFactory1() {
return (HostDataSourceFactory::registerFactory("mem1", mem1Factory));
}
// @brief Derive mem2 class
class Mem2HostDataSource : public MemHostDataSource {
public:
virtual string getType() const {
return ("mem2");
}
};
// @brief Factory of mem2
BaseHostDataSource*
mem2Factory(const DatabaseConnection::ParameterMap&) {
return (new Mem2HostDataSource());
}
// @brief Register mem2Factory
bool registerFactory2() {
return (HostDataSourceFactory::registerFactory("mem2", mem2Factory));
}
// @brief Factory function returning 0
BaseHostDataSource* factory0(const DatabaseConnection::ParameterMap&) {
return (0);
}
// @brief Test fixture class
class HostDataSourceFactoryTest : public ::testing::Test {
private:
// @brief Prepares the class for a test.
virtual void SetUp() {
}
// @brief Cleans up after the test.
virtual void TearDown() {
sources_.clear();
HostDataSourceFactory::deregisterFactory("mem");
HostDataSourceFactory::deregisterFactory("mem1");
HostDataSourceFactory::deregisterFactory("mem2");
}
public:
HostDataSourceList sources_;
};
// Verify a factory can be registered and only once.
TEST_F(HostDataSourceFactoryTest, registerFactory) {
EXPECT_TRUE(registerFactory());
// Only once
EXPECT_FALSE(registerFactory());
}
// Verify a factory can be registered and deregistered
TEST_F(HostDataSourceFactoryTest, deregisterFactory) {
// Does not exist at the beginning
EXPECT_FALSE(HostDataSourceFactory::deregisterFactory("mem"));
// Register and deregister
EXPECT_TRUE(registerFactory());
EXPECT_TRUE(HostDataSourceFactory::deregisterFactory("mem"));
// No longer exists
EXPECT_FALSE(HostDataSourceFactory::deregisterFactory("mem"));
}
// Verify a registered factory can be called
TEST_F(HostDataSourceFactoryTest, add) {
EXPECT_TRUE(registerFactory());
EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=mem"));
ASSERT_EQ(1, sources_.size());
EXPECT_EQ("mem", sources_[0]->getType());
}
// Verify that type is required
TEST_F(HostDataSourceFactoryTest, notype) {
EXPECT_THROW(HostDataSourceFactory::add(sources_, "tp=mem"),
InvalidParameter);
EXPECT_THROW(HostDataSourceFactory::add(sources_, "type=mem"),
InvalidType);
}
// Verify that factory must not return NULL
TEST_F(HostDataSourceFactoryTest, null) {
EXPECT_TRUE(HostDataSourceFactory::registerFactory("mem", factory0));
EXPECT_THROW(HostDataSourceFactory::add(sources_, "type=mem"),
Unexpected);
}
// Verify del class method
TEST_F(HostDataSourceFactoryTest, del) {
// No sources at the beginning
EXPECT_FALSE(HostDataSourceFactory::del(sources_, "mem"));
// Add mem
EXPECT_TRUE(registerFactory());
EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=mem"));
ASSERT_EQ(1, sources_.size());
// Delete another
EXPECT_FALSE(HostDataSourceFactory::del(sources_, "another"));
// Delete mem
EXPECT_TRUE(HostDataSourceFactory::del(sources_, "mem"));
// No longer mem in sources
EXPECT_FALSE(HostDataSourceFactory::del(sources_, "mem"));
}
// Verify add and del class method on multiple backends
TEST_F(HostDataSourceFactoryTest, multiple) {
// Add foo twice
EXPECT_TRUE(registerFactory1());
EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=mem1"));
EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=mem1"));
// Add mem2 once
EXPECT_TRUE(registerFactory2());
EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=mem2"));
// Delete them
EXPECT_TRUE(HostDataSourceFactory::del(sources_, "mem1"));
EXPECT_TRUE(HostDataSourceFactory::del(sources_, "mem2"));
// Second instance of mem1
EXPECT_TRUE(HostDataSourceFactory::del(sources_, "mem1"));
// No more sources
EXPECT_EQ(0, sources_.size());
EXPECT_FALSE(HostDataSourceFactory::del(sources_, "mem1"));
EXPECT_FALSE(HostDataSourceFactory::del(sources_, "mem2"));
}
}; // end of anonymous namespace

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -109,6 +109,10 @@ protected:
/// from which it will be retrieved.
void testGet4(BaseHostDataSource& data_source);
/// @brief This test verifies that it is possible to retrieve negative
/// cached reservation with and only with get4Any,
void testGet4Any();
/// @brief This test verifies that it is possible to retrieve an IPv6
/// reservation for the particular host using HostMgr.
///
@ -116,6 +120,10 @@ protected:
/// from which it will be retrieved.
void testGet6(BaseHostDataSource& data_source);
/// @brief This test verifies that it is possible to retrieve negative
/// cached reservation with and only with get6Any,
void testGet6Any();
/// @brief This test verifies that it is possible to retrieve an IPv6
/// prefix reservation for the particular host using HostMgr.
///
@ -210,8 +218,8 @@ HostMgrTest::testGetAll(BaseHostDataSource& data_source1,
// If there non-matching HW address is specified, nothing should be
// returned.
hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR,
&hwaddrs_[1]->hwaddr_[0],
hwaddrs_[1]->hwaddr_.size());
&hwaddrs_[1]->hwaddr_[0],
hwaddrs_[1]->hwaddr_.size());
ASSERT_TRUE(hosts.empty());
// For the correct HW address, there should be two reservations.
@ -225,7 +233,7 @@ HostMgrTest::testGetAll(BaseHostDataSource& data_source1,
// Look for the first reservation.
bool found = false;
for (int i = 0; i < 2; ++i) {
for (unsigned i = 0; i < 2; ++i) {
if (hosts[0]->getIPv4Reservation() == IOAddress("192.0.2.5")) {
ASSERT_EQ(1, hosts[0]->getIPv4SubnetID());
found = true;
@ -238,7 +246,7 @@ HostMgrTest::testGetAll(BaseHostDataSource& data_source1,
// Look for the second reservation.
found = false;
for (int i = 0; i < 2; ++i) {
for (unsigned i = 0; i < 2; ++i) {
if (hosts[1]->getIPv4Reservation() == IOAddress("192.0.3.10")) {
ASSERT_EQ(10, hosts[1]->getIPv4SubnetID());
found = true;
@ -297,6 +305,53 @@ HostMgrTest::testGet4(BaseHostDataSource& data_source) {
EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
}
void
HostMgrTest::testGet4Any() {
// Initially, no host should be present.
ConstHostPtr host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
&duids_[0]->getDuid()[0],
duids_[0]->getDuid().size());
ASSERT_FALSE(host);
HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID,
&duids_[0]->getDuid()[0],
duids_[0]->getDuid().size());
ASSERT_FALSE(host);
// Add new host to the database.
HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1),
SubnetID(0), IOAddress("192.0.2.5")));
// Abuse of the server's configuration.
getCfgHosts()->add(new_host);
CfgMgr::instance().commit();
// Retrieve the host from the database and expect that the parameters match.
host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
&duids_[0]->getDuid()[0],
duids_[0]->getDuid().size());
ASSERT_TRUE(host);
EXPECT_EQ(1, host->getIPv4SubnetID());
EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
// Set the negative cache flag on the host.
new_host->setNegative(true);
// Get4 can't get it.
host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
&duids_[0]->getDuid()[0],
duids_[0]->getDuid().size());
EXPECT_FALSE(host);
// But Get4Any can.
host = HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID,
&duids_[0]->getDuid()[0],
duids_[0]->getDuid().size());
ASSERT_TRUE(host);
EXPECT_EQ(1, host->getIPv4SubnetID());
EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
EXPECT_TRUE(host->getNegative());
}
void
HostMgrTest::testGet6(BaseHostDataSource& data_source) {
// Initially, no host should be present.
@ -313,10 +368,64 @@ HostMgrTest::testGet6(BaseHostDataSource& data_source) {
&duids_[0]->getDuid()[0],
duids_[0]->getDuid().size());
ASSERT_TRUE(host);
EXPECT_EQ(2, host->getIPv6SubnetID());
EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
IOAddress("2001:db8:1::1"))));
}
void
HostMgrTest::testGet6Any() {
// Initially, no host should be present.
ConstHostPtr host = HostMgr::instance().get6(SubnetID(2),
Host::IDENT_HWADDR,
&hwaddrs_[0]->hwaddr_[0],
hwaddrs_[0]->hwaddr_.size());
ASSERT_FALSE(host);
host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR,
&hwaddrs_[0]->hwaddr_[0],
hwaddrs_[0]->hwaddr_.size());
ASSERT_FALSE(host);
// Add new host to the database.
HostPtr new_host(new Host(hwaddrs_[0]->toText(false), "hw-address",
SubnetID(1), SubnetID(2),
IOAddress::IPV4_ZERO_ADDRESS()));
new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
IOAddress("2001:db8:1::1"), 128));
// Abuse of the server's configuration.
getCfgHosts()->add(new_host);
CfgMgr::instance().commit();
// Retrieve the host from the database and expect that the parameters match.
host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
&hwaddrs_[0]->hwaddr_[0],
hwaddrs_[0]->hwaddr_.size());
ASSERT_TRUE(host);
EXPECT_EQ(2, host->getIPv6SubnetID());
EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
IOAddress("2001:db8:1::1"))));
// Set the negative cache flag on the host.
new_host->setNegative(true);
// Get6 can't get it.
host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
&hwaddrs_[0]->hwaddr_[0],
hwaddrs_[0]->hwaddr_.size());
EXPECT_FALSE(host);
// But Get4Any can.
host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR,
&hwaddrs_[0]->hwaddr_[0],
hwaddrs_[0]->hwaddr_.size());
ASSERT_TRUE(host);
EXPECT_EQ(2, host->getIPv6SubnetID());
EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
IOAddress("2001:db8:1::1"))));
EXPECT_TRUE(host->getNegative());
}
void
HostMgrTest::testGet6ByPrefix(BaseHostDataSource& data_source1,
BaseHostDataSource& data_source2) {
@ -375,6 +484,11 @@ TEST_F(HostMgrTest, get4) {
testGet4(*getCfgHosts());
}
// This test verifies handling of negative caching by get4/get4Any.
TEST_F(HostMgrTest, get4Any) {
testGet4Any();
}
// This test verifies that it is possible to retrieve IPv6 reservations for
// the particular host using HostMgr. The reservation is specified in the
// server's configuration.
@ -382,6 +496,11 @@ TEST_F(HostMgrTest, get6) {
testGet6(*getCfgHosts());
}
// This test verifies handling of negative caching by get4/get4Any.
TEST_F(HostMgrTest, get6Any) {
testGet6Any();
}
// This test verifies that it is possible to retrieve the reservation of the
// particular IPv6 prefix using HostMgr.
TEST_F(HostMgrTest, get6ByPrefix) {
@ -425,7 +544,7 @@ MySQLHostMgrTest::SetUp() {
// Connect to the database
try {
HostMgr::create(test::validMySQLConnectionString());
HostMgr::addSource(test::validMySQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
@ -438,8 +557,8 @@ MySQLHostMgrTest::SetUp() {
void
MySQLHostMgrTest::TearDown() {
HostDataSourceFactory::getHostDataSourcePtr()->rollback();
HostDataSourceFactory::destroy();
HostMgr::instance().getHostDataSource()->rollback();
HostMgr::delSource("mysql");
test::destroyMySQLSchema();
}
@ -502,7 +621,7 @@ PostgreSQLHostMgrTest::SetUp() {
// Connect to the database
try {
HostMgr::create(test::validPgSQLConnectionString());
HostMgr::addSource(test::validPgSQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
@ -515,8 +634,8 @@ PostgreSQLHostMgrTest::SetUp() {
void
PostgreSQLHostMgrTest::TearDown() {
HostDataSourceFactory::getHostDataSourcePtr()->rollback();
HostDataSourceFactory::destroy();
HostMgr::instance().getHostDataSource()->rollback();
HostMgr::delSource("postgresql");
test::destroyPgSQLSchema();
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2018 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
@ -669,6 +669,7 @@ TEST_F(HostTest, setValues) {
ASSERT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
ASSERT_EQ("some-host.example.org", host->getHostname());
ASSERT_FALSE(host->getContext());
ASSERT_FALSE(host->getNegative());
host->setIPv4SubnetID(SubnetID(123));
host->setIPv6SubnetID(SubnetID(234));
@ -679,6 +680,7 @@ TEST_F(HostTest, setValues) {
host->setBootFileName("bootfile.efi");
std::string user_context = "{ \"foo\": \"bar\" }";
host->setContext(Element::fromJSON(user_context));
host->setNegative(true);
EXPECT_EQ(123, host->getIPv4SubnetID());
EXPECT_EQ(234, host->getIPv6SubnetID());
@ -689,6 +691,7 @@ TEST_F(HostTest, setValues) {
EXPECT_EQ("bootfile.efi", host->getBootFileName());
ASSERT_TRUE(host->getContext());
EXPECT_EQ(user_context, host->getContext()->str());
EXPECT_TRUE(host->getNegative());
// Remove IPv4 reservation.
host->removeIPv4Reservation();
@ -981,6 +984,7 @@ TEST_F(HostTest, toText) {
host->setHostname("");
host->removeIPv4Reservation();
host->setIPv4SubnetID(0);
host->setNegative(true);
EXPECT_EQ("hwaddr=010203040506 ipv6_subnet_id=2"
" hostname=(empty) ipv4_reservation=(no)"
@ -990,7 +994,8 @@ TEST_F(HostTest, toText) {
" ipv6_reservation0=2001:db8:1::cafe"
" ipv6_reservation1=2001:db8:1::1"
" ipv6_reservation2=2001:db8:1:1::/64"
" ipv6_reservation3=2001:db8:1:2::/64",
" ipv6_reservation3=2001:db8:1:2::/64"
" negative cached",
host->toText());
// Create host identified by DUID, instead of HWADDR, with a very
@ -1139,6 +1144,8 @@ TEST_F(HostTest, unparse) {
// Add some classes.
host->addClientClass4("modem");
host->addClientClass4("router");
// Set invisible negative cache.
host->setNegative(true);
EXPECT_EQ("{ "
"\"boot-file-name\": \"\", "

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 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
@ -12,9 +12,10 @@
#include <dhcpsrv/host.h>
#include <dhcpsrv/mysql_connection.h>
#include <dhcpsrv/mysql_host_data_source.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/mysql_schema.h>
#include <dhcpsrv/testutils/host_data_source_utils.h>
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <gtest/gtest.h>
@ -47,7 +48,8 @@ public:
// Connect to the database
try {
HostDataSourceFactory::create(validMySQLConnectionString());
HostMgr::create();
HostMgr::addSource(validMySQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
@ -57,7 +59,7 @@ public:
throw;
}
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief Destructor
@ -70,7 +72,7 @@ public:
} catch (...) {
// Rollback may fail if backend is in read only mode. That's ok.
}
HostDataSourceFactory::destroy();
HostMgr::delAllSources();
hdsptr_.reset();
destroyMySQLSchema();
}
@ -83,9 +85,9 @@ public:
/// Parameter is ignored for MySQL backend as the v4 and v6 leases share
/// the same database.
void reopen(Universe) {
HostDataSourceFactory::destroy();
HostDataSourceFactory::create(validMySQLConnectionString());
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
HostMgr::create();
HostMgr::addSource(validMySQLConnectionString());
hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief returns number of rows in a table
@ -149,9 +151,9 @@ TEST(MySqlHostDataSource, OpenDatabase) {
// Check that lease manager open the database opens correctly and tidy up.
// If it fails, print the error message.
try {
HostDataSourceFactory::create(validMySQLConnectionString());
EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
HostMgr::create();
EXPECT_NO_THROW(HostMgr::addSource(validMySQLConnectionString()));
HostMgr::delSource("mysql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
@ -164,9 +166,9 @@ TEST(MySqlHostDataSource, OpenDatabase) {
try {
string connection_string = validMySQLConnectionString() + string(" ") +
string(VALID_TIMEOUT);
HostDataSourceFactory::create(connection_string);
EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
HostMgr::create();
EXPECT_NO_THROW(HostMgr::addSource(connection_string));
HostMgr::delSource("mysql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
@ -176,43 +178,43 @@ TEST(MySqlHostDataSource, OpenDatabase) {
// Check that attempting to get an instance of the lease manager when
// none is set throws an exception.
EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
EXPECT_FALSE(HostMgr::instance().getHostDataSource());
// Check that wrong specification of backend throws an exception.
// (This is really a check on LeaseMgrFactory, but is convenient to
// perform here.)
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
InvalidParameter);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
InvalidType);
// Check that invalid login data causes an exception.
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
DbInvalidTimeout);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
DbInvalidTimeout);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD,
VALID_TIMEOUT, INVALID_READONLY_DB)), DbInvalidReadOnly);
// Check for missing parameters
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
NoDatabaseName);

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2018 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
@ -12,9 +12,10 @@
#include <dhcpsrv/host.h>
#include <dhcpsrv/pgsql_connection.h>
#include <dhcpsrv/pgsql_host_data_source.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/pgsql_schema.h>
#include <dhcpsrv/testutils/host_data_source_utils.h>
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <gtest/gtest.h>
@ -47,7 +48,8 @@ public:
// Connect to the database
try {
HostDataSourceFactory::create(validPgSQLConnectionString());
HostMgr::create();
HostMgr::addSource(validPgSQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
@ -57,7 +59,7 @@ public:
throw;
}
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief Destructor
@ -71,7 +73,7 @@ public:
} catch (...) {
// Rollback may fail if backend is in read only mode. That's ok.
}
HostDataSourceFactory::destroy();
HostMgr::delAllSources();
hdsptr_.reset();
destroyPgSQLSchema();
}
@ -84,9 +86,9 @@ public:
/// Parameter is ignored for PostgreSQL backend as the v4 and v6 leases
/// share the same database.
void reopen(Universe) {
HostDataSourceFactory::destroy();
HostDataSourceFactory::create(validPgSQLConnectionString());
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
HostMgr::create();
HostMgr::addSource(validPgSQLConnectionString());
hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief returns number of rows in a table
@ -149,9 +151,9 @@ TEST(PgSqlHostDataSource, OpenDatabase) {
// Check that lease manager open the database opens correctly and tidy up.
// If it fails, print the error message.
try {
HostDataSourceFactory::create(validPgSQLConnectionString());
EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
HostMgr::create();
EXPECT_NO_THROW(HostMgr::addSource(validPgSQLConnectionString()));
HostMgr::delSource("postgresql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
@ -164,9 +166,8 @@ TEST(PgSqlHostDataSource, OpenDatabase) {
try {
string connection_string = validPgSQLConnectionString() + string(" ") +
string(VALID_TIMEOUT);
HostDataSourceFactory::create(connection_string);
EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
EXPECT_NO_THROW(HostMgr::addSource(connection_string));
HostMgr::delSource("postgresql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
@ -176,40 +177,40 @@ TEST(PgSqlHostDataSource, OpenDatabase) {
// Check that attempting to get an instance of the lease manager when
// none is set throws an exception.
EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
EXPECT_FALSE(HostMgr::instance().getHostDataSource());
// Check that wrong specification of backend throws an exception.
// (This is really a check on LeaseMgrFactory, but is convenient to
// perform here.)
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
InvalidParameter);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
InvalidType);
// Check that invalid login data causes an exception.
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
DbOpenError);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
DbInvalidTimeout);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
DbInvalidTimeout);
// Check for missing parameters
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
NoDatabaseName);

View File

@ -15,6 +15,9 @@ noinst_LTLIBRARIES = libdhcpsrvtest.la
libdhcpsrvtest_la_SOURCES = config_result_check.cc config_result_check.h
libdhcpsrvtest_la_SOURCES += dhcp4o6_test_ipc.cc dhcp4o6_test_ipc.h
libdhcpsrvtest_la_SOURCES += host_data_source_utils.cc host_data_source_utils.h
libdhcpsrvtest_la_SOURCES += memory_host_data_source.cc memory_host_data_source.h
libdhcpsrvtest_la_SOURCES += generic_host_data_source_unittest.cc generic_host_data_source_unittest.h
libdhcpsrvtest_la_SOURCES += schema.cc schema.h
libdhcpsrvtest_la_SOURCES += lease_file_io.cc lease_file_io.h

View File

@ -14,15 +14,16 @@
#include <dhcp/option_string.h>
#include <dhcp/option_vendor.h>
#include <dhcpsrv/database_connection.h>
#include <dhcpsrv/db_exceptions.h>
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/tests/test_utils.h>
#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/schema.h>
#include <dhcpsrv/testutils/host_data_source_utils.h>
#include <util/buffer.h>
#include <boost/foreach.hpp>
#include <dhcpsrv/testutils/host_data_source_utils.h>
#include <gtest/gtest.h>
#include <util/buffer.h>
#include <chrono>
#include <cstring>
@ -195,7 +196,9 @@ GenericHostDataSourceTest::testReadOnlyDatabase(const char* valid_db_type) {
// insert some data to the database.
HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
ASSERT_TRUE(host);
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Subnet id will be used in queries to the database.
SubnetID subnet_id = host->getIPv6SubnetID();
@ -210,12 +213,12 @@ GenericHostDataSourceTest::testReadOnlyDatabase(const char* valid_db_type) {
// Close the database connection and reopen in "read-only" mode as
// specified by the "VALID_READONLY_DB" parameter.
HostDataSourceFactory::destroy();
HostDataSourceFactory::create(connectionString(
HostMgr::create();
HostMgr::addSource(connectionString(
valid_db_type, VALID_NAME, VALID_HOST, VALID_READONLY_USER,
VALID_PASSWORD, VALID_READONLY_DB));
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
hdsptr_ = HostMgr::instance().getHostDataSource();
// Check that an attempt to insert new host would result in
// exception.
@ -244,7 +247,9 @@ GenericHostDataSourceTest::testBasic4(const Host::IdentifierType& id) {
SubnetID subnet = host->getIPv4SubnetID();
// Try to add it to the host data source.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// This should not return anything
ConstHostPtr from_hds = hdsptr_->get4(subnet, IOAddress("10.10.10.10"));
@ -270,10 +275,15 @@ GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) {
HostPtr host4 = HostDataSourceUtils::initializeHost4("192.0.2.4", id);
// ... and add them to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
ASSERT_NO_THROW(hdsptr_->add(host3));
ASSERT_NO_THROW(hdsptr_->add(host4));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host3));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host4));
EXPECT_TRUE(added);
SubnetID subnet1 = host1->getIPv4SubnetID();
SubnetID subnet2 = host2->getIPv4SubnetID();
@ -316,8 +326,11 @@ GenericHostDataSourceTest::testGet4ByIdentifier(
ASSERT_FALSE(host1->getIdentifier() == host2->getIdentifier());
// Try to add both of them to the host data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
SubnetID subnet1 = host1->getIPv4SubnetID();
SubnetID subnet2 = host2->getIPv4SubnetID();
@ -348,7 +361,9 @@ GenericHostDataSourceTest::testHWAddrNotClientId() {
ASSERT_FALSE(host->getDuid());
// Try to add it to the host data source.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
SubnetID subnet = host->getIPv4SubnetID();
@ -380,7 +395,9 @@ GenericHostDataSourceTest::testClientIdNotHWAddr() {
ASSERT_TRUE(host->getDuid());
// Try to add it to the host data source.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
SubnetID subnet = host->getIPv4SubnetID();
@ -433,7 +450,9 @@ GenericHostDataSourceTest::testHostname(std::string name, int num) {
for (vector<HostPtr>::const_iterator it = hosts.begin(); it != hosts.end();
++it) {
// Try to add both of the to the host data source.
ASSERT_NO_THROW(hdsptr_->add(*it));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(*it));
EXPECT_TRUE(added);
}
// And finally retrieve them one by one and check
@ -462,7 +481,9 @@ GenericHostDataSourceTest::testUserContext(ConstElementPtr user_context) {
SubnetID subnet = host->getIPv4SubnetID();
// Try to add it to the host data source.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Retrieve it.
ConstHostPtr from_hds = hdsptr_->get4(subnet, IOAddress("192.0.2.1"));
@ -479,7 +500,8 @@ GenericHostDataSourceTest::testUserContext(ConstElementPtr user_context) {
host->setHostname("foo.example.com");
subnet = host->getIPv6SubnetID();
ASSERT_NO_THROW(hdsptr_->add(host));
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
from_hds = hdsptr_->get6(subnet, Host::IDENT_HWADDR,
&host->getIdentifier()[0],
@ -502,7 +524,9 @@ GenericHostDataSourceTest::testMultipleSubnets(int subnets,
host->setIPv4SubnetID(i + 1000);
// Check that the same host can have reservations in multiple subnets.
EXPECT_NO_THROW(hdsptr_->add(host));
bool added = false;
EXPECT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
}
// Now check that the reservations can be retrieved by IPv4 address from
@ -576,8 +600,11 @@ GenericHostDataSourceTest::testGet6ByHWAddr() {
HostDataSourceUtils::compareHwaddrs(host1, host2, false);
// Try to add both of them to the host data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
SubnetID subnet1 = host1->getIPv6SubnetID();
SubnetID subnet2 = host2->getIPv6SubnetID();
@ -613,8 +640,11 @@ GenericHostDataSourceTest::testGet6ByClientId() {
HostDataSourceUtils::compareDuids(host1, host2, false);
// Try to add both of them to the host data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
SubnetID subnet1 = host1->getIPv6SubnetID();
SubnetID subnet2 = host2->getIPv6SubnetID();
@ -650,7 +680,9 @@ GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) {
host->setIPv6SubnetID(i + 1000);
// Check that the same host can have reservations in multiple subnets.
EXPECT_NO_THROW(hdsptr_->add(host));
bool added = false;
EXPECT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Increase address to make sure we don't assign the same address
// in different subnets.
@ -698,10 +730,15 @@ GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id, bool prefix) {
HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::4", id, prefix);
// ... and add them to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
ASSERT_NO_THROW(hdsptr_->add(host3));
ASSERT_NO_THROW(hdsptr_->add(host4));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host3));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host4));
EXPECT_TRUE(added);
// Are we talking about addresses or prefixes?
uint8_t len = prefix ? 64 : 128;
@ -741,10 +778,15 @@ GenericHostDataSourceTest::testGetBySubnetIPv6() {
HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8:4::", Host::IDENT_DUID, true);
// ... and add them to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
ASSERT_NO_THROW(hdsptr_->add(host3));
ASSERT_NO_THROW(hdsptr_->add(host4));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host3));
EXPECT_TRUE(added);
ASSERT_NO_THROW(added = hdsptr_->add(host4));
EXPECT_TRUE(added);
// And then try to retrieve them back.
ConstHostPtr from_hds1 = hdsptr_->get6(host1->getIPv6SubnetID(), IOAddress("2001:db8:1::"));
@ -774,7 +816,9 @@ GenericHostDataSourceTest::testAddDuplicate6WithSameDUID() {
HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, true);
// Add this reservation once.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Then try to add it again, it should throw an exception.
ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
@ -789,7 +833,9 @@ GenericHostDataSourceTest::testAddDuplicate6WithSameHWAddr() {
HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_HWADDR, true);
// Add this reservation once.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Then try to add it again, it should throw an exception.
ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
@ -804,7 +850,9 @@ GenericHostDataSourceTest::testAddDuplicate4() {
HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_DUID);
// Add this reservation once.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Then try to add it again, it should throw an exception.
ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
@ -818,7 +866,8 @@ GenericHostDataSourceTest::testAddDuplicate4() {
// Modify address to avoid its duplication and make sure
// we can now add the host.
ASSERT_NO_THROW(host->setIPv4Reservation(IOAddress("192.0.2.3")));
EXPECT_NO_THROW(hdsptr_->add(host));
EXPECT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
}
void
@ -834,7 +883,9 @@ GenericHostDataSourceTest::testAddr6AndPrefix() {
host->addReservation(resv);
// Add this reservation
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Get this host by DUID
ConstHostPtr from_hds =
@ -868,7 +919,9 @@ GenericHostDataSourceTest::testMultipleReservations() {
host->addReservation(resv3);
host->addReservation(resv4);
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
ConstHostPtr from_hds = hdsptr_->get6(IOAddress("2001:db8::1"), len);
@ -915,7 +968,9 @@ void GenericHostDataSourceTest::testOptionsReservations4(const bool formatted,
// Add a bunch of DHCPv4 and DHCPv6 options for the host.
ASSERT_NO_THROW(addTestOptions(host, formatted, DHCP4_ONLY, user_context));
// Insert host and the options into respective tables.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Subnet id will be used in queries to the database.
SubnetID subnet_id = host->getIPv4SubnetID();
@ -943,7 +998,9 @@ void GenericHostDataSourceTest::testOptionsReservations6(const bool formatted,
// Add a bunch of DHCPv4 and DHCPv6 options for the host.
ASSERT_NO_THROW(addTestOptions(host, formatted, DHCP6_ONLY, user_context));
// Insert host, options and IPv6 reservations into respective tables.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Subnet id will be used in queries to the database.
SubnetID subnet_id = host->getIPv6SubnetID();
@ -965,7 +1022,9 @@ GenericHostDataSourceTest::testOptionsReservations46(const bool formatted) {
// Add a bunch of DHCPv4 and DHCPv6 options for the host.
ASSERT_NO_THROW(addTestOptions(host, formatted, DHCP4_AND_DHCP6));
// Insert host, options and IPv6 reservations into respective tables.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// getAll(identifier_type, identifier, identifier_size)
ConstHostCollection hosts_by_id =
@ -990,7 +1049,9 @@ GenericHostDataSourceTest::testMultipleClientClasses4() {
}
// Add the host.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Subnet id will be used in queries to the database.
SubnetID subnet_id = host->getIPv4SubnetID();
@ -1055,7 +1116,9 @@ GenericHostDataSourceTest::testMultipleClientClasses6() {
}
// Add the host.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Subnet id will be used in queries to the database.
SubnetID subnet_id = host->getIPv6SubnetID();
@ -1124,7 +1187,9 @@ GenericHostDataSourceTest::testMultipleClientClassesBoth() {
}
// Add the host.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Subnet id will be used in queries to the database.
SubnetID subnet_id = host->getIPv6SubnetID();
@ -1153,7 +1218,9 @@ GenericHostDataSourceTest::testMessageFields4() {
});
// Add the host.
ASSERT_NO_THROW(hdsptr_->add(host));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host));
EXPECT_TRUE(added);
// Subnet id will be used in queries to the database.
SubnetID subnet_id = host->getIPv4SubnetID();
@ -1282,7 +1349,9 @@ void GenericHostDataSourceTest::testDeleteByAddr4() {
SubnetID subnet1 = host1->getIPv4SubnetID();
// ... and add it to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
// And then try to retrieve it back.
ConstHostPtr before = hdsptr_->get4(subnet1, IOAddress("192.0.2.1"));
@ -1309,7 +1378,9 @@ void GenericHostDataSourceTest::testDeleteById4() {
SubnetID subnet1 = host1->getIPv4SubnetID();
// ... and add it to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
// And then try to retrieve it back.
ConstHostPtr before = hdsptr_->get4(subnet1,
@ -1350,7 +1421,9 @@ void GenericHostDataSourceTest::testDeleteById4Options() {
SubnetID subnet1 = host1->getIPv4SubnetID();
// ... and add it to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
// There must be some options
EXPECT_NE(0, countDBOptions4());
@ -1391,7 +1464,9 @@ void GenericHostDataSourceTest::testDeleteById6() {
SubnetID subnet1 = host1->getIPv6SubnetID();
// ... and add it to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
// And then try to retrieve it back.
ConstHostPtr before = hdsptr_->get6(subnet1,
@ -1427,7 +1502,9 @@ void GenericHostDataSourceTest::testDeleteById6Options() {
ASSERT_NO_THROW(addTestOptions(host1, true, DHCP6_ONLY));
// ... and add it to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
// Check that the options are stored...
EXPECT_NE(0, countDBOptions6());
@ -1475,7 +1552,9 @@ GenericHostDataSourceTest::testMultipleHostsNoAddress4() {
host1->setIPv4SubnetID(1);
host1->setIPv6SubnetID(0);
// Add the host to the database.
ASSERT_NO_THROW(hdsptr_->add(host1));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
// An attempt to add this host again should fail due to client identifier
// duplication.
@ -1487,7 +1566,8 @@ GenericHostDataSourceTest::testMultipleHostsNoAddress4() {
HostPtr host2 = HostDataSourceUtils::initializeHost4("0.0.0.0", Host::IDENT_HWADDR);
host2->setIPv4SubnetID(1);
host2->setIPv6SubnetID(0);
ASSERT_NO_THROW(hdsptr_->add(host2));
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
}
void
@ -1500,7 +1580,9 @@ GenericHostDataSourceTest::testMultipleHosts6() {
host1->setIPv4SubnetID(0);
host1->setIPv6SubnetID(1);
// Add the host to the database.
ASSERT_NO_THROW(hdsptr_->add(host1));
bool added = false;
ASSERT_NO_THROW(added = hdsptr_->add(host1));
EXPECT_TRUE(added);
// An attempt to add this host again should fail due to client identifier
// duplication.
@ -1510,7 +1592,8 @@ GenericHostDataSourceTest::testMultipleHosts6() {
host2->setIPv4SubnetID(0);
host2->setIPv6SubnetID(1);
// Add the host to the database.
ASSERT_NO_THROW(hdsptr_->add(host2));
ASSERT_NO_THROW(added = hdsptr_->add(host2));
EXPECT_TRUE(added);
}
} // namespace test

View File

@ -0,0 +1,233 @@
// Copyright (C) 2018 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <dhcpsrv/testutils/memory_host_data_source.h>
using namespace std;
namespace isc {
namespace dhcp {
namespace test {
ConstHostCollection
MemHostDataSource::getAll(const HWAddrPtr& /*hwaddr*/,
const DuidPtr& /*duid*/) const {
return (ConstHostCollection());
}
ConstHostCollection
MemHostDataSource::getAll(const Host::IdentifierType& /*identifier_type*/,
const uint8_t* /*identifier_begin*/,
const size_t /*identifier_len*/) const {
return (ConstHostCollection());
}
ConstHostCollection
MemHostDataSource::getAll4(const asiolink::IOAddress& /*address*/) const {
return (ConstHostCollection());
}
ConstHostPtr
MemHostDataSource::get4(const SubnetID& /*subnet_id*/,
const HWAddrPtr& /*hwaddr*/,
const DuidPtr& /*duid*/) const {
return (ConstHostPtr());
}
ConstHostPtr
MemHostDataSource::get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
for (auto h = store_.begin(); h != store_.end(); ++h) {
// If either subnet-id or identifier type do not match,
// it's not our host
if (((*h)->getIPv4SubnetID() != subnet_id) ||
((*h)->getIdentifierType() != identifier_type)) {
continue;
}
// If the identifier matches, we found it!
if ((*h)->getIdentifier() == ident) {
return (*h);
}
}
// Nothing found
return (ConstHostPtr());
}
ConstHostPtr
MemHostDataSource::get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const {
vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
for (auto h = store_.begin(); h != store_.end(); ++h) {
// If either subnet-id or identifier type do not match,
// it's not our host
if (((*h)->getIPv6SubnetID() != subnet_id) ||
((*h)->getIdentifierType() != identifier_type)) {
continue;
}
// If the identifier matches, we found it!
if ((*h)->getIdentifier() == ident) {
return (*h);
}
}
return (ConstHostPtr());
}
ConstHostPtr
MemHostDataSource::get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
for (auto h = store_.begin(); h != store_.end(); ++h) {
if ((*h)->getIPv4SubnetID() == subnet_id &&
(*h)->getIPv4Reservation() == address) {
return (*h);
}
}
return (ConstHostPtr());
}
ConstHostPtr
MemHostDataSource::get6(const SubnetID& /*subnet_id*/,
const DuidPtr& /*duid*/,
const HWAddrPtr& /*hwaddr*/) const {
return (ConstHostPtr());
}
ConstHostPtr
MemHostDataSource::get6(const asiolink::IOAddress& /*prefix*/,
const uint8_t /*prefix_len*/) const {
return (ConstHostPtr());
}
ConstHostPtr
MemHostDataSource::get6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
for (auto h = store_.begin(); h != store_.end(); ++h) {
// Naive approach: check hosts one by one
// First check: subnet-id must match.
if ((*h)->getIPv6SubnetID() != subnet_id) {
// wrong subnet-id? ok, skip this one
continue;
}
// Second check: the v6 reservation must much. This is very simple
// as we ignore the reservation type.
auto resrvs = (*h)->getIPv6Reservations();
for (auto r = resrvs.first; r != resrvs.second; ++r) {
if ((*r).second.getPrefix() == address) {
return (*h);
}
}
}
return (ConstHostPtr());
}
bool
MemHostDataSource::add(const HostPtr& host) {
store_.push_back(host);
return (true);
}
bool
MemHostDataSource::del(const SubnetID& subnet_id,
const asiolink::IOAddress& addr) {
for (auto h = store_.begin(); h != store_.end(); ++h) {
if (addr.isV4()) {
if ((*h)->getIPv4SubnetID() == subnet_id &&
(*h)->getIPv4Reservation() == addr) {
store_.erase(h);
return (true);
}
} else {
if ((*h)->getIPv6SubnetID() != subnet_id) {
continue;
}
// Second check: the v6 reservation must much. This is very simple
// as we ignore the reservation type.
auto resrvs = (*h)->getIPv6Reservations();
for (auto r = resrvs.first; r != resrvs.second; ++r) {
if ((*r).second.getPrefix() == addr) {
store_.erase(h);
return (true);
}
}
}
}
return (false);
}
bool
MemHostDataSource::del4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) {
vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
for (auto h = store_.begin(); h != store_.end(); ++h) {
// If either subnet-id or identifier type do not match,
// it's not our host
if (((*h)->getIPv4SubnetID() != subnet_id) ||
((*h)->getIdentifierType() != identifier_type)) {
continue;
}
// If the identifier matches, we found it!
if ((*h)->getIdentifier() == ident) {
store_.erase(h);
return (true);
}
}
return (false);
}
bool
MemHostDataSource::del6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) {
vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
for (auto h = store_.begin(); h != store_.end(); ++h) {
// If either subnet-id or identifier type do not match,
// it's not our host
if (((*h)->getIPv6SubnetID() != subnet_id) ||
((*h)->getIdentifierType() != identifier_type)) {
continue;
}
// If the identifier matches, we found it!
if ((*h)->getIdentifier() == ident) {
store_.erase(h);
return (true);
}
}
return (false);
}
size_t
MemHostDataSource::size() const {
return (store_.size());
}
BaseHostDataSource*
memFactory(const DatabaseConnection::ParameterMap& /*parameters*/) {
return (new MemHostDataSource());
}
} // namespace isc::dhcp::test
} // namespace isc::dhcp
} // namespace isc

View File

@ -0,0 +1,235 @@
// Copyright (C) 2018 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef MEMORY_HOST_DATA_SOURCE_H
#define MEMORY_HOST_DATA_SOURCE_H
#include <dhcpsrv/host_data_source_factory.h>
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
namespace isc {
namespace dhcp {
namespace test {
/// @brief Simple host data source implementation for tests.
///
/// It used vector<HostPtr> as a storage and iterates through all hosts when
/// conducting operations. Most operations are skeleton methods that don't
/// work, just several are implemented. Those are used in the tests.
class MemHostDataSource : public virtual BaseHostDataSource {
public:
/// @brief Destructor.
virtual ~MemHostDataSource() { }
/// BaseHostDataSource methods.
/// @brief Return all hosts for the specified HW address or DUID.
///
/// @param hwaddr HW address of the client or NULL if no HW address
/// available.
/// @param duid client id or NULL if not available, e.g. DHCPv4 client case.
/// @return Empty collection of const @c Host objects.
virtual ConstHostCollection
getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
/// @brief Return all hosts connected to any subnet for which reservations
/// have been made using a specified identifier.
///
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return Empty collection of const @c Host objects.
virtual ConstHostCollection
getAll(const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Returns a collection of hosts using the specified IPv4 address.
///
/// @param address IPv4 address for which the @c Host object is searched.
/// @return Empty collection of const @c Host objects.
virtual ConstHostCollection
getAll4(const asiolink::IOAddress& address) const;
/// @brief Returns a host connected to the IPv4 subnet.
///
/// @param subnet_id Subnet identifier.
/// @param hwaddr HW address of the client or NULL if no HW address
/// available.
/// @param duid client id or NULL if not available.
/// @return Const @c Host object using a specified HW address or DUID.
virtual ConstHostPtr
get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
const DuidPtr& duid = DuidPtr()) const;
/// @brief Returns a host connected to the IPv4 subnet.
///
/// @param subnet_id Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return Const @c Host object for which reservation has been made using
/// the specified identifier.
virtual ConstHostPtr
get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Returns a host connected to the IPv4 subnet and having
/// a reservation for a specified IPv4 address.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv4 address.
/// @return Const @c Host object using a specified IPv4 address.
virtual ConstHostPtr
get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const;
/// @brief Returns a host connected to the IPv6 subnet.
///
/// @param subnet_id Subnet identifier.
/// @param hwaddr HW address of the client or NULL if no HW address
/// available.
/// @param duid DUID or NULL if not available.
/// @return Const @c Host object using a specified HW address or DUID.
virtual ConstHostPtr
get6(const SubnetID& subnet_id, const DuidPtr& duid,
const HWAddrPtr& hwaddr = HWAddrPtr()) const;
/// @brief Returns a host connected to the IPv6 subnet.
///
/// @param subnet_id Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return Const @c Host object for which reservation has been made using
/// the specified identifier.
virtual ConstHostPtr
get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Returns a host using the specified IPv6 prefix.
///
/// @param prefix IPv6 prefix for which the @c Host object is searched.
/// @param prefix_len IPv6 prefix length.
/// @return Const @c Host object using a specified HW address or DUID.
virtual ConstHostPtr
get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
/// @brief Returns a host connected to the IPv6 subnet and having
/// a reservation for a specified IPv6 address or prefix.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv6 address/prefix.
/// @return Const @c Host object using a specified IPv6 address/prefix.
virtual ConstHostPtr
get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
/// @brief Adds a new host to the collection.
///
/// @param host Pointer to the new @c Host object being added.
/// @return true if addition was successful.
virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by (subnet-id, address)
///
/// @param subnet_id subnet identifier.
/// @param addr specified address.
/// @return true if deletion was successful, false if the host was not there.
/// @throw various exceptions in case of errors
virtual bool del(const SubnetID& subnet_id, const asiolink::IOAddress& addr);
/// @brief Attempts to delete a host by (subnet-id4, identifier, identifier-type)
///
/// @param subnet_id IPv4 Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return true if deletion was successful, false if the host was not there.
/// @throw various exceptions in case of errors
virtual bool del4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const size_t identifier_len);
/// @brief Attempts to delete a host by (subnet-id6, identifier, identifier-type)
///
/// @param subnet_id IPv6 Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return true if deletion was successful, false if the host was not there.
/// @throw various exceptions in case of errors
virtual bool del6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const size_t identifier_len);
/// @brief Return backend type
///
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
///
/// @return Type of the backend.
virtual std::string getType() const {
return ("mem");
}
/// More lease backend?
/// @brief Returns name of the database or file used by the backend
/// @return "mem" string"
virtual std::string getName() const {
return (std::string("mem"));
}
/// @brief Returns description of the backend.
/// @return description
virtual std::string getDescription() const {
return (std::string("In memory storage, mostly useful for testing."));
}
/// @brief Returns version this backend
/// @return two numbers that each represent practical value of this backend.
virtual std::pair<uint32_t, uint32_t> getVersion() const {
return (std::make_pair(0,0));
}
/// @brief Returns store size.
/// @return number of hosts in the store.
virtual size_t size() const;
protected:
// This is very simple storage.
/// @brief Store
std::vector<HostPtr> store_;
};
/// Pointer to the Mem host data source.
typedef boost::shared_ptr<MemHostDataSource> MemHostDataSourcePtr;
/// @brief Factory function.
///
/// @param parameters
/// @return A pointer to a base host data source instance.
BaseHostDataSource*
memFactory(const DatabaseConnection::ParameterMap& /*parameters*/);
} // namespace isc::dhcp::test
} // namespace isc::dhcp
} // namespace isc
#endif