Commit 7d4cd801 authored by Francis Dupont's avatar Francis Dupont
Browse files

[master] merging HEAD

parents 216cc297 83cf70ae
1344. [func] marcin
Implemented lease4-get-all command in lease_cmds hooks library.
(Trac #5468, git a378ec28489e98df64830d1f26c3bebd20e256b2)
1343. [func] marcin
Implemented "force-create" parameter for lease4-update and
lease6-update commands.
......
......@@ -1340,6 +1340,10 @@ An example deletion by (subnet-id, identifier-type, identifier) looks as follows
<para><command>lease4-get</command> - checks if an IPv4 lease with
the specified parameters exists and returns it if it does;</para>
</listitem>
<listitem>
<para><command>lease4-get-all</command> - returns all IPv4 leases
or IPv4 leases for specified subnets;</para>
</listitem>
<listitem>
<para><command>lease6-get</command> - checks if an IPv6 lease with
the specified parameters exists and returns it if it does;</para>
......@@ -1658,6 +1662,80 @@ An example result returned when the host was found:
</section>
<section>
<title>lease4-get-all command</title>
<para><command>lease4-get-all</command> is used to retrieve all IPv4
leases or all leases for the specified set of subnets. All leases are
returned when there are no arguments specified with the command as
in the following example:
<screen>
{
"command": "lease4-get-all"
}
</screen>
</para>
<para>If the arguments are provided, it is expected that they contain
"subnets" parameter, being a list of subnet identifiers for which the
leases should be returned, e.g.:
<screen>
{
"command": "lease4-get-all",
"arguments": {
"subnets": [ 1, 2, 3, 4 ]
}
}
</screen>
</para>
<para>
The returned response contains a detailed list of leases in the
following format:
<screen>{
"arguments": {
"leases": [
{
"client-id": "42:42:42:42:42:42:42:42",
"cltt": 12345678,
"fqdn-fwd": false,
"fqdn-rev": true,
"hostname": "myhost.example.com.",
"hw-address": "08:08:08:08:08:08",
"ip-address": "192.0.2.1",
"state": 0,
"subnet-id": 44,
"valid-lft": 3600
},
{
"client-id": "21:21:21:21:21:21:21:21",
"cltt": 12345678,
"fqdn-fwd": false,
"fqdn-rev": true,
"hostname": "",
"hw-address": "10:10:10:10:10:10",
"ip-address": "192.0.2.2",
"state": 0,
"subnet-id": 44,
"valid-lft": 3600
}
]
},
"result": 0,
"text": "2 IPv4 lease(s) found."
}</screen>
</para>
<warning>
<para>The <command>lease4-get-command</command> may result in very
large responses. This may have negative impact on the DHCP server
responsiveness while the response is generated and transmitted
over the control channel, as the server imposes no restriction
on the number of leases returned as a result of this command.
</para>
</warning>
</section>
<section>
<title>lease4-del, lease6-del commands</title>
<para><command>leaseX-del</command> can be used to delete a lease from
......
......@@ -25,6 +25,7 @@
#include <boost/bind.hpp>
#include <string>
#include <sstream>
using namespace isc::dhcp;
using namespace isc::data;
......@@ -129,6 +130,18 @@ public:
int
leaseGetHandler(CalloutHandle& handle);
/// @brief lease4-get-all command handler
///
/// This command attempts to retrieve all IPv4 leases or all IPv4 leases
/// belonging to the particular subnets. If no subnet identifiers are
/// provided, it returns all IPv4 leases from the database.
///
/// @param handle Callout context - which is expected to contain the
/// get command JSON text in the "command" argument
/// @return 0 upon success, non-zero otherwise.
int
lease4GetAllHandler(CalloutHandle& handle);
/// @brief lease4-del command handler
///
/// Provides the implementation for @ref isc::lease_cmds::LeaseCmds::lease4DelHandler
......@@ -457,6 +470,67 @@ LeaseCmdsImpl::leaseGetHandler(CalloutHandle& handle) {
return (0);
}
int
LeaseCmdsImpl::lease4GetAllHandler(CalloutHandle& handle) {
try {
extractCommand(handle);
ElementPtr leases_json = Element::createList();
// The argument may contain a list of subnets for which leases should
// be returned.
if (cmd_args_) {
ConstElementPtr subnets = cmd_args_->get("subnets");
if (subnets) {
if (subnets->getType() != Element::list) {
isc_throw(BadValue, "'subnets' parameter must be a list");
}
const std::vector<ElementPtr>& subnet_ids = subnets->listValue();
for (auto subnet_id = subnet_ids.begin(); subnet_id != subnet_ids.end();
++subnet_id) {
if ((*subnet_id)->getType() != Element::integer) {
isc_throw(BadValue, "listed subnet identifiers must be numbers");
}
Lease4Collection leases =
LeaseMgrFactory::instance().getLeases4((*subnet_id)->intValue());
for (auto lease = leases.begin(); lease != leases.end(); ++lease) {
ElementPtr lease_json = (*lease)->toElement();
leases_json->add(lease_json);
}
}
} else {
isc_throw(BadValue, "'subnets' parameter not specified");
}
} else {
// There is no 'subnets' argument so let's return all leases.
Lease4Collection leases = LeaseMgrFactory::instance().getLeases4();
for (auto lease = leases.begin(); lease != leases.end(); ++lease) {
ElementPtr lease_json = (*lease)->toElement();
leases_json->add(lease_json);
}
}
std::ostringstream s;
s << leases_json->size() << " IPv4 lease(s) found.";
ElementPtr args = Element::createMap();
args->set("leases", leases_json);
ConstElementPtr response = createAnswer((leases_json->size() == 0 ? CONTROL_RESULT_EMPTY :
CONTROL_RESULT_SUCCESS), s.str(), args);
setResponse(handle, response);
} catch (const std::exception& ex) {
setErrorResponse(handle, ex.what());
return (CONTROL_RESULT_ERROR);
}
return (0);
}
int
LeaseCmdsImpl::lease4DelHandler(CalloutHandle& handle) {
Parameters p;
......@@ -723,6 +797,11 @@ LeaseCmds::leaseGetHandler(CalloutHandle& handle) {
return(impl_->leaseGetHandler(handle));
}
int
LeaseCmds::lease4GetAllHandler(hooks::CalloutHandle& handle) {
return (impl_->lease4GetAllHandler(handle));
}
int
LeaseCmds::lease4DelHandler(CalloutHandle& handle) {
return(impl_->lease4DelHandler(handle));
......
......@@ -131,6 +131,31 @@ public:
int
leaseGetHandler(hooks::CalloutHandle& handle);
/// @brief lease4-get-all command handler
///
/// This command attempts to retrieve all IPv4 leases or all IPv4 leases
/// belonging to the particular subnets. If no subnet identifiers are
/// provided, it returns all IPv4 leases from the database.
///
/// Example command for query by (subnet-ids):
/// {
/// "command": "lease4-get-all",
/// "arguments": {
/// "subnets": [ 1, 2, 3, 4 ]
/// }
/// }
///
/// Example command for retrieving all leases:
/// {
/// "command": "lease4-get-all",
/// }
///
/// @param handle Callout context - which is expected to contain the
/// get command JSON text in the "command" argument
/// @return result of the operation.
int
lease4GetAllHandler(hooks::CalloutHandle& handle);
/// @brief lease4-del command handler
///
/// This command attempts to delete an IPv4 lease that match selected
......
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2017-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.
......@@ -53,6 +53,17 @@ int lease4_get(CalloutHandle& handle) {
return(lease_cmds.leaseGetHandler(handle));
}
/// @brief This is a command callout for 'lease4-get-all' command.
///
/// @param handle Callout handle used to retrieve a command and
/// provide a response.
/// @return 0 if this callout has been invoked successfully,
/// 1 otherwise.
int lease4_get_all(CalloutHandle& handle) {
LeaseCmds lease_cmds;
return (lease_cmds.lease4GetAllHandler(handle));
}
/// @brief This is a command callout for 'lease6-get' command.
///
/// @param handle Callout handle used to retrieve a command and
......@@ -138,6 +149,7 @@ int load(LibraryHandle& handle) {
handle.registerCommandCallout("lease4-add", lease4_add);
handle.registerCommandCallout("lease6-add", lease6_add);
handle.registerCommandCallout("lease4-get", lease4_get);
handle.registerCommandCallout("lease4-get-all", lease4_get_all);
handle.registerCommandCallout("lease6-get", lease6_get);
handle.registerCommandCallout("lease4-del", lease4_del);
handle.registerCommandCallout("lease6-del", lease6_del);
......
......@@ -260,9 +260,11 @@ public:
subnets->add(subnet6);
cfg_mgr.commit();
} else {
Subnet4Ptr subnet4(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, 44));
Subnet4Ptr subnet44(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, 44));
Subnet4Ptr subnet88(new Subnet4(IOAddress("192.0.3.0"), 24, 1, 2, 3, 88));
CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
subnets->add(subnet4);
subnets->add(subnet44);
subnets->add(subnet88);
cfg_mgr.commit();
}
......@@ -270,34 +272,43 @@ public:
if (v6) {
lmptr_->addLease(createLease6());
} else {
lmptr_->addLease(createLease4());
lmptr_->addLease(createLease4("192.0.2.1", 44, 0x08, 0x42));
lmptr_->addLease(createLease4("192.0.2.2", 44, 0x09, 0x56));
lmptr_->addLease(createLease4("192.0.3.1", 88, 0x08, 0x42));
lmptr_->addLease(createLease4("192.0.3.2", 88, 0x09, 0x56));
}
}
}
/// @brief Creates an IPv4 lease
///
/// Lease parameters: ip-address = 192.0.2.1, hwaddr = 08:08:08:08:08:08,
/// client-id = 42:42:42:42:42:42:42:42, valid lifetime = 3600,
/// cltt = 12345678, subnet-id = 44, fqdn-fwd = false, fqdn-rev = true
/// hostname = myhost.example.com
/// Lease parameters: valid lifetime = 3600, cltt = 12345678, fqdn-fwd = false,
/// fqdn-rev = true, hostname = myhost.example.com
///
/// @param ip_address IP address for the lease.
/// @param subnet_id subnet identifier
/// @param hw_address_pattern value to be used for generating HW address by repating
/// it 6 times.
/// @param client_id_pattern value to be used for generating client identifier by
/// repeating it 8 times.
/// @return Returns the lease created
Lease4Ptr createLease4() {
Lease4Ptr createLease4(const std::string& ip_address, const SubnetID& subnet_id,
const uint8_t hw_address_pattern,
const uint8_t client_id_pattern) {
Lease4Ptr lease(new Lease4());
lease->addr_ = IOAddress("192.0.2.1");
lease->addr_ = IOAddress(ip_address);
// Initialize unused fields.
lease->t1_ = 0; // Not saved
lease->t2_ = 0; // Not saved
// Set other parameters. For historical reasons, address 0 is not used.
lease->hwaddr_.reset(new HWAddr(vector<uint8_t>(6, 0x08), HTYPE_ETHER));
lease->client_id_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x42)));
lease->hwaddr_.reset(new HWAddr(vector<uint8_t>(6, hw_address_pattern), HTYPE_ETHER));
lease->client_id_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, client_id_pattern)));
lease->valid_lft_ = 3600;
lease->cltt_ = 12345678;
lease->subnet_id_ = 44;
lease->subnet_id_ = subnet_id;
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = true;
lease->hostname_ = "myhost.example.com.";
......@@ -343,6 +354,22 @@ public:
uint32_t subnet_id, std::string hwaddr,
bool client_id_required) {
ASSERT_TRUE(l);
// If the element is a list we need to retrieve the lease that
// we're interested in.
if (l->getType() == Element::list) {
std::vector<ElementPtr> e = l->listValue();
for (auto it = e.begin(); it != e.end(); ++it) {
ConstElementPtr ip_address = (*it)->get("ip-address");
if (ip_address && ip_address->stringValue() == ip) {
l = (*it);
break;
}
}
ASSERT_TRUE(l);
}
ASSERT_TRUE(l->get("ip-address"));
EXPECT_EQ(ip, l->get("ip-address")->stringValue());
......@@ -1099,6 +1126,208 @@ TEST_F(LeaseCmdsTest, Lease4GetByHWAddr) {
checkLease4(lease, "192.0.2.1", 44, "08:08:08:08:08:08", false);
}
// Checks that lease4-get-all returns all leases.
TEST_F(LeaseCmdsTest, Lease4GetAll) {
// Initialize lease manager (false = v4, true = add a lease)
initLeaseMgr(false, true);
// Query for all leases.
string cmd =
"{\n"
" \"command\": \"lease4-get-all\"\n"
"}";
string exp_rsp = "4 IPv4 lease(s) found.";
ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
// Now check that the lease parameters were indeed returned.
ASSERT_TRUE(rsp);
ConstElementPtr args = rsp->get("arguments");
ASSERT_TRUE(args);
ASSERT_EQ(Element::map, args->getType());
ConstElementPtr leases = args->get("leases");
ASSERT_TRUE(leases);
ASSERT_EQ(Element::list, leases->getType());
// Let's check if the response contains desired leases.
checkLease4(leases, "192.0.2.1", 44, "08:08:08:08:08:08", true);
checkLease4(leases, "192.0.2.2", 44, "09:09:09:09:09:09", true);
checkLease4(leases, "192.0.3.1", 88, "08:08:08:08:08:08", true);
checkLease4(leases, "192.0.3.2", 88, "09:09:09:09:09:09", true);
}
// Checks that lease4-get-all returns empty set if no leases are found.
TEST_F(LeaseCmdsTest, Lease4GetAllNoLeases) {
// Initialize lease manager (false = v4, false = do not add leasesxs)
initLeaseMgr(false, false);
// Query for all leases.
string cmd =
"{\n"
" \"command\": \"lease4-get-all\"\n"
"}";
string exp_rsp = "0 IPv4 lease(s) found.";
ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
// Now check that the lease parameters were indeed returned.
ASSERT_TRUE(rsp);
ConstElementPtr args = rsp->get("arguments");
ASSERT_TRUE(args);
ASSERT_EQ(Element::map, args->getType());
ConstElementPtr leases = args->get("leases");
ASSERT_TRUE(leases);
ASSERT_EQ(Element::list, leases->getType());
EXPECT_EQ(0, leases->size());
}
// Checks that lease4-get-all returns all leases for a subnet.
TEST_F(LeaseCmdsTest, Lease4GetAllBySubnetId) {
// Initialize lease manager (false = v4, true = add leases)
initLeaseMgr(false, true);
// Query for leases from subnet 44. Subnet 127 will be ignored because
// it doesn't contain any leases.
string cmd =
"{\n"
" \"command\": \"lease4-get-all\",\n"
" \"arguments\": {\n"
" \"subnets\": [ 44, 127 ]"
" }\n"
"}";
string exp_rsp = "2 IPv4 lease(s) found.";
ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
// Now check that the lease parameters were indeed returned.
ASSERT_TRUE(rsp);
ConstElementPtr args = rsp->get("arguments");
ASSERT_TRUE(args);
ASSERT_EQ(Element::map, args->getType());
ConstElementPtr leases = args->get("leases");
ASSERT_TRUE(leases);
ASSERT_EQ(Element::list, leases->getType());
// Let's check if the response contains desired leases.
checkLease4(leases, "192.0.2.1", 44, "08:08:08:08:08:08", true);
checkLease4(leases, "192.0.2.2", 44, "09:09:09:09:09:09", true);
}
// Checks that lease4-get-all returns empty set when no leases are found.
TEST_F(LeaseCmdsTest, Lease4GetAllBySubnetIdNoLeases) {
// Initialize lease manager (false = v4, true = do not add leases)
initLeaseMgr(false, false);
// Query for leases from subnet 44. Subnet 127 will be ignored because
// it doesn't contain any leases.
string cmd =
"{\n"
" \"command\": \"lease4-get-all\",\n"
" \"arguments\": {\n"
" \"subnets\": [ 44, 127 ]"
" }\n"
"}";
string exp_rsp = "0 IPv4 lease(s) found.";
ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
// Now check that the lease parameters were indeed returned.
ASSERT_TRUE(rsp);
ConstElementPtr args = rsp->get("arguments");
ASSERT_TRUE(args);
ASSERT_EQ(Element::map, args->getType());
ConstElementPtr leases = args->get("leases");
ASSERT_TRUE(leases);
ASSERT_EQ(Element::list, leases->getType());
EXPECT_EQ(0, leases->size());
}
// Checks that lease4-get-all returns leases from multiple subnets.
TEST_F(LeaseCmdsTest, Lease4GetAllByMultipleSubnetIds) {
// Initialize lease manager (false = v4, true = add a lease)
initLeaseMgr(false, true);
// Query for leases from subnet 44 and 88.
string cmd =
"{\n"
" \"command\": \"lease4-get-all\",\n"
" \"arguments\": {\n"
" \"subnets\": [ 44, 88 ]"
" }\n"
"}";
string exp_rsp = "4 IPv4 lease(s) found.";
ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
// Now check that the lease parameters were indeed returned.
ASSERT_TRUE(rsp);
ConstElementPtr args = rsp->get("arguments");
ASSERT_TRUE(args);
ASSERT_EQ(Element::map, args->getType());
ConstElementPtr leases = args->get("leases");
ASSERT_TRUE(leases);
ASSERT_EQ(Element::list, leases->getType());
// Let's check if the response contains desired leases.
checkLease4(leases, "192.0.2.1", 44, "08:08:08:08:08:08", true);
checkLease4(leases, "192.0.2.2", 44, "09:09:09:09:09:09", true);
checkLease4(leases, "192.0.3.1", 88, "08:08:08:08:08:08", true);
checkLease4(leases, "192.0.3.2", 88, "09:09:09:09:09:09", true);
}
// Checks that lease4-get-all checks its input arguments.
TEST_F(LeaseCmdsTest, Lease4GetBySubnetIdInvalidArguments) {
// Initialize lease manager (false = v4, true = add a lease)
initLeaseMgr(false, true);
// Subnets not specified in arguments.
string cmd =
"{\n"
" \"command\": \"lease4-get-all\",\n"
" \"arguments\": {"
" \"foo\": 1\n"
" }\n"
"}";
string exp_rsp = "'subnets' parameter not specified";
testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
// Subnets are not a list.
cmd =
"{\n"
" \"command\": \"lease4-get-all\",\n"
" \"arguments\": {"
" \"subnets\": 1\n"
" }\n"
"}";
exp_rsp = "'subnets' parameter must be a list";
testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
// Subnets list must contain numbers.
cmd =
"{\n"
" \"command\": \"lease4-get-all\",\n"
" \"arguments\": {"
" \"subnets\": [ \"x\", \"y\" ]\n"
" }\n"
"}";
exp_rsp = "listed subnet identifiers must be numbers";
testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
}
// Checks that lease6-get(addr) can handle a situation when
// the query is correctly formed, but the lease is not there.
TEST_F(LeaseCmdsTest, Lease6GetByAddr6NotFound) {
......@@ -2224,7 +2453,7 @@ TEST_F(LeaseCmdsTest, Lease4Wipe) {
" \"subnet-id\": 44"
" }\n"
"}";
string exp_rsp = "Deleted 1 IPv4 lease(s).";
string exp_rsp = "Deleted 2 IPv4 lease(s).";
testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
// Make sure the lease is really gone.
......
// Copyright (C) 2015-2017 Deutsche Telekom AG.
// Copyright (C) 2015-2018 Deutsche Telekom AG.
//
// Authors: Razvan Becheriu <razvan.becheriu@qualitance.com>
// Andrei Pavel <andrei.pavel@qualitance.com>
......@@ -1620,6 +1620,16 @@ CqlLeaseMgr::getLease4(const ClientId &clientid, SubnetID subnet_id) const {
return (result);
}
Lease4Collection
CqlLeaseMgr::getLeases4(SubnetID) const {
isc_throw(NotImplemented, "getLeases4(subnet_id) is not implemented");
}
Lease4Collection
CqlLeaseMgr::getLeases4() const {
isc_throw(NotImplemented, "getLeases4() is not implemented");
}
Lease6Ptr