Commit b9e65257 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac5396' (docs for shared network commands)

parents f2e69ea3 c6efaa83
// This is and example configuration for iPXE boot in Kea6.
// This is an example configuration for iPXE boot in Kea6.
{
"Dhcp6": {
// mandatory part of the config that list interfaces on which
// kea will listen to incoming traffic
// Mandatory part of the config that list interfaces on which
// Kea will listen for incoming traffic.
"interfaces-config": {
"interfaces": [
"ethX"
]
"interfaces": [ "ethX" ]
},
// Two classes are migrated form ISC-DHCP example:
......
......@@ -175,7 +175,7 @@
the form:
<screen>
{
"result": 0|1,
"result": 0|1|2|3,
"text": "textual description",
"arguments": {
"argument1": "value1",
......@@ -185,14 +185,26 @@
}
</screen>
<command>result</command> indicates the outcome of the command. A value of 0
means success while any non-zero value designates an error. Currently 1 is
used as a generic error, but additional error codes may be added in the
future. The <command>text</command> field typically appears when result is
non-zero and contains a description of the error encountered, but it may
also appear for successful results (that is command specific).
<command>arguments</command> is a map of additional data values returned by
the server which is specific to the command issued. The map is always present, even
if it contains no data values.</para>
means success while any non-zero value designates an error or at least a
failure to complete the requested action. Currently 1 is used as a generic
error, 2 means that a command is not supported and 3 means that the
requested operation was completed, but the requested object was not
found. Additional error codes may be added in the future. For example a well
formed command that requests a subnet that exists in server's configuration
would return result 0. If the server encounters an error condition, it would
return 1. If the command was asking for IPv6 subnet, but was sent to DHCPv4
server, it would return 2. If the query was asking for a subnet-id and there
is no subnet with such id, the result would be set to 3.</para>
<para>
The <command>text</command> field typically appears when result is non-zero
and contains a description of the error encountered, but it often also appears
for successful outcomes. The exact text is command specific, but in general
uses plain English to describe the outcome of the command.
<command>arguments</command> is a map of additional data values
returned by the server which is specific to the command issued. The map is
may be present, but that depends on specific command.
</para>
<note>
<simpara>
......@@ -211,7 +223,7 @@
<para>Kea development team is actively working on providing client applications
which can be used to control the servers. These applications are, however, in the
early stages of development and as of Kea 1.2.0 release have certain limitations.
The easiest way to start playing with the control API is to use common Unix/Linux tools
The easiest way to start interacting with the control API is to use common Unix/Linux tools
such as <command>socat</command> and <command>curl</command>.</para>
<para>In order to control the given Kea service via unix domain socket, use
......@@ -222,14 +234,16 @@ $ socat UNIX:/path/to/the/kea/socket -
where <command>/path/to/the/kea/socket</command> is the path specified in the
<command>Dhcp4/control-socket/socket-name</command> parameter in the Kea
configuration file. Text passed to <command>socat</command>
will be sent to Kea and the responses received from Kea printed to standard output.</para>
will be sent to Kea and the responses received from Kea printed to standard
output. This approach communicates with the specific server directly and
bypasses Control Agent.</para>
<para>It is also easy to open UNIX socket programmatically. An example of
such a simplistic client written in C is available in the Kea Developer's
Guide, chapter Control Channel Overview, section Using Control Channel.</para>
<para>In order to use Kea's RESTful API with <command>curl</command> try the
following:
<para>In order to use Kea's RESTful API with <command>curl</command> you may
use the following:
<screen>
$ curl -X POST -H "Content-Type: application/json" -d '{ "command": "config-get", "service": [ "dhcp4" ] }' http://ca.example.org:8000/
</screen>
......
......@@ -1721,12 +1721,15 @@ An example IPv4 lease deletion by "hw-address" looks as follows:
<title>subnet_cmds: Subnet Commands</title>
<para>
This section describes a hook application that offers a number of new
commands used to query and manipulate subnet configurations in Kea.
This application is very useful in deployments with a large number of
subnets being managed by the DHCP servers and when the subnets are
frequently updated. The commands offer lightweight approach for
manipulating subnets without a need to fully reconfigure the server
and without affecting existing servers' configurations.
commands used to query and manipulate subnet and shared network
configurations in Kea. This application is very useful in deployments
with a large number of subnets being managed by the DHCP servers and
when the subnets are frequently updated. The commands offer
lightweight approach for manipulating subnets without a need to fully
reconfigure the server and without affecting existing servers'
configurations. An ability to manage shared networks (listing,
retrieving details, adding new ones, removing existing ones, adding
subnets to and removing from shared networks) is also provided.
</para>
<para>Currently this library is only available to ISC customers with a
......@@ -1740,7 +1743,7 @@ An example IPv4 lease deletion by "hw-address" looks as follows:
</listitem>
<listitem>
<simpara>
<command>subnet4-get/subnet6-get</command>: retrieves detailed information about a selected subnet
<command>subnet4-get/subnet6-get</command>: retrieves detailed information about a specified subnet
</simpara>
</listitem>
<listitem>
......@@ -1753,6 +1756,45 @@ An example IPv4 lease deletion by "hw-address" looks as follows:
<command>subnet4-del/subnet6-del</command>: removes a subnet from the server's configuration
</simpara>
</listitem>
<listitem>
<simpara>
<command>network4-list/network6-list</command>: lists all configured
shared networks
</simpara>
</listitem>
<listitem>
<simpara>
<command>network4-get/network6-get</command>: retrieves detailed
information about specified shared network
</simpara>
</listitem>
<listitem>
<simpara>
<command>network4-add/network6-add</command>: adds a new shared
network to the server's configuration
</simpara>
</listitem>
<listitem>
<simpara>
<command>network4-del/network6-del</command>: removes a shared
network from the server's configuration
</simpara>
</listitem>
<listitem>
<simpara>
<command>network4-subnet-add/network6-subnet-add</command>: adds
existing subnet to existing shared network
</simpara>
</listitem>
<listitem>
<simpara>
<command>network4-subnet-del/network6-subnet-del</command>: removes
a subnet from existing shared network and demotes it to a plain
subnet.
</simpara>
</listitem>
</itemizedlist>
</para>
......@@ -2094,6 +2136,12 @@ If the subnet exists the response will be similar to this:
new subnet. Thus, we recommend that this command is used with extreme
caution.
</para>
<para>
This command can also be used to completely delete an IPv4 subnet that
is part of a shared network. If you want to simply remove the subnet
from a shared network and keep the subnet configuration, use
<command>network4-subnet-del</command> command instead.
</para>
<para>The command has the following structure:
<screen>
......@@ -2148,6 +2196,12 @@ If the subnet exists the response will be similar to this:
new subnet. Thus, we recommend that this command is used with extreme
caution.
</para>
<para>
This command can also be used to completely delete an IPv6 subnet that
is part of a shared network. If you want to simply remove the subnet
from a shared network and keep the subnet configuration, use
<command>network6-subnet-del</command> command instead.
</para>
<para>The command has the following structure:
<screen>
......@@ -2176,8 +2230,305 @@ If the subnet exists the response will be similar to this:
</para>
</section>
<section>
<title>network4-list, network6-list commands</title>
<para>
These commands are used to retrieve full list of currently configured
shared networks. The list contains only very basic information about
each shared network. If more details are needed, please use
<command>network4-get</command> or <command>network6-get</command> to
retrieve all information available. This command does not require any
parameters and its invocation is very simple:
<screen>
{
"command": "network4-list"
}
</screen>
An example response for <command>network4-list</command> looks as follows:
<screen>
{
"arguments": {
"shared-networks": [
{ "name": "floor1" },
{ "name": "office" }
]
},
"result": 0,
"text": "2 IPv4 network(s) found"
}</screen>
<command>network6-list</command> follows exactly the same syntax for
both the query and the response.
</para>
</section>
<section>
<title>network4-get, network6-get commands</title>
<para>
These commands are used to retrieve detailed information
about shared networks, including subnets currently
being part of a given network. Both commands take one
mandatory parameter <command>name</command>, which specify
the name of shared network. An example command to retrieve
details about IPv4 shared network with a name "floor13"
looks as follows:
<screen>
{
"command": "network4-get",
"arguments": {
"name": "floor13"
}
}</screen>
An example response could look as follows:
<screen>
{
"result": 0,
"text": "Info about IPv4 shared network 'floor13' returned",
"arguments": {
"shared-networks": [
{
"match-client-id": true,
"name": "floor13",
"option-data": [ ],
"rebind-timer": 90,
"relay": {
"ip-address": "0.0.0.0"
},
"renew-timer": 60,
"reservation-mode": "all",
"subnet4": [
{
"subnet": "192.0.2.0/24",
"id": 5,
// many other subnet specific details here
},
{
"id": 6,
"subnet": "192.0.3.0/31",
// many other subnet specific details here
}
],
"valid-lifetime": 120
}
]
}
}
</screen>
Note that actual response contains many additional fields that are
omitted here for clarity. The response format is exactly the same as
used in <command>config-get</command>, just is limited to returning
shared networks information.
</para>
</section>
<section>
<title>network4-add, network6-add commands</title>
<para>
These commands are used to add a new shared network. New
network has to have unique name. This command requires one parameter
<command>shared-networks</command>, which is a list and
should contain exactly one entry that defines the
network. The only mandatory element for a network is its
name. Although it does not make operational sense, it is
allowed to add an empty shared network that does not have
any subnets in it. That is allowed for testing purposes, but
having empty networks (or with only one subnet) is
discouraged in production environments. For details regarding
syntax, see <xref linkend="shared-network4"/> and <xref
linkend="shared-network6"/>.
</para>
<note><para>As opposed to parameter inheritance during full
new configuration processing, this command does not fully handle
parameter inheritance and any missing parameters will be
filled with default values, rather than inherited from
global scope.</para></note>
<para>
An example that showcases how to add a new IPv4 shared network looks
as follows:
<screen>
{
"command": "network4-add",
"arguments": {
"shared-networks": [ {
"name": "floor13",
"subnet4": [
{
"id": 100,
"pools": [ { "pool": "192.0.2.2-192.0.2.99" } ],
"subnet": "192.0.2.0/24",
"option-data": [
{
"name": "routers",
"data": "192.0.2.1"
}
]
},
{
"id": 101,
"pools": [ { "pool": "192.0.3.2-192.0.3.99" } ],
"subnet": "192.0.3.0/24",
"option-data": [
{
"name": "routers",
"data": "192.0.3.1"
}
]
} ]
} ]
}
}
</screen>
Assuming there was no shared network with a name floor13 and no subnets with id
100 and 101 previously configured, the command will be successful and will
return the following response:
<screen>
{
"arguments": {
"shared-networks": [ { "name": "floor13" } ]
},
"result": 0,
"text": "A new IPv4 shared network 'floor13' added"
}
</screen>
The <command>network6-add</command> uses the same syntax for both the query and
the response. However, there are some parameters that are IPv4-only
(e.g. match-client-id) and some are IPv6-only (e.g. interface-id). The same
applies to subnets within the network.
</para>
</section>
<section>
<title>network4-del, network6-del commands</title>
<para>
These commands are used to delete existing shared networks. Each
subnet within the network being removed will be demoted to a plain
subnet. If you want to completely remove the subnets, please use
<command>subnet4-del</command> or <command>subnet6-del</command>
commands. Both commands take exactly one parameter 'name' that
specifies the name of the network to be removed. An example invocation
of <command>network4-del</command> command looks as follows:
<screen>
{
"command": "network4-del",
"arguments": {
"name": "floor13"
}
}
</screen>
Assuming there was such a network configured, the response will look similar to
the following:
<screen>
{
"arguments": {
"shared-networks": [
{
"name": "floor1"
}
]
},
"result": 0,
"text": "IPv4 shared network 'floor13' deleted"
}</screen>
The <command>network6-del</command> command uses exactly the same syntax for
both the command and the response.
</para>
</section>
<section>
<title>network4-subnet-add, network6-subnet-add commands</title>
<para>
These commands are used to add existing subnets to existing shared
networks. There are several ways to add new shared network. System
administrator can add the whole shared network at once, either by
editing a configuration file or by calling
<command>network4-add</command> or <command>network6-add</command>
commands with desired subnets in it. This approach works better for completely
new shared subnets. However, there may be cases when an existing
subnet is running out of addresses and needs to be extended with
additional address space. In other words another subnet has to be
added on top of it. For this scenario, a system administrator can use
<command>network4-add</command> or <command>network6-add</command> and
then add existing subnet to this newly created shared network using
<command>network4-subnet-add</command> or
<command>network6-subnet-add</command>.
</para>
<para>
The <command>network4-subnet-add</command> and
<command>network6-subnet-add</command> commands take two parameters:
<command>id</command>, which is an integer and specifies subnet-id of existing subnet to
be added to a shared network; and <command>name</command>, which
specifies name of the shared network the subnet will be added to. The
subnet must not belong to any existing network. In case you want to
reassign a subnet from one shared network to another, please use
<command>network4-subnet-del</command> or
<command>network6-subnet-del</command> commands first.
</para>
<para>
An example invocation of <command>network4-subnet-add</command>
command looks as follows:
<screen>
{
"command": "network4-subnet-add",
"arguments": {
"name": "floor13",
"id": 5
}
}</screen>
Assuming there is a network named 'floor13', there is a subnet with subnet-id 5
and it is not a part of existing network, the command will return a response
similar to the following:
<screen>
{
"result": 0,
"text": "IPv4 subnet 10.0.0.0/8 (id 5) is now part of shared network 'floor1'"
}</screen>
The <command>network6-subnet-add</command> command uses exactly the same syntax for
both the command and the response.
</para>
<note><para>As opposed to parameter inheritance during full
new configuration processing or when adding a new shared network with
new subnets, this command does not fully handle
parameter inheritance and any missing parameters will be
filled with default values, rather than inherited from
global scope or from the shared network.</para></note>
</section>
<section>
<title>network4-subnet-del, network6-subnet-del commands</title>
<para>
These commands are used to remove a subnet that is part of existing shared
network and demote it to a plain, stand-alone subnet. If you want to
remove a subnet completely, use <command>subnet4-del</command> or
<command>subnet6-del</command> commands instead.
The <command>network4-subnet-del</command> and
<command>network6-subnet-del</command> commands take two parameters:
<command>id</command>, which is an integer and specifies subnet-id of
existing subnet to be removed from a shared network; and
<command>name</command>, which specifies name of the shared network
the subnet will be removed from.
</para>
<para>An example invocation of the
<command>network4-subnet-del</command> command looks as follows:
<screen>
{
"command": "network4-subnet-del",
"arguments": {
"name": "floor13",
"id": 5
}
}</screen>
Assuming there was a subnet with subnet-id equal to 5 that was part of a shared
network named 'floor13', the response would look similar to the following:
<screen>
{
"result": 0,
"text": "IPv4 subnet 10.0.0.0/8 (id 5) is now removed from shared network 'floor13'"
}</screen>
The <command>network6-subnet-del</command> command uses exactly the same syntax for
both the command and the response.
</para>
</section>
</section>
</section> <!-- end of subnet commands -->
</section> <!-- end of subnet commands -->
<section id="user-context">
<title>User contexts</title>
......
premium @ 133a3165
Subproject commit 133a3165f244adb0ed50cc3a59e3e4a86f1e10bc
......@@ -58,8 +58,11 @@ public:
auto& index = networks_.template get<SharedNetworkNameIndexTag>();
auto shared_network = index.find(name);
if (shared_network != index.end()) {
index.erase(shared_network);
// Delete all subnets from the network
(*shared_network)->delAll();
// Then delete the network from the networks list.
index.erase(shared_network);
} else {
isc_throw(BadValue, "unable to delete non-existing network '"
<< name << "' from shared networks configuration");
......
......@@ -219,6 +219,14 @@ SharedNetwork4::del(const SubnetID& subnet_id) {
clearSharedNetwork(subnet);
}
void
SharedNetwork4::delAll() {
for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
clearSharedNetwork(*subnet);
}
subnets_.clear();
}
Subnet4Ptr
SharedNetwork4::getSubnet(const SubnetID& subnet_id) const {
return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_id));
......@@ -267,6 +275,13 @@ SharedNetwork6::del(const SubnetID& subnet_id) {
clearSharedNetwork(subnet);
}
void
SharedNetwork6::delAll() {
for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
clearSharedNetwork(*subnet);
}
subnets_.clear();
}
Subnet6Ptr
SharedNetwork6::getSubnet(const SubnetID& subnet_id) const {
return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_id));
......
......@@ -86,6 +86,9 @@ public:
/// @throw BadValue When specified subnet doesn't exist.
void del(const SubnetID& subnet_id);
/// @brief Removes all subnets from a shared network.
void delAll();
/// @brief Returns a pointer to the collection of subnets within this
/// shared network.
const Subnet4Collection* getAllSubnets() const {
......@@ -217,6 +220,9 @@ public:
/// @throw BadValue When specified subnet doesn't exist.
void del(const SubnetID& subnet_id);
/// @brief Removes all subnets from a shared network.
void delAll();
/// @brief Returns a pointer to the collection of subnets within this
/// shared network.
const Subnet6Collection* getAllSubnets() const {
......
......@@ -8,10 +8,12 @@
#include <exceptions/exceptions.h>
#include <dhcpsrv/cfg_shared_networks.h>
#include <testutils/test_to_element.h>
#include <asiolink/io_address.h>
#include <gtest/gtest.h>
using namespace isc;
using namespace isc::dhcp;
using namespace asiolink;
namespace {
......@@ -62,6 +64,37 @@ TEST(CfgSharedNetworks4Test, deleteByName) {
ASSERT_THROW(cfg.del(network2->getName()), BadValue);
}
// Checks that subnets have their shared network pointers updated when
// the network is deleted. This is used when the shared network is deleted
// by admin commands.
TEST(CfgSharedNetworks4Test, deleteNetworkWithSubnets) {
CfgSharedNetworks4 cfg;
SharedNetwork4Ptr network(new SharedNetwork4("frog"));
SubnetID id1(100);
SubnetID id2(101);
Subnet4Ptr sub1(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, id1));
Subnet4Ptr sub2(new Subnet4(IOAddress("192.0.3.0"), 24, 1, 2, 3, id2));
network->add(sub1);
network->add(sub2);
cfg.add(network);
// Make sure the subnets are part of the network.
SharedNetwork4Ptr test;
sub1->getSharedNetwork(test);
EXPECT_TRUE(test);
EXPECT_EQ(network->toElement()->str(), test->toElement()->str());
sub2->getSharedNetwork(test);
EXPECT_TRUE(test);
EXPECT_EQ(network->toElement()->str(), test->toElement()->str());
// Now remove the network. Subnets should be disassociated with the network.
cfg.del("frog");
sub1->getSharedNetwork(test);
EXPECT_FALSE(test);
sub2->getSharedNetwork(test);
EXPECT_FALSE(test);
}
// This test verifies that shared networks must have unique names.
TEST(CfgSharedNetworks4Test, duplicateName) {
SharedNetwork4Ptr network1(new SharedNetwork4("frog"));
......
......@@ -7,11 +7,13 @@
#include <config.h>
#include <exceptions/exceptions.h>
#include <dhcpsrv/cfg_shared_networks.h>
#include <asiolink/io_address.h>
#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
using namespace isc;
using namespace isc::dhcp;
using namespace asiolink;
namespace {
......@@ -62,6 +64,37 @@ TEST(CfgSharedNetworks6Test, deleteByName) {
ASSERT_THROW(cfg.del(network2->getName()), BadValue);