From: Francis Dupont Date: Fri, 22 Jun 2018 09:37:22 +0000 (+0200) Subject: [5584] Checkpoint: more updates X-Git-Tag: trac5685_base~2^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b14d388e5477322cb7597ab64dd8ffa0bd4a931e;p=thirdparty%2Fkea.git [5584] Checkpoint: more updates --- diff --git a/doc/guide/hooks.xml b/doc/guide/hooks.xml index dd2177d253..85532eaa3b 100644 --- a/doc/guide/hooks.xml +++ b/doc/guide/hooks.xml @@ -475,6 +475,8 @@ $ ls -l /usr/local/lib/hooks/*.so errors, like adding a lease with subnet-id that does not exist in the configuration or configuring a lease to use an address that is outside of the subnet to which it is supposed to belong. + It provides a not programmatic way to manage user contexts + associated to leases. @@ -720,7 +722,7 @@ path/base-name.CCYYMMDD.txt An entry is a single string with no embedded end-of-line markers, a prepended timestamp and has the following sections: -timestamp address duration device-id {client-info} {relay-info} +timestamp address duration device-id {client-info} {relay-info} {user-context} @@ -754,6 +756,9 @@ timestamp address duration device-id {client-info} {relay-info} options: 1, 2 and 6) if present. The circuit id and remote id are presented as hex strings + + user-context - the optional user context associated to the lease. + @@ -835,7 +840,7 @@ with hardware address: 1a:1b:1c:1d:1e:1f, client-id: 1234567890 An entry is a single string with no embedded end-of-line markers, a prepended timestamp and has the following sections: -timestamp address duration device-id {relay-info}* +timestamp address duration device-id {relay-info}* {user-context} @@ -868,6 +873,9 @@ timestamp address duration device-id {relay-info}* topology. Nevertheless, this is useful information to better scope down the location of the device, so it is being recorded, if present. + + user-context - the optional user context associated to the lease. + @@ -1063,20 +1071,7 @@ Examples: Please refer to for MySQL, to for PostgreSQL or to for Cassandra CQL. - Scripts are in - path-to-kea/share/kea/legal_log/scripts directory, for instance the PostgreSQL create schema - command is: - -$ psql -d database-name -U user-name -f path-to-kea/share/kea/legal_log/scripts/pgsql/legldb_create.pgsql -Password for user user-name: -START TRANSACTION -CREATE TABLE -CREATE INDEX -CREATE TABLE -INSERT 0 1 -COMMIT -$ - + The logs table is part of the Kea database schemas. Configuration parameters are extended by standard lease database @@ -1671,6 +1666,8 @@ An example deletion by (subnet-id, identifier-type, identifier) looks as follows errors, like adding a lease with subnet-id that does not exist in the configuration or configuring a lease to use an address that is outside of the subnet to which it is supposed to belong. + It provides a not programmatic way to manage user contexts + associated to leases. This library may only be loaded by kea-dhcp4 @@ -1875,6 +1872,11 @@ The commands can take a number of additional optional parameters: configured for the subnet corresponding to the specified subnet-id is used. This parameter is not used in IPv4. + + user-context - specifies the user + context to be associated with this lease. It must be a + JSON map. + @@ -1894,7 +1896,8 @@ The commands can take a number of additional optional parameters: "expire": 12345678, "fqdn-fwd": true, "fqdn-rev": true, - "hostname": "urania.example.org" + "hostname": "urania.example.org", + "user-context": { "version": 1 } } } @@ -3136,6 +3139,7 @@ both the command and the response. host reservations, control socket, dhcp ddns, loggers and server id. These are supported in both DHCPv4 and DHCPv6 at the exception of server id which is DHCPv6 only. + Kea 1.5 added user contexts assocated with leases. diff --git a/src/bin/lfc/tests/lfc_controller_unittests.cc b/src/bin/lfc/tests/lfc_controller_unittests.cc index c0d9e7d29e..898056d5b9 100644 --- a/src/bin/lfc/tests/lfc_controller_unittests.cc +++ b/src/bin/lfc/tests/lfc_controller_unittests.cc @@ -84,11 +84,11 @@ protected: cstr_ = base_dir + "/" + "config_file"; // config v4_hdr_ = "address,hwaddr,client_id,valid_lifetime,expire,subnet_id," - "fqdn_fwd,fqdn_rev,hostname,state\n"; + "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"; v6_hdr_ = "address,duid,valid_lifetime,expire,subnet_id," "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd," - "fqdn_rev,hostname,hwaddr,state\n"; + "fqdn_rev,hostname,hwaddr,state,user_context\n"; // and remove any outstanding test files removeTestFile(); @@ -398,27 +398,27 @@ TEST_F(LFCControllerTest, launch4) { // We have several entries for different leases, the naming is: // _ string a_1 = "192.0.2.1,06:07:08:09:0a:bc,," - "200,200,8,1,1,host.example.com,1\n"; + "200,200,8,1,1,host.example.com,1,\n"; string a_2 = "192.0.2.1,06:07:08:09:0a:bc,," - "200,500,8,1,1,host.example.com,1\n"; + "200,500,8,1,1,host.example.com,1,\n"; string a_3 = "192.0.2.1,06:07:08:09:0a:bc,," - "200,800,8,1,1,host.example.com,1\n"; + "200,800,8,1,1,host.example.com,1,{ \"foo\": true }\n"; string b_1 = "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04," - "100,100,7,0,0,,1\n"; + "100,100,7,0,0,,1,{ \"bar\": false }\n"; string b_2 = "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04," - "100,135,7,0,0,,1\n"; + "100,135,7,0,0,,1,\n"; string b_3 = "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04," - "100,150,7,0,0,,1\n"; + "100,150,7,0,0,,1,\n"; // This one should be invalid, no hardware address and state is not declined string c_1 = "192.0.2.3,,a:11:01:04," - "200,200,8,1,1,host.example.com,0\n"; + "200,200,8,1,1,host.example.com,0,\n"; string d_1 = "192.0.2.5,16:17:18:19:1a:bc,," - "200,200,8,1,1,host.example.com,1\n"; + "200,200,8,1,1,host.example.com,1,\n"; string d_2 = "192.0.2.5,16:17:18:19:1a:bc,," - "0,200,8,1,1,host.example.com,1\n"; + "0,200,8,1,1,host.example.com,1,\n"; // Subtest 1: both previous and copy available. // Create the test previous file @@ -553,27 +553,29 @@ TEST_F(LFCControllerTest, launch6) { // We have several entries for different leases, the naming is: // _. string a_1 = "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," - "200,200,8,100,0,7,0,1,1,host.example.com,,1\n"; - string a_2 = "2001:db8:1::1,,200,200,8,100,0,7,0,1,1,host.example.com,,1\n"; + "200,200,8,100,0,7,0,1,1,host.example.com,,1,\n"; + string a_2 = "2001:db8:1::1,,200,200,8,100,0,7,0,1,1," + "host.example.com,,1,\n"; string a_3 = "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," - "200,400,8,100,0,7,0,1,1,host.example.com,,1\n"; + "200,400,8,100,0,7,0,1,1,host.example.com,,1,\n"; string a_4 = "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," - "0,200,8,100,0,7,0,1,1,host.example.com,,1\n"; + "0,200,8,100,0,7,0,1,1,host.example.com,,1," + "{ \"foo\": true }\n"; string b_1 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05," - "300,300,6,150,0,8,0,0,0,,,1\n"; + "300,300,6,150,0,8,0,0,0,,,1,{ \"bar\": false }\n"; string b_2 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05," - "300,800,6,150,0,8,0,0,0,,,1\n"; + "300,800,6,150,0,8,0,0,0,,,1,\n"; string b_3 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05," - "300,1000,6,150,0,8,0,0,0,,,1\n"; + "300,1000,6,150,0,8,0,0,0,,,1,\n"; string c_1 = "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," - "100,200,8,0,2,16,64,0,0,,,1\n"; + "100,200,8,0,2,16,64,0,0,,,1,\n"; string c_2 = "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," - "100,400,8,0,2,16,64,0,0,,,1\n"; + "100,400,8,0,2,16,64,0,0,,,1,\n"; string d_1 = "2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," - "200,600,8,100,0,7,0,1,1,host.example.com,,1\n"; + "200,600,8,100,0,7,0,1,1,host.example.com,,1,\n"; // Subtest 1: bot previous and copy available // Create the test previous file diff --git a/src/hooks/dhcp/lease_cmds/lease_parser.cc b/src/hooks/dhcp/lease_cmds/lease_parser.cc index 4a457d8a77..6198205c62 100644 --- a/src/hooks/dhcp/lease_cmds/lease_parser.cc +++ b/src/hooks/dhcp/lease_cmds/lease_parser.cc @@ -110,6 +110,13 @@ Lease4Parser::parse(ConstSrvConfigPtr& cfg, "values are: 0 (default), 1 (declined) and 2 (expired-reclaimed)"); } + // Handle user context. + ConstElementPtr ctx = lease_info->get("user-context"); + if (ctx && (ctx->getType() != Element::map)) { + isc_throw(BadValue, "Invalid user context '" << ctx->str() + << "' is not a JSON map."); + } + // Let's fabricate some data and we're ready to go. uint32_t t1 = subnet->getT1(); uint32_t t2 = subnet->getT2(); @@ -118,6 +125,7 @@ Lease4Parser::parse(ConstSrvConfigPtr& cfg, cltt, subnet_id, fqdn_fwd, fqdn_rev, hostname)); l->state_ = state; + l->setContext(ctx); // Retrieve the optional flag indicating if the lease must be created when it // doesn't exist during the update. @@ -251,6 +259,13 @@ Lease6Parser::parse(ConstSrvConfigPtr& cfg, "values are: 0 (default), 1 (declined) and 2 (expired-reclaimed)"); } + // Handle user context. + ConstElementPtr ctx = lease_info->get("user-context"); + if (ctx && (ctx->getType() != Element::map)) { + isc_throw(BadValue, "Invalid user context '" << ctx->str() + << "' is not a JSON map."); + } + // Let's fabricate some data and we're ready to go. uint32_t t1 = subnet->getT1(); uint32_t t2 = subnet->getT2(); @@ -260,6 +275,7 @@ Lease6Parser::parse(ConstSrvConfigPtr& cfg, hwaddr_ptr, prefix_len)); l->cltt_ = cltt; l->state_ = state; + l->setContext(ctx); // Retrieve the optional flag indicating if the lease must be created when it // doesn't exist during the update. diff --git a/src/hooks/dhcp/lease_cmds/lease_parser.h b/src/hooks/dhcp/lease_cmds/lease_parser.h index 8b72c0018a..2220d49933 100644 --- a/src/hooks/dhcp/lease_cmds/lease_parser.h +++ b/src/hooks/dhcp/lease_cmds/lease_parser.h @@ -29,7 +29,8 @@ namespace lease_cmds { /// "fqdn-fwd": true, /// "fqdn-rev": true, /// "hostname": "myhost.example.org", -/// "state": 0 +/// "state": 0, +/// "user-context": { \"version\": 1 } /// } class Lease4Parser : public isc::data::SimpleParser { public: @@ -67,7 +68,8 @@ public: /// "fqdn-fwd": true, /// "fqdn-rev": true, /// "hostname": "myhost.example.org", -/// "state": 0 +/// "state": 0, +/// "user-context": { \"version\": 1 } /// } /// It expects the input data to use the following format: diff --git a/src/hooks/dhcp/lease_cmds/tests/lease_cmds_unittest.cc b/src/hooks/dhcp/lease_cmds/tests/lease_cmds_unittest.cc index 04b3252695..a43d4e8cc5 100644 --- a/src/hooks/dhcp/lease_cmds/tests/lease_cmds_unittest.cc +++ b/src/hooks/dhcp/lease_cmds/tests/lease_cmds_unittest.cc @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include using namespace std; @@ -25,6 +25,7 @@ using namespace isc::config; using namespace isc::data; using namespace isc::dhcp; using namespace isc::asiolink; +using namespace isc::test; namespace { @@ -472,6 +473,22 @@ public: // Check that there are no v4 specific fields. EXPECT_FALSE(l->contains("client-id")); } + + /// @brief Checks if specified response contains user context + /// + /// @param lease Element tree that represents a lease + /// @param expected expected user context in textual form + void checkContext(ConstElementPtr lease, std::string expected) { + ASSERT_TRUE(lease); + ConstElementPtr moved = moveComments(lease); + ConstElementPtr ctx = moved->get("user-context"); + if (!expected.empty()) { + ASSERT_TRUE(ctx); + EXPECT_EQ(expected, ctx->str()); + } else { + EXPECT_FALSE(ctx); + } + } }; // Simple test that checks the library really registers the commands. @@ -611,6 +628,20 @@ TEST_F(LeaseCmdsTest, Lease4AddBadParams) { exp_rsp = "Invalid state value: 123, supported values are: 0 (default), 1 " "(declined) and 2 (expired-reclaimed)"; testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); + + // Bad user context: not a map. + txt = + "{\n" + " \"command\": \"lease4-add\",\n" + " \"arguments\": {" + " \"subnet-id\": 44,\n" + " \"ip-address\": \"192.0.2.1\",\n" + " \"hw-address\": \"1a:1b:1c:1d:1e:1f\",\n" + " \"user-context\": \"bad value\"\n" + " }\n" + "}"; + exp_rsp = "Invalid user context '\"bad value\"' is not a JSON map."; + testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); } // Check that a simple, well formed lease4 can be added. @@ -646,6 +677,7 @@ TEST_F(LeaseCmdsTest, Lease4Add) { EXPECT_FALSE(l->fqdn_fwd_); EXPECT_FALSE(l->fqdn_rev_); EXPECT_EQ("", l->hostname_); + EXPECT_FALSE(l->getContext()); // Test execution is fast. The cltt should be set to now. In some rare // cases we could have the seconds counter to tick, so having a value off @@ -677,7 +709,8 @@ TEST_F(LeaseCmdsTest, Lease4AddFull) { " \"expire\": 12345678,\n" " \"fqdn-fwd\": true,\n" " \"fqdn-rev\": true,\n" - " \"hostname\": \"urania.example.org\"" + " \"hostname\": \"urania.example.org\",\n" + " \"user-context\": { \"foobar\": true }\n" " }\n" "}"; string exp_rsp = "Lease added."; @@ -695,6 +728,8 @@ TEST_F(LeaseCmdsTest, Lease4AddFull) { EXPECT_EQ(true, l->fqdn_fwd_); EXPECT_EQ(true, l->fqdn_rev_); EXPECT_EQ("urania.example.org", l->hostname_); + ASSERT_TRUE(l->getContext()); + EXPECT_EQ("{ \"foobar\": true }", l->getContext()->str()); } // Check that lease6-add with missing parameters will fail. @@ -845,6 +880,21 @@ TEST_F(LeaseCmdsTest, Lease6AddBadParams) { exp_rsp = "Invalid state value: 123, supported values are: 0 (default), 1 " "(declined) and 2 (expired-reclaimed)"; testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); + + // Bad user context: not a map. + txt = + "{\n" + " \"command\": \"lease6-add\",\n" + " \"arguments\": {" + " \"subnet-id\": 66,\n" + " \"ip-address\": \"2001:db8:1::1\",\n" + " \"duid\": \"1a:1b:1c:1d:1e:1f\",\n" + " \"iaid\": 1234\n," + " \"user-context\": \"bad value\"\n" + " }\n" + "}"; + exp_rsp = "Invalid user context '\"bad value\"' is not a JSON map."; + testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); } // Check that a simple, well formed lease6 can be added. @@ -871,7 +921,10 @@ TEST_F(LeaseCmdsTest, Lease6Add) { testCommand(txt, CONTROL_RESULT_SUCCESS, exp_rsp); // Now check that the lease is really there. - EXPECT_TRUE(lmptr_->getLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::3"))); + Lease6Ptr l = lmptr_->getLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::3")); + ASSERT_TRUE(l); + EXPECT_EQ("", l->hostname_); + EXPECT_FALSE(l->getContext()); } // Check that a simple, well formed prefix lease can be added. @@ -904,6 +957,8 @@ TEST_F(LeaseCmdsTest, Lease6AddPrefix) { ASSERT_TRUE(l); EXPECT_EQ(Lease::TYPE_PD, l->type_); EXPECT_EQ(48, l->prefixlen_); + EXPECT_EQ("", l->hostname_); + EXPECT_FALSE(l->getContext()); } // Check that a well formed lease6 with tons of parameters can be added. @@ -930,7 +985,8 @@ TEST_F(LeaseCmdsTest, Lease6AddFullAddr) { " \"expire\": 12345678,\n" " \"fqdn-fwd\": true,\n" " \"fqdn-rev\": true,\n" - " \"hostname\": \"urania.example.org\"" + " \"hostname\": \"urania.example.org\",\n" + " \"user-context\": { \"foobar\": true }\n" " }\n" "}"; string exp_rsp = "Lease added."; @@ -949,6 +1005,8 @@ TEST_F(LeaseCmdsTest, Lease6AddFullAddr) { EXPECT_EQ(true, l->fqdn_fwd_); EXPECT_EQ(true, l->fqdn_rev_); EXPECT_EQ("urania.example.org", l->hostname_); + ASSERT_TRUE(l->getContext()); + EXPECT_EQ("{ \"foobar\": true }", l->getContext()->str()); } // Checks that lease6-get can handle a situation when the query is @@ -1894,6 +1952,20 @@ TEST_F(LeaseCmdsTest, Lease4UpdateBadParams) { "}"; exp_rsp = "Non-IPv4 address specified: 2001:db8:1::1"; testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); + + // Bad user context: not a map. + txt = + "{\n" + " \"command\": \"lease4-update\",\n" + " \"arguments\": {" + " \"subnet-id\": 44,\n" + " \"ip-address\": \"192.0.2.1\",\n" + " \"hw-address\": \"1a:1b:1c:1d:1e:1f\",\n" + " \"user-context\": \"bad value\"\n" + " }\n" + "}"; + exp_rsp = "Invalid user context '\"bad value\"' is not a JSON map."; + testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); } // Check that lease4-update correctly handles case when there is @@ -1953,6 +2025,7 @@ TEST_F(LeaseCmdsTest, Lease4Update) { ASSERT_TRUE(l->hwaddr_); EXPECT_EQ("1a:1b:1c:1d:1e:1f", l->hwaddr_->toText(false)); EXPECT_EQ("newhostname.example.org", l->hostname_); + EXPECT_FALSE(l->getContext()); } // Check that a lease4 is created if it doesn't exist during the update. @@ -1988,6 +2061,7 @@ TEST_F(LeaseCmdsTest, Lease4UpdateForceCreate) { ASSERT_TRUE(l->hwaddr_); EXPECT_EQ("1a:1b:1c:1d:1e:1f", l->hwaddr_->toText(false)); EXPECT_EQ("newhostname.example.org", l->hostname_); + EXPECT_FALSE(l->getContext()); } // Check that lease4-update correctly handles case when the 'force-create' @@ -2119,6 +2193,21 @@ TEST_F(LeaseCmdsTest, Lease6UpdateBadParams) { "}"; exp_rsp = "Non-IPv6 address specified: 192.0.2.1"; testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); + + // Bad user context: not a map. + txt = + "{\n" + " \"command\": \"lease6-update\",\n" + " \"arguments\": {" + " \"subnet-id\": 66,\n" + " \"ip-address\": \"2001:db8:1::1\",\n" + " \"duid\": \"1a:1b:1c:1d:1e:1f\",\n" + " \"iaid\": 1234\n," + " \"user-context\": \"bad value\"\n" + " }\n" + "}"; + exp_rsp = "Invalid user context '\"bad value\"' is not a JSON map."; + testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp); } // Check that a lease6 can be updated. We're changing hw-address @@ -2155,6 +2244,7 @@ TEST_F(LeaseCmdsTest, Lease6Update) { EXPECT_EQ("88:88:88:88:88:88:88:88", l->duid_->toText()); EXPECT_EQ("newhostname.example.org", l->hostname_); EXPECT_EQ(7654321, l->iaid_); + EXPECT_FALSE(l->getContext()); } @@ -2220,6 +2310,7 @@ TEST_F(LeaseCmdsTest, Lease6UpdateForceCreate) { EXPECT_EQ("88:88:88:88:88:88:88:88", l->duid_->toText()); EXPECT_EQ("newhostname.example.org", l->hostname_); EXPECT_EQ(7654321, l->iaid_); + EXPECT_FALSE(l->getContext()); } // Check that lease6-update correctly handles case when the 'force-create' diff --git a/src/lib/testutils/user_context_utils.cc b/src/lib/testutils/user_context_utils.cc index 398a5e52f5..33799f39b1 100644 --- a/src/lib/testutils/user_context_utils.cc +++ b/src/lib/testutils/user_context_utils.cc @@ -1,4 +1,4 @@ -// 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 Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -128,6 +128,11 @@ ElementPtr moveComments(ElementPtr element) { return (result.get()); } +ConstElementPtr moveComments(ConstElementPtr element) { + Value result = moveComments1(element); + return (result.get()); +} + }; // end of isc::test namespace }; // end of isc namespace @@ -231,5 +236,10 @@ ElementPtr extractComments(ElementPtr element) { return (result.get()); } +ConstElementPtr extractComments(ConstElementPtr element) { + Value result = extractComments1(element); + return (result.get()); +} + }; // end of isc::test namespace }; // end of isc namespace diff --git a/src/lib/testutils/user_context_utils.h b/src/lib/testutils/user_context_utils.h index acd43071d3..498efe4805 100644 --- a/src/lib/testutils/user_context_utils.h +++ b/src/lib/testutils/user_context_utils.h @@ -23,6 +23,12 @@ namespace test { /// @return a processed copy of element or unmodified element isc::data::ElementPtr moveComments(isc::data::ElementPtr element); +/// @brief Move comment entries to user-context (const variant) +/// +/// @param element +/// @return a processed copy of element or unmodified element +isc::data::ConstElementPtr moveComments(isc::data::ConstElementPtr element); + /// @brief Extract comment entries from user-context /// /// Process an element looking for user-context entries carrying @@ -35,6 +41,12 @@ isc::data::ElementPtr moveComments(isc::data::ElementPtr element); /// @return a processed copy of element or unmodified element isc::data::ElementPtr extractComments(isc::data::ElementPtr element); +/// @brief Extract comment entries from user-context (const variant) +/// +/// @param element +/// @return a processed copy of element or unmodified element +isc::data::ConstElementPtr extractComments(isc::data::ConstElementPtr element); + }; // end of isc::test namespace }; // end of isc namespace