summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2018-07-07 19:23:16 +0200
committerFrancis Dupont <fdupont@isc.org>2018-07-07 19:23:16 +0200
commit12ebb96c01dfdc397faead1945569853d5b617eb (patch)
tree7645b9243ec0f49a0613508d14c6580e7dc59293 /src/lib/dhcpsrv
parent[master] spurious spaces (diff)
parent[5584] Addressed comments (diff)
downloadkea-12ebb96c01dfdc397faead1945569853d5b617eb.tar.xz
kea-12ebb96c01dfdc397faead1945569853d5b617eb.zip
[master] Merged trac5584 (user context for leases)
Diffstat (limited to 'src/lib/dhcpsrv')
-rw-r--r--src/lib/dhcpsrv/cql_connection.h5
-rw-r--r--src/lib/dhcpsrv/cql_lease_mgr.cc114
-rw-r--r--src/lib/dhcpsrv/csv_lease_file4.cc29
-rw-r--r--src/lib/dhcpsrv/csv_lease_file4.h8
-rw-r--r--src/lib/dhcpsrv/csv_lease_file6.cc27
-rw-r--r--src/lib/dhcpsrv/csv_lease_file6.h8
-rw-r--r--src/lib/dhcpsrv/lease.cc33
-rw-r--r--src/lib/dhcpsrv/lease.h6
-rw-r--r--src/lib/dhcpsrv/memfile_lease_mgr.h3
-rw-r--r--src/lib/dhcpsrv/mysql_connection.h2
-rw-r--r--src/lib/dhcpsrv/mysql_lease_mgr.cc164
-rw-r--r--src/lib/dhcpsrv/pgsql_connection.h4
-rw-r--r--src/lib/dhcpsrv/pgsql_lease_mgr.cc116
-rw-r--r--src/lib/dhcpsrv/tests/csv_lease_file4_unittest.cc43
-rw-r--r--src/lib/dhcpsrv/tests/csv_lease_file6_unittest.cc81
-rw-r--r--src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc34
-rw-r--r--src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc74
-rw-r--r--src/lib/dhcpsrv/tests/lease_unittest.cc152
-rw-r--r--src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc200
-rw-r--r--src/lib/dhcpsrv/tests/test_utils.cc16
20 files changed, 851 insertions, 268 deletions
diff --git a/src/lib/dhcpsrv/cql_connection.h b/src/lib/dhcpsrv/cql_connection.h
index 68ae833618..9d81d93626 100644
--- a/src/lib/dhcpsrv/cql_connection.h
+++ b/src/lib/dhcpsrv/cql_connection.h
@@ -1,3 +1,4 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2017 Deutsche Telekom AG.
//
// Authors: Razvan Becheriu <razvan.becheriu@qualitance.com>
@@ -48,9 +49,9 @@ constexpr uint32_t CQL_DRIVER_VERSION_MAJOR = CASS_VERSION_MAJOR;
constexpr uint32_t CQL_DRIVER_VERSION_MINOR = CASS_VERSION_MINOR;
/// @}
-/// Define CQL schema version: 2.0
+/// Define CQL schema version: 3.0
/// @{
-constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR = 2u;
+constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR = 3u;
constexpr uint32_t CQL_SCHEMA_VERSION_MINOR = 0u;
/// @}
diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc
index a225585ab2..1a3faadb0b 100644
--- a/src/lib/dhcpsrv/cql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/cql_lease_mgr.cc
@@ -1,3 +1,4 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2018 Deutsche Telekom AG.
//
// Authors: Razvan Becheriu <razvan.becheriu@qualitance.com>
@@ -25,6 +26,7 @@
#include <asiolink/io_address.h>
+using namespace isc::data;
using isc::asiolink::IOAddress;
namespace isc {
@@ -32,6 +34,7 @@ namespace dhcp {
static constexpr size_t HOSTNAME_MAX_LEN = 255u;
static constexpr size_t ADDRESS6_TEXT_MAX_LEN = 39u;
+static constexpr char NULL_USER_CONTEXT[] = "";
/// @brief Common CQL and Lease Data Methods
///
@@ -47,7 +50,7 @@ public:
CqlLeaseExchange(const CqlConnection &connection)
: connection_(connection), valid_lifetime_(0), expire_(0),
subnet_id_(0), fqdn_fwd_(cass_false), fqdn_rev_(cass_false),
- state_(0) {
+ state_(0), user_context_(NULL_USER_CONTEXT) {
}
/// @brief Create BIND array to receive C++ data.
@@ -96,6 +99,9 @@ protected:
/// @brief Lease state
cass_int32_t state_;
+
+ /// @brief User context
+ std::string user_context_;
};
/// @brief Exchange Lease4 information between Kea and CQL
@@ -249,9 +255,9 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{INSERT_LEASE4,
"INSERT INTO lease4( "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
") VALUES ( "
- "?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
+ "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
") "
"IF NOT EXISTS "}},
@@ -267,7 +273,8 @@ StatementMap CqlLease4Exchange::tagged_statements_{
"fqdn_fwd = ?, "
"fqdn_rev = ?, "
"hostname = ?, "
- "state = ? "
+ "state = ?, "
+ "user_context = ? "
"WHERE address = ? "
"IF EXISTS "}},
@@ -283,7 +290,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4_EXPIRE,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "
"WHERE state = ? "
"AND expire < ? "
@@ -295,7 +302,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "}},
// Gets an IPv4 lease with specified IPv4 address
@@ -303,7 +310,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4_ADDR,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "
"WHERE address = ? "}},
@@ -312,7 +319,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4_CLIENTID,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "
"WHERE client_id = ? "
"ALLOW FILTERING "}},
@@ -322,7 +329,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4_CLIENTID_SUBID,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "
"WHERE client_id = ? "
"AND subnet_id = ? "
@@ -333,7 +340,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4_HWADDR,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "
"WHERE hwaddr = ? "
"ALLOW FILTERING "}},
@@ -343,7 +350,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4_HWADDR_SUBID,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "
"WHERE hwaddr = ? "
"AND subnet_id = ? "
@@ -354,7 +361,7 @@ StatementMap CqlLease4Exchange::tagged_statements_{
{GET_LEASE4_SUBID,
"SELECT "
"address, hwaddr, client_id, valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, state, user_context "
"FROM lease4 "
"WHERE subnet_id = ? "
"ALLOW FILTERING "}}
@@ -437,6 +444,14 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) {
// state: int
state_ = static_cast<cass_int32_t>(lease_->state_);
+ // user_context: text
+ ConstElementPtr ctx = lease_->getContext();
+ if (ctx) {
+ user_context_ = ctx->str();
+ } else {
+ user_context_ = NULL_USER_CONTEXT;
+ }
+
// Start with a fresh array.
data.clear();
data.add(&address_);
@@ -449,6 +464,7 @@ CqlLease4Exchange::createBindForInsert(const Lease4Ptr &lease, AnyArray &data) {
data.add(&fqdn_rev_);
data.add(&hostname_);
data.add(&state_);
+ data.add(&user_context_);
} catch (const Exception &ex) {
isc_throw(DbOperationError, "CqlLease4Exchange::createBindForInsert(): "
@@ -531,6 +547,14 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data,
// state: int
state_ = static_cast<cass_int32_t>(lease_->state_);
+ // user_context: text
+ ConstElementPtr ctx = lease_->getContext();
+ if (ctx) {
+ user_context_ = ctx->str();
+ } else {
+ user_context_ = NULL_USER_CONTEXT;
+ }
+
// Start with a fresh array.
data.clear();
data.add(&hwaddr_);
@@ -542,6 +566,7 @@ CqlLease4Exchange::createBindForUpdate(const Lease4Ptr &lease, AnyArray &data,
data.add(&fqdn_rev_);
data.add(&hostname_);
data.add(&state_);
+ data.add(&user_context_);
data.add(&address_);
} catch (const Exception &ex) {
@@ -609,6 +634,9 @@ CqlLease4Exchange::createBindForSelect(AnyArray &data, StatementTag /* unused */
// state: int
data.add(&state_);
+
+ // user_context: text
+ data.add(&user_context_);
}
boost::any
@@ -645,6 +673,15 @@ CqlLease4Exchange::retrieve() {
uint32_t addr4 = static_cast<uint32_t>(address_);
+ ConstElementPtr ctx;
+ if (!user_context_.empty()) {
+ ctx = Element::fromJSON(user_context_);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context_
+ << "' is not a JSON map");
+ }
+ }
+
Lease4Ptr result(new Lease4(addr4, hwaddr, client_id_.data(),
client_id_.size(), valid_lifetime_, 0, 0,
cltt, subnet_id_, fqdn_fwd_, fqdn_rev_,
@@ -652,6 +689,10 @@ CqlLease4Exchange::retrieve() {
result->state_ = state_;
+ if (ctx) {
+ result->setContext(ctx);
+ }
+
return (result);
} catch (const Exception &ex) {
isc_throw(DbOperationError,
@@ -885,9 +926,9 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
"INSERT INTO lease6("
"address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
"lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
- "hwaddr_source, state "
+ "hwaddr_source, state, user_context "
") VALUES ("
- "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
+ "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
") "
"IF NOT EXISTS "}},
@@ -909,7 +950,8 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
"hwaddr = ?, "
"hwtype = ?, "
"hwaddr_source = ?, "
- "state = ? "
+ "state = ?, "
+ "user_context = ? "
"WHERE address = ? "
"IF EXISTS "}},
@@ -926,7 +968,7 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
"SELECT "
"address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
"lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
- "hwaddr_source, state "
+ "hwaddr_source, state, user_context "
"FROM lease6 "
"WHERE state = ? "
"AND expire < ? "
@@ -939,7 +981,7 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
"SELECT "
"address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
"lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
- "hwaddr_source, state "
+ "hwaddr_source, state, user_context "
"FROM lease6 "
"WHERE address = ? "
"AND lease_type = ? "
@@ -951,7 +993,7 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
"SELECT "
"address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
"lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
- "hwaddr_source, state "
+ "hwaddr_source, state, user_context "
"FROM lease6 "
"WHERE duid = ? AND iaid = ? "
"AND lease_type = ? "
@@ -963,7 +1005,7 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
"SELECT "
"address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
"lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
- "hwaddr_source, state "
+ "hwaddr_source, state, user_context "
"FROM lease6 "
"WHERE duid = ? AND iaid = ? "
"AND lease_type = ? "
@@ -1072,6 +1114,14 @@ CqlLease6Exchange::createBindForInsert(const Lease6Ptr &lease, AnyArray &data) {
// state: int
state_ = static_cast<cass_int32_t>(lease_->state_);
+ // user_context: text
+ ConstElementPtr ctx = lease_->getContext();
+ if (ctx) {
+ user_context_ = ctx->str();
+ } else {
+ user_context_ = NULL_USER_CONTEXT;
+ }
+
// Start with a fresh array.
data.clear();
@@ -1092,6 +1142,7 @@ CqlLease6Exchange::createBindForInsert(const Lease6Ptr &lease, AnyArray &data) {
data.add(&hwtype_);
data.add(&hwaddr_source_);
data.add(&state_);
+ data.add(&user_context_);
} catch (const Exception &ex) {
isc_throw(DbOperationError, "CqlLease6Exchange::createBindForInsert(): "
@@ -1205,6 +1256,14 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data,
// state: int
state_ = static_cast<cass_int32_t>(lease_->state_);
+ // user_context: text
+ ConstElementPtr ctx = lease_->getContext();
+ if (ctx) {
+ user_context_ = ctx->str();
+ } else {
+ user_context_ = NULL_USER_CONTEXT;
+ }
+
// Start with a fresh array.
data.clear();
@@ -1224,6 +1283,7 @@ CqlLease6Exchange::createBindForUpdate(const Lease6Ptr &lease, AnyArray &data,
data.add(&hwtype_);
data.add(&hwaddr_source_);
data.add(&state_);
+ data.add(&user_context_);
data.add(&address_);
} catch (const Exception &ex) {
@@ -1309,6 +1369,9 @@ CqlLease6Exchange::createBindForSelect(AnyArray &data, StatementTag /* unused */
// state: int
data.add(&state_);
+
+ // user_context: text
+ data.add(&user_context_);
}
boost::any
@@ -1360,6 +1423,15 @@ CqlLease6Exchange::retrieve() {
hwaddr->source_ = hwaddr_source_;
}
+ ConstElementPtr ctx;
+ if (!user_context_.empty()) {
+ ctx = Element::fromJSON(user_context_);
+ if (!ctx ||(ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context_
+ << "' is not a JSON map");
+ }
+ }
+
// Create the lease and set the cltt (after converting from the
// expire time retrieved from the database).
Lease6Ptr result(
@@ -1373,6 +1445,10 @@ CqlLease6Exchange::retrieve() {
result->state_ = state_;
+ if (ctx) {
+ result->setContext(ctx);
+ }
+
return (result);
} catch (const Exception &ex) {
isc_throw(DbOperationError,
diff --git a/src/lib/dhcpsrv/csv_lease_file4.cc b/src/lib/dhcpsrv/csv_lease_file4.cc
index 6f1d5d5335..e54189f144 100644
--- a/src/lib/dhcpsrv/csv_lease_file4.cc
+++ b/src/lib/dhcpsrv/csv_lease_file4.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 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
@@ -8,6 +8,7 @@
#include <dhcpsrv/csv_lease_file4.h>
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::util;
namespace isc {
@@ -52,6 +53,10 @@ CSVLeaseFile4::append(const Lease4& lease) {
row.writeAt(getColumnIndex("fqdn_rev"), lease.fqdn_rev_);
row.writeAt(getColumnIndex("hostname"), lease.hostname_);
row.writeAt(getColumnIndex("state"), lease.state_);
+ // User context is optional.
+ if (lease.getContext()) {
+ row.writeAt(getColumnIndex("user_context"), lease.getContext()->str());
+ }
try {
VersionedCSVFile::append(row);
@@ -103,6 +108,9 @@ CSVLeaseFile4::next(Lease4Ptr& lease) {
" valid for declined leases");
}
+ // Get the user context (can be NULL).
+ ConstElementPtr ctx = readContext(row);
+
lease.reset(new Lease4(readAddress(row),
HWAddrPtr(new HWAddr(hwaddr)),
client_id_vec.empty() ? NULL : &client_id_vec[0],
@@ -116,6 +124,10 @@ CSVLeaseFile4::next(Lease4Ptr& lease) {
readHostname(row)));
lease->state_ = state;
+ if (ctx) {
+ lease->setContext(ctx);
+ }
+
} catch (std::exception& ex) {
// bump the read error count
++read_errs_;
@@ -145,6 +157,7 @@ CSVLeaseFile4::initColumns() {
addColumn("fqdn_rev", "1.0");
addColumn("hostname", "1.0");
addColumn("state", "2.0", "0");
+ addColumn("user_context", "2.1");
// Any file with less than hostname is invalid
setMinimumValidColumns("hostname");
}
@@ -217,5 +230,19 @@ CSVLeaseFile4::readState(const util::CSVRow& row) {
return (state);
}
+ConstElementPtr
+CSVLeaseFile4::readContext(const util::CSVRow& row) {
+ std::string user_context = row.readAt(getColumnIndex("user_context"));
+ if (user_context.empty()) {
+ return (ConstElementPtr());
+ }
+ ConstElementPtr ctx = Element::fromJSON(user_context);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(isc::BadValue, "user context '" << user_context
+ << "' is not a JSON map");
+ }
+ return (ctx);
+}
+
} // end of namespace isc::dhcp
} // end of namespace isc
diff --git a/src/lib/dhcpsrv/csv_lease_file4.h b/src/lib/dhcpsrv/csv_lease_file4.h
index 2964580b44..ef5d2b4e68 100644
--- a/src/lib/dhcpsrv/csv_lease_file4.h
+++ b/src/lib/dhcpsrv/csv_lease_file4.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 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
@@ -95,6 +95,7 @@ private:
/// - fqdn_rev
/// - hostname
/// - state
+ /// - user_context
void initColumns();
///
@@ -151,6 +152,11 @@ private:
///
/// @param row CSV file row holding lease information.
uint32_t readState(const util::CSVRow& row);
+
+ /// @brief Reads lease user context from the CSV file row.
+ ///
+ /// @param row CSV file row holding lease information.
+ data::ConstElementPtr readContext(const util::CSVRow& row);
//@}
};
diff --git a/src/lib/dhcpsrv/csv_lease_file6.cc b/src/lib/dhcpsrv/csv_lease_file6.cc
index c1f8cb474a..ea1d5f2454 100644
--- a/src/lib/dhcpsrv/csv_lease_file6.cc
+++ b/src/lib/dhcpsrv/csv_lease_file6.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2016 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
@@ -9,6 +9,7 @@
#include <dhcpsrv/csv_lease_file6.h>
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::util;
namespace isc {
@@ -52,6 +53,10 @@ CSVLeaseFile6::append(const Lease6& lease) {
row.writeAt(getColumnIndex("hwaddr"), lease.hwaddr_->toText(false));
}
row.writeAt(getColumnIndex("state"), lease.state_);
+ // User context is optional.
+ if (lease.getContext()) {
+ row.writeAt(getColumnIndex("user_context"), lease.getContext()->str());
+ }
try {
VersionedCSVFile::append(row);
} catch (const std::exception&) {
@@ -99,6 +104,10 @@ CSVLeaseFile6::next(Lease6Ptr& lease) {
isc_throw(isc::BadValue, "The Empty DUID is"
"only valid for declined leases");
}
+ ConstElementPtr ctx = readContext(row);
+ if (ctx) {
+ lease->setContext(ctx);
+ }
} catch (std::exception& ex) {
// bump the read error count
++read_errs_;
@@ -132,7 +141,7 @@ CSVLeaseFile6::initColumns() {
addColumn("hostname", "1.0");
addColumn("hwaddr", "2.0");
addColumn("state", "3.0", "0");
-
+ addColumn("user_context", "3.1");
// Any file with less than hostname is invalid
setMinimumValidColumns("hostname");
}
@@ -244,5 +253,19 @@ CSVLeaseFile6::readState(const util::CSVRow& row) {
return (state);
}
+ConstElementPtr
+CSVLeaseFile6::readContext(const util::CSVRow& row) {
+ std::string user_context = row.readAt(getColumnIndex("user_context"));
+ if (user_context.empty()) {
+ return (ConstElementPtr());
+ }
+ ConstElementPtr ctx = Element::fromJSON(user_context);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(isc::BadValue, "user context '" << user_context
+ << "' is not a JSON map");
+ }
+ return (ctx);
+}
+
} // end of namespace isc::dhcp
} // end of namespace isc
diff --git a/src/lib/dhcpsrv/csv_lease_file6.h b/src/lib/dhcpsrv/csv_lease_file6.h
index ac72b1c73e..3fdd71fbff 100644
--- a/src/lib/dhcpsrv/csv_lease_file6.h
+++ b/src/lib/dhcpsrv/csv_lease_file6.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 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
@@ -98,6 +98,7 @@ private:
/// - hostname
/// - hwaddr
/// - state
+ /// - user_context
void initColumns();
///
@@ -175,6 +176,11 @@ private:
///
/// @param row CSV file row holding lease information.
uint32_t readState(const util::CSVRow& row);
+
+ /// @brief Reads lease user context from the CSV file row.
+ ///
+ /// @param row CSV file row holding lease information.
+ data::ConstElementPtr readContext(const util::CSVRow& row);
//@}
};
diff --git a/src/lib/dhcpsrv/lease.cc b/src/lib/dhcpsrv/lease.cc
index 9f52c6603d..6b50a3858f 100644
--- a/src/lib/dhcpsrv/lease.cc
+++ b/src/lib/dhcpsrv/lease.cc
@@ -251,6 +251,15 @@ Lease::fromElementCommon(const LeasePtr& lease, const data::ConstElementPtr& ele
}
lease->state_ = state->intValue();
+
+ // user context
+ ConstElementPtr ctx = element->get("user-context");
+ if (ctx) {
+ if (ctx->getType() != Element::map) {
+ isc_throw(BadValue, "user context is not a map");
+ }
+ lease->setContext(ctx);
+ }
}
Lease4::Lease4(const Lease4& other)
@@ -275,6 +284,10 @@ Lease4::Lease4(const Lease4& other)
client_id_.reset();
}
+
+ if (other.getContext()) {
+ setContext(other.getContext());
+ }
}
Lease4::Lease4(const isc::asiolink::IOAddress& address,
@@ -375,6 +388,10 @@ Lease4::operator=(const Lease4& other) {
} else {
client_id_.reset();
}
+
+ if (other.getContext()) {
+ setContext(other.getContext());
+ }
}
return (*this);
}
@@ -383,6 +400,7 @@ isc::data::ElementPtr
Lease4::toElement() const {
// Prepare the map
ElementPtr map = Element::createMap();
+ contextToElement(map);
map->set("ip-address", Element::create(addr_.toText()));
map->set("subnet-id", Element::create(static_cast<long int>(subnet_id_)));
map->set("hw-address", Element::create(hwaddr_->toText(false)));
@@ -526,6 +544,10 @@ Lease6::toText() const {
<< "Subnet ID: " << subnet_id_ << "\n"
<< "State: " << statesToText(state_) << "\n";
+ if (getContext()) {
+ stream << "User context: " << getContext()->str() << "\n";
+ }
+
return (stream.str());
}
@@ -543,6 +565,10 @@ Lease4::toText() const {
<< "Subnet ID: " << subnet_id_ << "\n"
<< "State: " << statesToText(state_) << "\n";
+ if (getContext()) {
+ stream << "User context: " << getContext()->str() << "\n";
+ }
+
return (stream.str());
}
@@ -560,7 +586,8 @@ Lease4::operator==(const Lease4& other) const {
hostname_ == other.hostname_ &&
fqdn_fwd_ == other.fqdn_fwd_ &&
fqdn_rev_ == other.fqdn_rev_ &&
- state_ == other.state_);
+ state_ == other.state_ &&
+ nullOrEqualValues(getContext(), other.getContext()));
}
bool
@@ -580,13 +607,15 @@ Lease6::operator==(const Lease6& other) const {
hostname_ == other.hostname_ &&
fqdn_fwd_ == other.fqdn_fwd_ &&
fqdn_rev_ == other.fqdn_rev_ &&
- state_ == other.state_);
+ state_ == other.state_ &&
+ nullOrEqualValues(getContext(), other.getContext()));
}
isc::data::ElementPtr
Lease6::toElement() const {
// Prepare the map
ElementPtr map = Element::createMap();
+ contextToElement(map);
map->set("ip-address", Element::create(addr_.toText()));
map->set("type", Element::create(typeToText(type_)));
if (type_ == Lease::TYPE_PD) {
diff --git a/src/lib/dhcpsrv/lease.h b/src/lib/dhcpsrv/lease.h
index d8869b5af8..45568dc0d1 100644
--- a/src/lib/dhcpsrv/lease.h
+++ b/src/lib/dhcpsrv/lease.h
@@ -11,6 +11,7 @@
#include <dhcp/duid.h>
#include <dhcp/option.h>
#include <dhcp/hwaddr.h>
+#include <cc/user_context.h>
#include <cc/cfg_to_element.h>
namespace isc {
@@ -31,7 +32,7 @@ typedef boost::shared_ptr<Lease> LeasePtr;
///
/// This structure holds all information that is common between IPv4 and IPv6
/// leases.
-struct Lease : public isc::data::CfgToElement {
+struct Lease : public UserContext, public isc::data::CfgToElement {
/// @brief Type of lease or pool
typedef enum {
@@ -221,6 +222,9 @@ struct Lease : public isc::data::CfgToElement {
/// @param probation_period lease lifetime will be set to this value
virtual void decline(uint32_t probation_period) = 0;
+ /// Avoid a clang spurious error
+ using isc::data::CfgToElement::toElement;
+
protected:
/// @brief Sets common (for v4 and v6) properties of the lease object.
diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h
index 3af59246a8..2b7b5048c3 100644
--- a/src/lib/dhcpsrv/memfile_lease_mgr.h
+++ b/src/lib/dhcpsrv/memfile_lease_mgr.h
@@ -83,12 +83,13 @@ public:
/// Version history:
/// 1.0 - initial version (released in Kea 0.9)
/// 2.0 - hwaddr column added (to be released in Kea 0.9.1)
+ /// 2.1 - user context column add (to be released in Kea 1.5)
///
/// @{
static const int MAJOR_VERSION = 2;
/// Defines minor version of the memfile backend.
- static const int MINOR_VERSION = 0;
+ static const int MINOR_VERSION = 1;
/// @}
diff --git a/src/lib/dhcpsrv/mysql_connection.h b/src/lib/dhcpsrv/mysql_connection.h
index b1d22d090b..88716d26cd 100644
--- a/src/lib/dhcpsrv/mysql_connection.h
+++ b/src/lib/dhcpsrv/mysql_connection.h
@@ -40,7 +40,7 @@ extern const int MLM_MYSQL_FETCH_FAILURE;
/// @name Current database schema version values.
//@{
-const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 6;
+const uint32_t MYSQL_SCHEMA_VERSION_MAJOR = 7;
const uint32_t MYSQL_SCHEMA_VERSION_MINOR = 0;
//@}
diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc
index 93593e9054..59b0ea04d4 100644
--- a/src/lib/dhcpsrv/mysql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc
@@ -26,6 +26,7 @@
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::data;
using namespace std;
/// @file
@@ -84,6 +85,9 @@ const size_t HOSTNAME_MAX_LEN = 255;
/// colon separators.
const size_t ADDRESS6_TEXT_MAX_LEN = 39;
+/// @brief Maximum length of user context.
+const size_t USER_CONTEXT_MAX_LEN = 8192;
+
boost::array<TaggedStatement, MySqlLeaseMgr::NUM_STATEMENTS>
tagged_statements = { {
{MySqlLeaseMgr::DELETE_LEASE4,
@@ -100,55 +104,55 @@ tagged_statements = { {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4"},
{MySqlLeaseMgr::GET_LEASE4_ADDR,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE address = ?"},
{MySqlLeaseMgr::GET_LEASE4_CLIENTID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE client_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE client_id = ? AND subnet_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_HWADDR,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE hwaddr = ?"},
{MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE hwaddr = ? AND subnet_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_SUBID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE subnet_id = ?"},
{MySqlLeaseMgr::GET_LEASE4_EXPIRE,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE state != ? AND expire < ? "
"ORDER BY expire ASC "
@@ -159,7 +163,7 @@ tagged_statements = { {
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6"},
{MySqlLeaseMgr::GET_LEASE6_ADDR,
"SELECT address, duid, valid_lifetime, "
@@ -167,7 +171,7 @@ tagged_statements = { {
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE address = ? AND lease_type = ?"},
{MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
@@ -176,7 +180,7 @@ tagged_statements = { {
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE duid = ? AND iaid = ? AND lease_type = ?"},
{MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
@@ -185,7 +189,7 @@ tagged_statements = { {
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE duid = ? AND iaid = ? AND subnet_id = ? "
"AND lease_type = ?"},
@@ -195,7 +199,7 @@ tagged_statements = { {
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE subnet_id = ?"},
{MySqlLeaseMgr::GET_LEASE6_EXPIRE,
@@ -204,7 +208,7 @@ tagged_statements = { {
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE state != ? AND expire < ? "
"ORDER BY expire ASC "
@@ -213,22 +217,22 @@ tagged_statements = { {
"INSERT INTO lease4(address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
+ "state, user_context) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
{MySqlLeaseMgr::INSERT_LEASE6,
"INSERT INTO lease6(address, duid, valid_lifetime, "
"expire, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
+ "state, user_context) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
{MySqlLeaseMgr::UPDATE_LEASE4,
"UPDATE lease4 SET address = ?, hwaddr = ?, "
"client_id = ?, valid_lifetime = ?, expire = ?, "
"subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
"hostname = ?, "
- "state = ? "
+ "state = ?, user_context = ? "
"WHERE address = ?"},
{MySqlLeaseMgr::UPDATE_LEASE6,
"UPDATE lease6 SET address = ?, duid = ?, "
@@ -236,7 +240,7 @@ tagged_statements = { {
"pref_lifetime = ?, lease_type = ?, iaid = ?, "
"prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
"hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, "
- "state = ? "
+ "state = ?, user_context = ? "
"WHERE address = ?"},
{MySqlLeaseMgr::ALL_LEASE4_STATS,
"SELECT subnet_id, state, leases as state_count"
@@ -355,7 +359,7 @@ public:
class MySqlLease4Exchange : public MySqlLeaseExchange {
/// @brief Set number of database columns for this lease structure
- static const size_t LEASE_COLUMNS = 10;
+ static const size_t LEASE_COLUMNS = 11;
public:
/// @brief Constructor
@@ -366,10 +370,12 @@ public:
client_id_length_(0), client_id_null_(MLM_FALSE),
subnet_id_(0), valid_lifetime_(0),
fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
- state_(0) {
+ state_(0), user_context_length_(0),
+ user_context_null_(MLM_FALSE) {
memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
+ memset(user_context_, 0, sizeof(user_context_));
std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
// Set the column names (for error messages)
@@ -383,7 +389,8 @@ public:
columns_[7] = "fqdn_rev";
columns_[8] = "hostname";
columns_[9] = "state";
- BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
+ columns_[10] = "user_context";
+ BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
}
/// @brief Create MYSQL_BIND objects for Lease4 Pointer
@@ -521,11 +528,25 @@ public:
// bind_[9].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
+ // user_context: text
+ ConstElementPtr ctx = lease->getContext();
+ if (ctx) {
+ bind_[10].buffer_type = MYSQL_TYPE_STRING;
+ string ctx_txt = ctx->str();
+ strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
+ bind_[10].buffer = user_context_;
+ bind_[10].buffer_length = ctx_txt.length();
+ // bind_[10].is_null = &MLM_FALSE; // commented out for performance
+ // reasons, see memset() above
+ } else {
+ bind_[10].buffer_type = MYSQL_TYPE_NULL;
+ }
+
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
- BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
+ BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
@@ -630,11 +651,20 @@ public:
// bind_[9].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
+ // user_context: text null
+ user_context_null_ = MLM_FALSE;
+ user_context_length_ = sizeof(user_context_);
+ bind_[10].buffer_type = MYSQL_TYPE_STRING;
+ bind_[10].buffer = reinterpret_cast<char*>(user_context_);
+ bind_[10].buffer_length = user_context_length_;
+ bind_[10].length= &user_context_length_;
+ bind_[10].is_null = &user_context_null_;
+
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
- BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
+ BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
// Add the data to the vector. Note the end element is one after the
// end of the array.
@@ -671,6 +701,23 @@ public:
hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, HTYPE_ETHER));
}
+ // Convert user_context to string as well.
+ std::string user_context;
+ if (user_context_null_ == MLM_FALSE) {
+ user_context_[user_context_length_] = '\0';
+ user_context.assign(user_context_);
+ }
+
+ // Set the user context if there is one.
+ ConstElementPtr ctx;
+ if (!user_context.empty()) {
+ ctx = Element::fromJSON(user_context);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context
+ << "' is not a JSON map");
+ }
+ }
+
// note that T1 and T2 are not stored
Lease4Ptr lease(new Lease4(addr4_, hwaddr,
client_id_buffer_, client_id_length_,
@@ -680,6 +727,10 @@ public:
// Set state.
lease->state_ = state_;
+ if (ctx) {
+ lease->setContext(ctx);
+ }
+
return (lease);
}
@@ -723,6 +774,9 @@ private:
char hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname
unsigned long hostname_length_; ///< Client hostname length
uint32_t state_; ///< Lease state
+ char user_context_[USER_CONTEXT_MAX_LEN]; ///< User context
+ unsigned long user_context_length_; ///< User context length
+ my_bool user_context_null_; ///< Is user context null?
};
/// @brief Exchange MySQL and Lease6 Data
@@ -740,7 +794,7 @@ private:
class MySqlLease6Exchange : public MySqlLeaseExchange {
/// @brief Set number of database columns for this lease structure
- static const size_t LEASE_COLUMNS = 16;
+ static const size_t LEASE_COLUMNS = 17;
public:
/// @brief Constructor
@@ -753,11 +807,13 @@ public:
fqdn_fwd_(false), fqdn_rev_(false),
hostname_length_(0), hwaddr_length_(0),
hwaddr_null_(MLM_FALSE), hwtype_(0), hwaddr_source_(0),
- state_(0) {
+ state_(0), user_context_length_(0),
+ user_context_null_(MLM_FALSE) {
memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
memset(duid_buffer_, 0, sizeof(duid_buffer_));
memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
+ memset(user_context_, 0, sizeof(user_context_));
std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
// Set the column names (for error messages)
@@ -777,7 +833,8 @@ public:
columns_[13] = "hwtype";
columns_[14] = "hwaddr_source";
columns_[15] = "state";
- BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
+ columns_[16] = "user_context";
+ BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
}
/// @brief Create MYSQL_BIND objects for Lease6 Pointer
@@ -990,11 +1047,25 @@ public:
// bind_[15].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
+ // user_context: text
+ ConstElementPtr ctx = lease->getContext();
+ if (ctx) {
+ bind_[16].buffer_type = MYSQL_TYPE_STRING;
+ string ctx_txt = ctx->str();
+ strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
+ bind_[16].buffer = user_context_;
+ bind_[16].buffer_length = ctx_txt.length();
+ // bind_[16].is_null = &MLM_FALSE; // commented out for performance
+ // reasons, see memset() above
+ } else {
+ bind_[16].buffer_type = MYSQL_TYPE_NULL;
+ }
+
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
- BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
+ BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
@@ -1143,11 +1214,20 @@ public:
// bind_[15].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
+ // user_context: text null
+ user_context_null_ = MLM_FALSE;
+ user_context_length_ = sizeof(user_context_);
+ bind_[16].buffer_type = MYSQL_TYPE_STRING;
+ bind_[16].buffer = reinterpret_cast<char*>(user_context_);
+ bind_[16].buffer_length = user_context_length_;
+ bind_[16].length= &user_context_length_;
+ bind_[16].is_null = &user_context_null_;
+
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
- BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
+ BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
// Add the data to the vector. Note the end element is one after the
// end of the array.
@@ -1210,6 +1290,23 @@ public:
hwaddr->source_ = hwaddr_source_;
}
+ // Convert user_context to string as well.
+ std::string user_context;
+ if (user_context_null_ == MLM_FALSE) {
+ user_context_[user_context_length_] = '\0';
+ user_context.assign(user_context_);
+ }
+
+ // Set the user context if there is one.
+ ConstElementPtr ctx;
+ if (!user_context.empty()) {
+ ctx = Element::fromJSON(user_context);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context
+ << "' is not a JSON map");
+ }
+ }
+
// Create the lease and set the cltt (after converting from the
// expire time retrieved from the database).
Lease6Ptr result(new Lease6(type, addr, duid_ptr, iaid_,
@@ -1223,6 +1320,10 @@ public:
// Set state.
result->state_ = state_;
+ if (ctx) {
+ result->setContext(ctx);
+ }
+
return (result);
}
@@ -1273,6 +1374,9 @@ private:
uint16_t hwtype_; ///< Hardware type
uint32_t hwaddr_source_; ///< Source of the hardware address
uint32_t state_; ///< Lease state.
+ char user_context_[USER_CONTEXT_MAX_LEN]; ///< User context
+ unsigned long user_context_length_; ///< User context length
+ my_bool user_context_null_; ///< Is user context null?
};
/// @brief MySql derivation of the statistical lease data query
diff --git a/src/lib/dhcpsrv/pgsql_connection.h b/src/lib/dhcpsrv/pgsql_connection.h
index 659c131942..49fda1444e 100644
--- a/src/lib/dhcpsrv/pgsql_connection.h
+++ b/src/lib/dhcpsrv/pgsql_connection.h
@@ -17,8 +17,8 @@
namespace isc {
namespace dhcp {
-/// @brief Define PostgreSQL backend version: 4.0
-const uint32_t PG_SCHEMA_VERSION_MAJOR = 4;
+/// @brief Define PostgreSQL backend version: 5.0
+const uint32_t PG_SCHEMA_VERSION_MAJOR = 5;
const uint32_t PG_SCHEMA_VERSION_MINOR = 0;
// Maximum number of parameters that can be used a statement
diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc
index f6e2a18434..ac652c02bc 100644
--- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc
@@ -22,6 +22,7 @@
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::data;
using namespace std;
namespace {
@@ -58,7 +59,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4"},
// GET_LEASE4_ADDR
@@ -67,7 +68,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE address = $1"},
@@ -77,7 +78,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE client_id = $1"},
@@ -87,7 +88,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE client_id = $1 AND subnet_id = $2"},
@@ -97,7 +98,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE hwaddr = $1"},
@@ -107,7 +108,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE hwaddr = $1 AND subnet_id = $2"},
@@ -117,7 +118,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE subnet_id = $1"},
@@ -127,7 +128,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
"fqdn_fwd, fqdn_rev, hostname, "
- "state "
+ "state, user_context "
"FROM lease4 "
"WHERE state != $1 AND expire < $2 "
"ORDER BY expire "
@@ -140,7 +141,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6"},
// GET_LEASE6_ADDR
@@ -150,7 +151,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE address = $1 AND lease_type = $2"},
@@ -161,7 +162,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE duid = $1 AND iaid = $2 AND lease_type = $3"},
@@ -172,7 +173,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE lease_type = $1 "
"AND duid = $2 AND iaid = $3 AND subnet_id = $4"},
@@ -184,7 +185,7 @@ PgSqlTaggedStatement tagged_statements[] = {
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE subnet_id = $1"},
@@ -196,56 +197,56 @@ PgSqlTaggedStatement tagged_statements[] = {
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state "
+ "state, user_context "
"FROM lease6 "
"WHERE state != $1 AND expire < $2 "
"ORDER BY expire "
"LIMIT $3"},
// INSERT_LEASE4
- { 10, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
- OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8 },
+ { 11, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
+ OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT },
"insert_lease4",
"INSERT INTO lease4(address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, "
- "state) "
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"},
+ "state, user_context) "
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"},
// INSERT_LEASE6
- { 16, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
+ { 17, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
OID_INT8, OID_INT2, OID_INT8, OID_INT2, OID_BOOL, OID_BOOL,
- OID_VARCHAR, OID_BYTEA, OID_INT2, OID_INT2, OID_INT8 },
+ OID_VARCHAR, OID_BYTEA, OID_INT2, OID_INT2, OID_INT8, OID_TEXT },
"insert_lease6",
"INSERT INTO lease6(address, duid, valid_lifetime, "
"expire, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
"hwaddr, hwtype, hwaddr_source, "
- "state) "
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)"},
+ "state, user_context) "
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)"},
// UPDATE_LEASE4
- { 11, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
- OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_INT8 },
+ { 12, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
+ OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_INT8 },
"update_lease4",
"UPDATE lease4 SET address = $1, hwaddr = $2, "
"client_id = $3, valid_lifetime = $4, expire = $5, "
"subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, "
- "state = $10 "
- "WHERE address = $11"},
+ "state = $10, user_context = $11 "
+ "WHERE address = $12"},
// UPDATE_LEASE6
- { 17, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8,
+ { 18, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8,
OID_INT2, OID_INT8, OID_INT2, OID_BOOL, OID_BOOL, OID_VARCHAR,
OID_BYTEA, OID_INT2, OID_INT2,
- OID_INT8, OID_VARCHAR },
+ OID_INT8, OID_TEXT, OID_VARCHAR },
"update_lease6",
"UPDATE lease6 SET address = $1, duid = $2, "
"valid_lifetime = $3, expire = $4, subnet_id = $5, "
"pref_lifetime = $6, lease_type = $7, iaid = $8, "
"prefix_len = $9, fqdn_fwd = $10, fqdn_rev = $11, hostname = $12, "
"hwaddr = $13, hwtype = $14, hwaddr_source = $15, "
- "state = $16 "
- "WHERE address = $17"},
+ "state = $16, user_context = $17 "
+ "WHERE address = $18"},
// ALL_LEASE4_STATS
{ 0, { OID_NONE },
"all_lease4_stats",
@@ -309,7 +310,7 @@ public:
: addr_str_(""), valid_lifetime_(0), valid_lifetime_str_(""),
expire_(0), expire_str_(""), subnet_id_(0), subnet_id_str_(""),
cltt_(0), fqdn_fwd_(false), fqdn_rev_(false), hostname_(""),
- state_str_("") {
+ state_str_(""), user_context_("") {
}
virtual ~PgSqlLeaseExchange(){}
@@ -329,6 +330,7 @@ protected:
bool fqdn_rev_;
std::string hostname_;
std::string state_str_;
+ std::string user_context_;
//@}
};
@@ -350,8 +352,9 @@ private:
static const size_t FQDN_REV_COL = 7;
static const size_t HOSTNAME_COL = 8;
static const size_t STATE_COL = 9;
+ static const size_t USER_CONTEXT_COL = 10;
/// @brief Number of columns in the table holding DHCPv4 leases.
- static const size_t LEASE_COLUMNS = 10;
+ static const size_t LEASE_COLUMNS = 11;
public:
@@ -376,6 +379,7 @@ public:
columns_.push_back("fqdn_rev");
columns_.push_back("hostname");
columns_.push_back("state");
+ columns_.push_back("user_context");
}
/// @brief Creates the bind array for sending Lease4 data to the database.
@@ -441,6 +445,14 @@ public:
state_str_ = boost::lexical_cast<std::string>(lease->state_);
bind_array.add(state_str_);
+ ConstElementPtr ctx = lease->getContext();
+ if (ctx) {
+ user_context_ = ctx->str();
+ } else {
+ user_context_ = "";
+ }
+ bind_array.add(user_context_);
+
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
"Could not create bind array from Lease4: "
@@ -487,6 +499,16 @@ public:
HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
HTYPE_ETHER));
+ user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
+ ConstElementPtr ctx;
+ if (!user_context_.empty()) {
+ ctx = Element::fromJSON(user_context_);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context_
+ << "' is not a JSON map");
+ }
+ }
+
Lease4Ptr result(new Lease4(addr4_, hwaddr,
client_id_buffer_, client_id_length_,
valid_lifetime_, 0, 0, cltt_,
@@ -495,6 +517,10 @@ public:
result->state_ = state;
+ if (ctx) {
+ result->setContext(ctx);
+ }
+
return (result);
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
@@ -543,9 +569,10 @@ private:
static const int HWTYPE_COL = 13;
static const int HWADDR_SOURCE_COL = 14;
static const int STATE_COL = 15;
+ static const size_t USER_CONTEXT_COL = 16;
//@}
/// @brief Number of columns in the table holding DHCPv6 leases.
- static const size_t LEASE_COLUMNS = 16;
+ static const size_t LEASE_COLUMNS = 17;
public:
PgSqlLease6Exchange()
@@ -574,6 +601,7 @@ public:
columns_.push_back("hwtype");
columns_.push_back("hwaddr_source");
columns_.push_back("state");
+ columns_.push_back("user_context");
}
/// @brief Creates the bind array for sending Lease6 data to the database.
@@ -670,6 +698,14 @@ public:
state_str_ = boost::lexical_cast<std::string>(lease->state_);
bind_array.add(state_str_);
+ ConstElementPtr ctx = lease->getContext();
+ if (ctx) {
+ user_context_ = ctx->str();
+ } else {
+ user_context_ = "";
+ }
+ bind_array.add(user_context_);
+
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
"Could not create bind array from Lease6: "
@@ -743,6 +779,16 @@ public:
uint32_t state;
getColumnValue(r, row , STATE_COL, state);
+ user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
+ ConstElementPtr ctx;
+ if (!user_context_.empty()) {
+ ctx = Element::fromJSON(user_context_);
+ if (!ctx || (ctx->getType() != Element::map)) {
+ isc_throw(BadValue, "user context '" << user_context_
+ << "' is not a JSON map");
+ }
+ }
+
Lease6Ptr result(new Lease6(lease_type_, addr, duid_ptr,
iaid_u_.uval_, pref_lifetime_,
valid_lifetime_, 0, 0,
@@ -752,6 +798,10 @@ public:
result->state_ = state;
+ if (ctx) {
+ result->setContext(ctx);
+ }
+
return (result);
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
diff --git a/src/lib/dhcpsrv/tests/csv_lease_file4_unittest.cc b/src/lib/dhcpsrv/tests/csv_lease_file4_unittest.cc
index a36d448999..d5fafd3bc4 100644
--- a/src/lib/dhcpsrv/tests/csv_lease_file4_unittest.cc
+++ b/src/lib/dhcpsrv/tests/csv_lease_file4_unittest.cc
@@ -15,6 +15,7 @@
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::util;
@@ -100,12 +101,12 @@ CSVLeaseFile4Test::absolutePath(const std::string& filename) {
void
CSVLeaseFile4Test::writeSampleFile() const {
io_.writeFile("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"
"192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,"
- "host.example.com,0\n"
- "192.0.2.1,,a:11:01:04,200,200,8,1,1,host.example.com,0\n"
+ "host.example.com,0,\n"
+ "192.0.2.1,,a:11:01:04,200,200,8,1,1,host.example.com,0,\n"
"192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7,"
- "0,0,,1\n");
+ "0,0,,1,{ \"foobar\": true }\n");
}
// This test checks the capability to read and parse leases from the file.
@@ -143,6 +144,7 @@ TEST_F(CSVLeaseFile4Test, parse) {
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("host.example.com", lease->hostname_);
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
// Second lease is malformed - HW address is empty when state
@@ -174,6 +176,8 @@ TEST_F(CSVLeaseFile4Test, parse) {
EXPECT_FALSE(lease->fqdn_rev_);
EXPECT_TRUE(lease->hostname_.empty());
EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
}
// There are no more leases. Reading should cause no error, but the returned
@@ -216,11 +220,12 @@ TEST_F(CSVLeaseFile4Test, recreate) {
checkStats(lf, 0, 0, 0, 1, 1, 0);
}
- // Create second lease, with non-NULL client id.
+ // Create second lease, with non-NULL client id and user context.
lease.reset(new Lease4(IOAddress("192.0.3.10"),
hwaddr1_,
CLIENTID, sizeof(CLIENTID),
100, 60, 90, 0, 7));
+ lease->setContext(Element::fromJSON("{ \"foobar\": true }"));
{
SCOPED_TRACE("Second write");
ASSERT_NO_THROW(lf.append(*lease));
@@ -231,10 +236,11 @@ TEST_F(CSVLeaseFile4Test, recreate) {
lf.close();
// Check that the contents of the csv file are correct.
EXPECT_EQ("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.3.2,00:01:02:03:04:05,,200,200,8,1,1,host.example.com,2\n"
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.3.2,00:01:02:03:04:05,,200,200,8,1,1,host.example.com,"
+ "2,\n"
"192.0.3.10,0d:0e:0a:0d:0b:0e:0e:0f,01:02:03:04,100,100,7,0,"
- "0,,0\n",
+ "0,,0,{ \"foobar\": true }\n",
io_.readFile());
}
@@ -252,9 +258,9 @@ TEST_F(CSVLeaseFile4Test, mixedSchemaload) {
// schema 2.0 record - has state
"192.0.2.2,06:07:08:09:2a:bc,,200,200,8,1,1,"
"two.example.com,1\n"
- // schema 2.0 record - has state
+ // schema 2.1 record - has state and user context
"192.0.2.3,06:07:08:09:3a:bc,,200,200,8,1,1,"
- "three.example.com,2\n"
+ "three.example.com,2,{ \"foobar\": true }\n"
);
// Open the lease file.
@@ -282,6 +288,7 @@ TEST_F(CSVLeaseFile4Test, mixedSchemaload) {
EXPECT_EQ("one.example.com", lease->hostname_);
// Verify that added state is DEFAULT
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
{
@@ -301,6 +308,7 @@ TEST_F(CSVLeaseFile4Test, mixedSchemaload) {
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("two.example.com", lease->hostname_);
EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
{
@@ -320,6 +328,8 @@ TEST_F(CSVLeaseFile4Test, mixedSchemaload) {
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("three.example.com", lease->hostname_);
EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
}
}
@@ -341,7 +351,7 @@ TEST_F(CSVLeaseFile4Test, tooFewHeaderColumns) {
TEST_F(CSVLeaseFile4Test, invalidHeaderColumn) {
// Create 1.0 file
io_.writeFile("address,hwaddr,BOGUS,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n");
// Open the lease file.
CSVLeaseFile4 lf(filename_);
@@ -353,10 +363,10 @@ TEST_F(CSVLeaseFile4Test, invalidHeaderColumn) {
TEST_F(CSVLeaseFile4Test, downGrade) {
// Create 2.0 PLUS a column file
io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state,FUTURE_COL\n"
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context,FUTURE_COL\n"
"192.0.2.3,06:07:08:09:3a:bc,,200,200,8,1,1,"
- "three.example.com,2,BOGUS\n");
+ "three.example.com,2,,BOGUS\n");
// Lease file should open and report as needing downgrade.
CSVLeaseFile4 lf(filename_);
@@ -383,6 +393,7 @@ TEST_F(CSVLeaseFile4Test, downGrade) {
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("three.example.com", lease->hostname_);
EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
}
@@ -390,9 +401,9 @@ TEST_F(CSVLeaseFile4Test, downGrade) {
// if they are in the declined state.
TEST_F(CSVLeaseFile4Test, declinedLeaseTest) {
io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.1,,,200,200,8,1,1,host.example.com,0\n"
- "192.0.2.1,,,200,200,8,1,1,host.example.com,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.1,,,200,200,8,1,1,host.example.com,0,\n"
+ "192.0.2.1,,,200,200,8,1,1,host.example.com,1,\n");
CSVLeaseFile4 lf(filename_);
ASSERT_NO_THROW(lf.open());
diff --git a/src/lib/dhcpsrv/tests/csv_lease_file6_unittest.cc b/src/lib/dhcpsrv/tests/csv_lease_file6_unittest.cc
index a8c3b8d473..74bda17ea5 100644
--- a/src/lib/dhcpsrv/tests/csv_lease_file6_unittest.cc
+++ b/src/lib/dhcpsrv/tests/csv_lease_file6_unittest.cc
@@ -15,6 +15,7 @@
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::util;
@@ -100,14 +101,14 @@ void
CSVLeaseFile6Test::writeSampleFile() const {
io_.writeFile("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"
"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"
- "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"
+ "2001:db8:1::1,,200,200,8,100,0,7,0,1,1,host.example.com,,1,\n"
"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"
+ "0,8,0,0,0,,,1,\n"
"3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,0,200,8,0,2,"
- "16,64,0,0,,,1\n");
+ "16,64,0,0,,,1,{ \"foobar\": true }\n");
}
// This test checks the capability to read and parse leases from the file.
@@ -147,6 +148,8 @@ TEST_F(CSVLeaseFile6Test, parse) {
EXPECT_TRUE(lease->fqdn_fwd_);
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("host.example.com", lease->hostname_);
+ EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
// Second lease is malformed - DUID is empty.
@@ -178,6 +181,8 @@ TEST_F(CSVLeaseFile6Test, parse) {
EXPECT_FALSE(lease->fqdn_fwd_);
EXPECT_FALSE(lease->fqdn_rev_);
EXPECT_TRUE(lease->hostname_.empty());
+ EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
// Reading the fourth lease should be successful.
@@ -201,6 +206,9 @@ TEST_F(CSVLeaseFile6Test, parse) {
EXPECT_FALSE(lease->fqdn_fwd_);
EXPECT_FALSE(lease->fqdn_rev_);
EXPECT_TRUE(lease->hostname_.empty());
+ EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
}
// There are no more leases. Reading should cause no error, but the returned
@@ -260,6 +268,7 @@ TEST_F(CSVLeaseFile6Test, recreate) {
7, 150, 300, 40, 70, 10, false, false,
"", HWAddrPtr(), 64));
lease->cltt_ = 0;
+ lease->setContext(Element::fromJSON("{ \"foobar\": true }"));
{
SCOPED_TRACE("Third write");
ASSERT_NO_THROW(lf.append(*lease));
@@ -268,13 +277,13 @@ TEST_F(CSVLeaseFile6Test, recreate) {
EXPECT_EQ("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
"lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "state,user_context\n"
"2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
- "200,200,8,100,0,7,128,1,1,host.example.com,,0\n"
+ "200,200,8,100,0,7,128,1,1,host.example.com,,0,\n"
"2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05"
- ",300,300,6,150,0,8,128,0,0,,,0\n"
+ ",300,300,6,150,0,8,128,0,0,,,0,\n"
"3000:1:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
- "300,300,10,150,2,7,64,0,0,,,0\n",
+ "300,300,10,150,2,7,64,0,0,,,0,{ \"foobar\": true }\n",
io_.readFile());
}
@@ -296,7 +305,12 @@ TEST_F(CSVLeaseFile6Test, mixedSchemaLoad) {
// schema 3.0 record - has hwaddr and state
"2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:03,"
- "200,200,8,100,0,7,0,1,1,three.example.com,0a:0b:0c:0d:0e,1\n");
+ "200,200,8,100,0,7,0,1,1,three.example.com,0a:0b:0c:0d:0e,1\n"
+
+ // schema 3.1 record - has hwaddr, state and user context
+ "2001:db8:1::4,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:03,"
+ "200,200,8,100,0,7,0,1,1,three.example.com,0a:0b:0c:0d:0e,1,"
+ "{ \"foobar\": true }\n");
// Open the lease file.
CSVLeaseFile6 lf(filename_);
@@ -326,6 +340,7 @@ TEST_F(CSVLeaseFile6Test, mixedSchemaLoad) {
EXPECT_FALSE(lease->hwaddr_);
// Verify that added state is STATE_DEFAULT
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
{
@@ -351,6 +366,7 @@ TEST_F(CSVLeaseFile6Test, mixedSchemaLoad) {
EXPECT_EQ("01:02:03:04:05", lease->hwaddr_->toText(false));
// Verify that added state is STATE_DEFAULT
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
{
@@ -375,6 +391,33 @@ TEST_F(CSVLeaseFile6Test, mixedSchemaLoad) {
ASSERT_TRUE(lease->hwaddr_);
EXPECT_EQ("0a:0b:0c:0d:0e", lease->hwaddr_->toText(false));
EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ EXPECT_FALSE(lease->getContext());
+ }
+
+ {
+ SCOPED_TRACE("Forth lease valid");
+ EXPECT_TRUE(lf.next(lease));
+ ASSERT_TRUE(lease);
+
+ // Verify that the lease attributes are correct.
+ EXPECT_EQ("2001:db8:1::4", lease->addr_.toText());
+ ASSERT_TRUE(lease->duid_);
+ EXPECT_EQ("00:01:02:03:04:05:06:0a:0b:0c:0d:0e:03", lease->duid_->toText());
+ EXPECT_EQ(200, lease->valid_lft_);
+ EXPECT_EQ(0, lease->cltt_);
+ EXPECT_EQ(8, lease->subnet_id_);
+ EXPECT_EQ(100, lease->preferred_lft_);
+ EXPECT_EQ(Lease::TYPE_NA, lease->type_);
+ EXPECT_EQ(7, lease->iaid_);
+ EXPECT_EQ(0, lease->prefixlen_);
+ EXPECT_TRUE(lease->fqdn_fwd_);
+ EXPECT_TRUE(lease->fqdn_rev_);
+ EXPECT_EQ("three.example.com", lease->hostname_);
+ ASSERT_TRUE(lease->hwaddr_);
+ EXPECT_EQ("0a:0b:0c:0d:0e", lease->hwaddr_->toText(false));
+ EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
}
}
@@ -395,7 +438,7 @@ TEST_F(CSVLeaseFile6Test, tooFewHeaderColumns) {
TEST_F(CSVLeaseFile6Test, invalidHeaderColumn) {
io_.writeFile("address,BOGUS,valid_lifetime,expire,subnet_id,pref_lifetime,"
"lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
- "hwaddr,state\n");
+ "hwaddr,state,user_context\n");
// Open should fail.
CSVLeaseFile6 lf(filename_);
@@ -410,12 +453,12 @@ TEST_F(CSVLeaseFile6Test, downGrade) {
// schema 1.0 header
"address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
"lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
- "hwaddr,state,FUTURE_COL\n"
+ "hwaddr,state,user_context,FUTURE_COL\n"
- // schema 3.0 record - has hwaddr and state
+ // schema 3.1 record - has hwaddr, state and user context
"2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:03,"
"200,200,8,100,0,7,0,1,1,three.example.com,0a:0b:0c:0d:0e,1,"
- "BOGUS\n");
+ "{ \"foobar\": true },BOGUS\n");
// Open should succeed in the event someone is downgrading.
CSVLeaseFile6 lf(filename_);
@@ -448,6 +491,8 @@ TEST_F(CSVLeaseFile6Test, downGrade) {
ASSERT_TRUE(lease->hwaddr_);
EXPECT_EQ("0a:0b:0c:0d:0e", lease->hwaddr_->toText(false));
EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
}
}
@@ -457,13 +502,13 @@ TEST_F(CSVLeaseFile6Test, downGrade) {
TEST_F(CSVLeaseFile6Test, declinedLeaseTest) {
io_.writeFile("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"
"2001:db8:1::1,00,"
- "200,200,8,100,0,7,0,1,1,host.example.com,,0\n"
+ "200,200,8,100,0,7,0,1,1,host.example.com,,0,\n"
"2001:db8:1::1,,"
- "200,200,8,100,0,7,0,1,1,host.example.com,,0\n"
+ "200,200,8,100,0,7,0,1,1,host.example.com,,0,\n"
"2001:db8:1::1,00,"
- "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");
CSVLeaseFile6 lf(filename_);
ASSERT_NO_THROW(lf.open());
diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
index ed1208fe21..62f5feb9e8 100644
--- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
@@ -22,6 +22,7 @@
using namespace std;
using namespace isc::asiolink;
+using namespace isc::data;
namespace isc {
namespace dhcp {
@@ -156,6 +157,8 @@ GenericLeaseMgrTest::initializeLease4(std::string address) {
lease->fqdn_rev_ = false;
lease->fqdn_fwd_ = false;
lease->hostname_ = "otherhost.example.com.";
+ lease->setContext(Element::fromJSON("{ \"foo\": true }"));
+
} else if (address == straddress4_[6]) {
lease->hwaddr_.reset(new HWAddr(vector<uint8_t>(6, 0x6e), HTYPE_ETHER));
// Same ClientId as straddress4_1
@@ -177,6 +180,7 @@ GenericLeaseMgrTest::initializeLease4(std::string address) {
lease->fqdn_rev_ = true;
lease->fqdn_fwd_ = true;
lease->hostname_ = "myhost.example.com.";
+ lease->setContext(Element::fromJSON("{ \"bar\": false }"));
} else {
// Unknown address, return an empty pointer.
@@ -288,6 +292,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) {
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = true;
lease->hostname_ = "hostname.example.com.";
+ lease->setContext(Element::fromJSON("{ \"foo\": true }"));
} else if (address == straddress6_[6]) {
// Same DUID as straddress6_1
@@ -317,6 +322,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) {
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = true;
lease->hostname_ = "hostname.example.com.";
+ lease->setContext(Element::fromJSON("{ \"bar\": false }"));
} else {
// Unknown address, return an empty pointer.
@@ -533,6 +539,17 @@ GenericLeaseMgrTest::testGetLease4HWAddr2() {
// Should be three leases, matching leases[1], [3] and [5].
ASSERT_EQ(3, returned.size());
+ // Check the lease[5] (and only this one) has an user context.
+ size_t contexts = 0;
+ for (Lease4Collection::const_iterator i = returned.begin();
+ i != returned.end(); ++i) {
+ if ((*i)->getContext()) {
+ ++contexts;
+ EXPECT_EQ("{ \"foo\": true }", (*i)->getContext()->str());
+ }
+ }
+ EXPECT_EQ(1, contexts);
+
// Easiest way to check is to look at the addresses.
vector<string> addresses;
for (Lease4Collection::const_iterator i = returned.begin();
@@ -708,6 +725,7 @@ void
GenericLeaseMgrTest::testBasicLease4() {
// Get the leases to be used for the test.
vector<Lease4Ptr> leases = createLeases4();
+ leases[2]->setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
// Start the tests. Add three leases to the database, read them back and
// check they are what we think they are.
@@ -785,6 +803,7 @@ void
GenericLeaseMgrTest::testBasicLease6() {
// Get the leases to be used for the test.
vector<Lease6Ptr> leases = createLeases6();
+ leases[2]->setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
// Start the tests. Add three leases to the database, read them back and
// check they are what we think they are.
@@ -1123,6 +1142,17 @@ GenericLeaseMgrTest::testGetLease4ClientId2() {
// Should be four leases, matching leases[1], [4], [5] and [6].
ASSERT_EQ(4, returned.size());
+ // Check the lease[5] (and only this one) has an user context.
+ size_t contexts = 0;
+ for (Lease4Collection::const_iterator i = returned.begin();
+ i != returned.end(); ++i) {
+ if ((*i)->getContext()) {
+ ++contexts;
+ EXPECT_EQ("{ \"foo\": true }", (*i)->getContext()->str());
+ }
+ }
+ EXPECT_EQ(1, contexts);
+
// Easiest way to check is to look at the addresses.
vector<string> addresses;
for (Lease4Collection::const_iterator i = returned.begin();
@@ -1516,6 +1546,7 @@ GenericLeaseMgrTest::testUpdateLease4() {
leases[1]->hostname_ = "modified.hostname.";
leases[1]->fqdn_fwd_ = !leases[1]->fqdn_fwd_;
leases[1]->fqdn_rev_ = !leases[1]->fqdn_rev_;;
+ leases[1]->setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
lmptr_->updateLease4(leases[1]);
// ... and check what is returned is what is expected.
@@ -1526,6 +1557,7 @@ GenericLeaseMgrTest::testUpdateLease4() {
// Alter the lease again and check.
++leases[1]->subnet_id_;
leases[1]->cltt_ += 6;
+ leases[1]->setContext(Element::fromJSON("{ \"foo\": \"bar\" }"));
lmptr_->updateLease4(leases[1]);
// Explicitly clear the returned pointer before getting new data to ensure
@@ -1572,6 +1604,7 @@ GenericLeaseMgrTest::testUpdateLease6() {
leases[1]->hostname_ = "modified.hostname.v6.";
leases[1]->fqdn_fwd_ = !leases[1]->fqdn_fwd_;
leases[1]->fqdn_rev_ = !leases[1]->fqdn_rev_;;
+ leases[1]->setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
lmptr_->updateLease6(leases[1]);
lmptr_->commit();
@@ -1586,6 +1619,7 @@ GenericLeaseMgrTest::testUpdateLease6() {
leases[1]->type_ = Lease::TYPE_TA;
leases[1]->cltt_ += 6;
leases[1]->prefixlen_ = 93;
+ leases[1]->setContext(Element::fromJSON("{ \"foo\": \"bar\" }"));
lmptr_->updateLease6(leases[1]);
l_returned.reset();
diff --git a/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc b/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc
index e84dbb03f8..1670f81087 100644
--- a/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc
+++ b/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc
@@ -18,6 +18,7 @@
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
@@ -143,11 +144,11 @@ protected:
/// @brief Sets up the header strings
virtual void SetUp() {
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";
}
};
@@ -171,17 +172,19 @@ LeaseFileLoaderTest::absolutePath(const std::string& filename) {
TEST_F(LeaseFileLoaderTest, loadWrite4) {
std::string test_str;
std::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,"
+ "{ \"foobar\": true }\n";
std::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,"
+ "{ \"foobar\": true }\n";
std::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,\n";
std::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";
std::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";
// Create lease file with leases for 192.0.2.1, 192.0.3.15. The lease
// entry for the 192.0.2.3 is invalid (lacks HW address) and should
@@ -212,6 +215,10 @@ TEST_F(LeaseFileLoaderTest, loadWrite4) {
ASSERT_TRUE(lease);
EXPECT_EQ(300, lease->cltt_);
+ // The lease for 192.0.2.1 should have user context.
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
+
// The invalid entry should not be loaded.
lease = getLease<Lease4Ptr>("192.0.2.3", storage);
ASSERT_FALSE(lease);
@@ -222,6 +229,7 @@ TEST_F(LeaseFileLoaderTest, loadWrite4) {
lease = getLease<Lease4Ptr>("192.0.3.15", storage);
ASSERT_TRUE(lease);
EXPECT_EQ(35, lease->cltt_);
+ EXPECT_FALSE(lease->getContext());
test_str = v4_hdr_ + a_2 + b_2;
writeLeases<Lease4, CSVLeaseFile4, Lease4Storage>(*lf, storage, test_str);
@@ -242,14 +250,14 @@ TEST_F(LeaseFileLoaderTest, loadWrite4) {
TEST_F(LeaseFileLoaderTest, loadWrite4LeaseRemove) {
std::string test_str;
std::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";
std::string a_2 = "192.0.2.1,06:07:08:09:0a:bc,,"
- "0,500,8,1,1,host.example.com,1\n";
+ "0,500,8,1,1,host.example.com,1,\n";
std::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,\n";
std::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";
// Create lease file in which one of the entries for 192.0.2.1
@@ -297,20 +305,21 @@ TEST_F(LeaseFileLoaderTest, loadWrite4LeaseRemove) {
TEST_F(LeaseFileLoaderTest, loadWrite6) {
std::string test_str;
std::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";
+ "200,200,8,100,0,7,0,1,1,host.example.com,,1,"
+ "{ \"foobar\": true }\n";
std::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,"
+ "{ \"foobar\": true }\n";
std::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,"
+ "{ \"foobar\": true }\n";
std::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,\n";
std::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";
std::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";
// Create a lease file with three valid leases: 2001:db8:1::1,
@@ -341,16 +350,22 @@ TEST_F(LeaseFileLoaderTest, loadWrite6) {
ASSERT_TRUE(lease);
EXPECT_EQ(200, lease->cltt_);
+ // The 2001:db8:1::1 should have user context.
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
+
// The 3000:1:: lease should be present.
lease = getLease<Lease6Ptr>("3000:1::", storage);
ASSERT_TRUE(lease);
EXPECT_EQ(100, lease->cltt_);
+ EXPECT_FALSE(lease->getContext());
// The 2001:db8:2::10 should be present and the cltt should be
// calculated according to the last entry in the lease file.
lease = getLease<Lease6Ptr>("2001:db8:2::10", storage);
ASSERT_TRUE(lease);
EXPECT_EQ(500, lease->cltt_);
+ EXPECT_FALSE(lease->getContext());
test_str = v6_hdr_ + a_3 + b_2 + c_1;
writeLeases<Lease6, CSVLeaseFile6, Lease6Storage>(*lf, storage, test_str);
@@ -371,14 +386,14 @@ TEST_F(LeaseFileLoaderTest, loadWrite6) {
TEST_F(LeaseFileLoaderTest, loadWrite6LeaseRemove) {
std::string test_str;
std::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";
+ "200,200,8,100,0,7,0,1,1,host.example.com,,1,\n";
std::string a_2 = "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
- "0,400,8,100,0,7,0,1,1,host.example.com,,1\n";
+ "0,400,8,100,0,7,0,1,1,host.example.com,,1,\n";
std::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,\n";
std::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";
// Create lease file in which one of the entries for the 2001:db8:1::1
// has valid lifetime set to 0, in which case the lease should be
@@ -423,13 +438,14 @@ TEST_F(LeaseFileLoaderTest, loadWrite6LeaseRemove) {
TEST_F(LeaseFileLoaderTest, loadMaxErrors) {
std::string test_str;
std::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";
std::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";
- std::string b_1 = "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com,0\n";
+ std::string b_1 = "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com,"
+ "0,\n";
- std::string c_1 = "192.0.2.10,01:02:03:04:05:06,,200,300,8,1,1,,1\n";
+ std::string c_1 = "192.0.2.10,01:02:03:04:05:06,,200,300,8,1,1,,1,\n";
// Create a lease file for which there is a number of invalid
// entries. b_1 is invalid and gets used multiple times.
@@ -493,8 +509,8 @@ TEST_F(LeaseFileLoaderTest, loadMaxErrors) {
// and comparing that with the expected value.
TEST_F(LeaseFileLoaderTest, loadWriteLeaseWithZeroLifetime) {
std::string test_str;
- std::string a_1 = "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,,1\n";
- std::string b_2 = "192.0.2.3,06:07:08:09:0a:bd,,0,200,8,1,1,,1\n";
+ std::string a_1 = "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,,1,\n";
+ std::string b_2 = "192.0.2.3,06:07:08:09:0a:bd,,0,200,8,1,1,,1,\n";
// Create lease file. The second lease has a valid lifetime of 0.
test_str = v4_hdr_ + a_1 + b_2;
diff --git a/src/lib/dhcpsrv/tests/lease_unittest.cc b/src/lib/dhcpsrv/tests/lease_unittest.cc
index a81719e503..8b3bac04f2 100644
--- a/src/lib/dhcpsrv/tests/lease_unittest.cc
+++ b/src/lib/dhcpsrv/tests/lease_unittest.cc
@@ -140,6 +140,7 @@ TEST_F(Lease4Test, constructor) {
EXPECT_TRUE(lease.fqdn_fwd_);
EXPECT_TRUE(lease.fqdn_rev_);
EXPECT_EQ(Lease::STATE_DEFAULT, lease.state_);
+ EXPECT_FALSE(lease.getContext());
}
}
@@ -157,6 +158,9 @@ TEST_F(Lease4Test, copyConstructor) {
// or the default state will be set for the copied lease.
lease.state_ = Lease::STATE_DECLINED;
+ // Set an user context.
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
+
// Use copy constructor to copy the lease.
Lease4 copied_lease(lease);
@@ -166,6 +170,11 @@ TEST_F(Lease4Test, copyConstructor) {
// Client IDs are equal, but they should be in two distinct pointers.
EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
+ // User context are equal and point to the same object.
+ ASSERT_TRUE(copied_lease.getContext());
+ EXPECT_TRUE(lease.getContext() == copied_lease.getContext());
+ EXPECT_TRUE(*lease.getContext() == *copied_lease.getContext());
+
// Hardware addresses are equal, but they should point to two objects,
// each holding the same data. The content should be equal...
EXPECT_TRUE(*lease.hwaddr_ == *copied_lease.hwaddr_);
@@ -194,6 +203,9 @@ TEST_F(Lease4Test, operatorAssign) {
// or the default state will be set for the copied lease.
lease.state_ = Lease::STATE_DECLINED;
+ // Set an user context.
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
+
// Create a default lease.
Lease4 copied_lease;
// Use assignment operator to assign new lease.
@@ -205,6 +217,11 @@ TEST_F(Lease4Test, operatorAssign) {
// Client IDs are equal, but they should be in two distinct pointers.
EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
+ // User context are equal and point to the same object.
+ ASSERT_TRUE(copied_lease.getContext());
+ EXPECT_TRUE(lease.getContext() == copied_lease.getContext());
+ EXPECT_TRUE(*lease.getContext() == *copied_lease.getContext());
+
// Hardware addresses are equal, but they should point to two objects,
// each holding the same data. The content should be equal...
EXPECT_TRUE(*lease.hwaddr_ == *copied_lease.hwaddr_);
@@ -294,6 +311,7 @@ TEST_F(Lease4Test, operatorEquals) {
// Check when the leases are equal.
Lease4 lease1(ADDRESS, hwaddr_, clientid_, VALID_LIFETIME, current_time, 0,
0, SUBNET_ID);
+ lease1.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
// We need to make an explicit copy. Otherwise the second lease will just
// store a pointer and we'll have two leases pointing to a single HWAddr
@@ -303,6 +321,7 @@ TEST_F(Lease4Test, operatorEquals) {
Lease4 lease2(ADDRESS, hwcopy, clientid_copy, VALID_LIFETIME, current_time,
0, 0, SUBNET_ID);
+ lease2.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
EXPECT_TRUE(lease1 == lease2);
EXPECT_FALSE(lease1 != lease2);
@@ -394,6 +413,20 @@ TEST_F(Lease4Test, operatorEquals) {
lease2.state_ += 1;
EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.setContext(Element::fromJSON("{ \"foobar\": 5678 }"));
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.setContext(ConstElementPtr());
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease2.setContext(ConstElementPtr());
+ EXPECT_TRUE(lease1 == lease2); // Check that no user context has mase the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
}
// Verify that the client id can be returned as a vector object and if client
@@ -438,6 +471,7 @@ TEST_F(Lease4Test, toText) {
const time_t current_time = 12345678;
Lease4 lease(IOAddress("192.0.2.3"), hwaddr_, clientid_, 3600, 123,
456, current_time, 789);
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
std::stringstream expected;
expected << "Address: 192.0.2.3\n"
@@ -448,13 +482,16 @@ TEST_F(Lease4Test, toText) {
<< "Hardware addr: " << hwaddr_->toText(false) << "\n"
<< "Client id: " << clientid_->toText() << "\n"
<< "Subnet ID: 789\n"
- << "State: default\n";
+ << "State: default\n"
+ << "User context: { \"foobar\": 1234 }\n";
EXPECT_EQ(expected.str(), lease.toText());
- // Now let's try with a lease without hardware address and client identifier.
+ // Now let's try with a lease without hardware address, client identifier
+ // and user context.
lease.hwaddr_.reset();
lease.client_id_.reset();
+ lease.setContext(ConstElementPtr());
expected.str("");
expected << "Address: 192.0.2.3\n"
<< "Valid life: 3600\n"
@@ -474,6 +511,7 @@ TEST_F(Lease4Test, toElement) {
const time_t current_time = 12345678;
Lease4 lease(IOAddress("192.0.2.3"), hwaddr_, clientid_, 3600, 123,
456, current_time, 789, true, true, "urania.example.org");
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
std::string expected = "{"
"\"client-id\": \"17:34:e2:ff:09:92:54\","
@@ -485,16 +523,36 @@ TEST_F(Lease4Test, toElement) {
"\"ip-address\": \"192.0.2.3\","
"\"state\": 0,"
"\"subnet-id\": 789,"
+ "\"user-context\": { \"foobar\": 1234 },"
"\"valid-lft\": 3600 "
"}";
runToElementTest<Lease4>(expected, lease);
- // Now let's try with a lease without client-id.
+ // Now let's try with a lease without client-id and user context.
lease.client_id_.reset();
+ lease.setContext(ConstElementPtr());
+
+ expected = "{"
+ "\"cltt\": 12345678,"
+ "\"fqdn-fwd\": true,"
+ "\"fqdn-rev\": true,"
+ "\"hostname\": \"urania.example.org\","
+ "\"hw-address\": \"08:00:2b:02:3f:4e\","
+ "\"ip-address\": \"192.0.2.3\","
+ "\"state\": 0,"
+ "\"subnet-id\": 789,"
+ "\"valid-lft\": 3600 "
+ "}";
+
+ runToElementTest<Lease4>(expected, lease);
+
+ // And to finish try with a comment.
+ lease.setContext(Element::fromJSON("{ \"comment\": \"a comment\" }"));
expected = "{"
"\"cltt\": 12345678,"
+ "\"comment\": \"a comment\","
"\"fqdn-fwd\": true,"
"\"fqdn-rev\": true,"
"\"hostname\": \"urania.example.org\","
@@ -520,6 +578,7 @@ TEST_F(Lease4Test, fromElement) {
"\"ip-address\": \"192.0.2.3\","
"\"state\": 0,"
"\"subnet-id\": 789,"
+ "\"user-context\": { \"foo\": \"bar\" },"
"\"valid-lft\": 3600 "
"}";
@@ -540,6 +599,8 @@ TEST_F(Lease4Test, fromElement) {
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("urania.example.org", lease->hostname_);
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foo\": \"bar\" }", lease->getContext()->str());
}
// Test that specifying invalid values for a lease or not specifying
@@ -578,6 +639,10 @@ TEST_F(Lease4Test, fromElementInvalidValues) {
testInvalidElement<Lease4>(json, "subnet-id", -5, false);
testInvalidElement<Lease4>(json, "valid-lft", std::string("xyz"));
testInvalidElement<Lease4>(json, "valid-lft", -3, false);
+ testInvalidElement<Lease4>(json, "user-context", "[ ]", false);
+ testInvalidElement<Lease4>(json, "user-context", 1234, false);
+ testInvalidElement<Lease4>(json, "user-context", false, false);
+ testInvalidElement<Lease4>(json, "user-context", "foo", false);
}
// Verify that decline() method properly clears up specific fields.
@@ -607,6 +672,7 @@ TEST_F(Lease4Test, decline) {
EXPECT_FALSE(lease.fqdn_rev_);
EXPECT_EQ(Lease::STATE_DECLINED, lease.state_);
EXPECT_EQ(123, lease.valid_lft_);
+ EXPECT_FALSE(lease.getContext());
}
// Verify that the lease states are correctly returned in the textual format.
@@ -668,7 +734,7 @@ TEST(Lease6Test, Lease6ConstructorDefault) {
EXPECT_FALSE(lease->fqdn_fwd_);
EXPECT_FALSE(lease->fqdn_rev_);
EXPECT_TRUE(lease->hostname_.empty());
-
+ EXPECT_FALSE(lease->getContext());
}
// Lease6 must be instantiated with a DUID, not with NULL pointer
@@ -745,6 +811,9 @@ TEST(Lease6Test, operatorEquals) {
Lease6 lease2(Lease::TYPE_NA, addr, duid, iaid, 100, 200, 50, 80,
subnet_id);
+ lease1.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
+ lease2.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
+
// cltt_ constructs with time(NULL), make sure they are always equal
lease1.cltt_ = lease2.cltt_;
@@ -859,6 +928,20 @@ TEST(Lease6Test, operatorEquals) {
lease2.state_ += 1;
EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.setContext(Element::fromJSON("{ \"foobar\": 5678 }"));
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.setContext(ConstElementPtr());
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease2.setContext(ConstElementPtr());
+ EXPECT_TRUE(lease1 == lease2); // Check that no user context has mase the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
}
// Checks if lease expiration is calculated properly
@@ -941,6 +1024,7 @@ TEST(Lease6Test, decline) {
EXPECT_FALSE(lease.fqdn_rev_);
EXPECT_EQ(Lease::STATE_DECLINED, lease.state_);
EXPECT_EQ(123, lease.valid_lft_);
+ EXPECT_FALSE(lease.getContext());
}
// Verify the behavior of the function which checks FQDN data for equality.
@@ -972,6 +1056,7 @@ TEST(Lease6Test, toText) {
400, 800, 100, 200, 5678, hwaddr, 128);
lease.cltt_ = 12345678;
lease.state_ = Lease::STATE_DECLINED;
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
std::stringstream expected;
expected << "Type: IA_NA(" << static_cast<int>(Lease::TYPE_NA) << ")\n"
@@ -984,12 +1069,14 @@ TEST(Lease6Test, toText) {
<< "DUID: 00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f\n"
<< "Hardware addr: " << hwaddr->toText(false) << "\n"
<< "Subnet ID: 5678\n"
- << "State: declined\n";
+ << "State: declined\n"
+ << "User context: { \"foobar\": 1234 }\n";
EXPECT_EQ(expected.str(), lease.toText());
- // Now let's try with a lease without hardware address.
+ // Now let's try with a lease without hardware address and user context.
lease.hwaddr_.reset();
+ lease.setContext(ConstElementPtr());
expected.str("");
expected << "Type: IA_NA(" << static_cast<int>(Lease::TYPE_NA) << ")\n"
<< "Address: 2001:db8::1\n"
@@ -1019,6 +1106,7 @@ TEST(Lease6Test, toElementAddress) {
lease.cltt_ = 12345678;
lease.state_ = Lease::STATE_DECLINED;
lease.hostname_ = "urania.example.org";
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
std::string expected = "{"
"\"cltt\": 12345678,"
@@ -1033,16 +1121,39 @@ TEST(Lease6Test, toElementAddress) {
"\"state\": 1,"
"\"subnet-id\": 5678,"
"\"type\": \"IA_NA\","
+ "\"user-context\": { \"foobar\": 1234 },"
"\"valid-lft\": 800"
"}";
runToElementTest<Lease6>(expected, lease);
- // Now let's try with a lease without hardware address.
+ // Now let's try with a lease without hardware address and user context.
lease.hwaddr_.reset();
+ lease.setContext(ConstElementPtr());
+
+ expected = "{"
+ "\"cltt\": 12345678,"
+ "\"duid\": \"00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f\","
+ "\"fqdn-fwd\": false,"
+ "\"fqdn-rev\": false,"
+ "\"hostname\": \"urania.example.org\","
+ "\"iaid\": 123456,"
+ "\"ip-address\": \"2001:db8::1\","
+ "\"preferred-lft\": 400,"
+ "\"state\": 1,"
+ "\"subnet-id\": 5678,"
+ "\"type\": \"IA_NA\","
+ "\"valid-lft\": 800"
+ "}";
+
+ runToElementTest<Lease6>(expected, lease);
+
+ // And to finish try with a comment.
+ lease.setContext(Element::fromJSON("{ \"comment\": \"a comment\" }"));
expected = "{"
"\"cltt\": 12345678,"
+ "\"comment\": \"a comment\","
"\"duid\": \"00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f\","
"\"fqdn-fwd\": false,"
"\"fqdn-rev\": false,"
@@ -1073,6 +1184,7 @@ TEST(Lease6Test, toElementPrefix) {
lease.cltt_ = 12345678;
lease.state_ = Lease::STATE_DEFAULT;
lease.hostname_ = "urania.example.org";
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
ElementPtr l = lease.toElement();
@@ -1120,10 +1232,24 @@ TEST(Lease6Test, toElementPrefix) {
ASSERT_TRUE(l->contains("hostname"));
EXPECT_EQ("urania.example.org", l->get("hostname")->stringValue());
- // Now let's try with a lease without hardware address.
+ ASSERT_TRUE(l->contains("user-context"));
+ EXPECT_EQ("{ \"foobar\": 1234 }", l->get("user-context")->str());
+
+ // Now let's try with a lease without hardware address or user context.
lease.hwaddr_.reset();
+ lease.setContext(ConstElementPtr());
l = lease.toElement();
EXPECT_FALSE(l->contains("hw-address"));
+ EXPECT_FALSE(l->contains("user-context"));
+ EXPECT_FALSE(l->contains("comment"));
+
+ // And to finish try with a comment.
+ lease.setContext(Element::fromJSON("{ \"comment\": \"a comment\" }"));
+ l = lease.toElement();
+ EXPECT_FALSE(l->contains("hw-address"));
+ EXPECT_FALSE(l->contains("user-context"));
+ ASSERT_TRUE(l->contains("comment"));
+ EXPECT_EQ("a comment", l->get("comment")->stringValue());
}
// Verify that the IA_NA can be created from JSON.
@@ -1141,6 +1267,7 @@ TEST(Lease6Test, fromElementNA) {
"\"state\": 1,"
"\"subnet-id\": 5678,"
"\"type\": \"IA_NA\","
+ "\"user-context\": { \"foobar\": 1234 },"
"\"valid-lft\": 800"
"}";
@@ -1159,6 +1286,8 @@ TEST(Lease6Test, fromElementNA) {
EXPECT_FALSE(lease->fqdn_rev_);
EXPECT_EQ("urania.example.org", lease->hostname_);
EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ ASSERT_TRUE(lease->getContext());
+ EXPECT_EQ("{ \"foobar\": 1234 }", lease->getContext()->str());
// IPv6 specific properties.
EXPECT_EQ(Lease::TYPE_NA, lease->type_);
@@ -1169,7 +1298,7 @@ TEST(Lease6Test, fromElementNA) {
EXPECT_EQ(400, lease->preferred_lft_);
}
-// Verify that the IA_NA can be created from JSON.
+// Verify that the IA_PD can be created from JSON.
TEST(Lease6Test, fromElementPD) {
std::string json = "{"
"\"cltt\": 12345678,"
@@ -1203,6 +1332,7 @@ TEST(Lease6Test, fromElementPD) {
EXPECT_FALSE(lease->fqdn_rev_);
EXPECT_EQ("urania.example.org", lease->hostname_);
EXPECT_EQ(Lease::STATE_DEFAULT , lease->state_);
+ EXPECT_FALSE(lease->getContext());
// IPv6 specific properties.
EXPECT_EQ(Lease::TYPE_PD, lease->type_);
@@ -1262,6 +1392,10 @@ TEST(Lease6Test, fromElementInvalidValues) {
testInvalidElement<Lease6>(json, "type", -3, false);
testInvalidElement<Lease6>(json, "valid-lft", std::string("xyz"));
testInvalidElement<Lease6>(json, "valid-lft", -3, false);
+ testInvalidElement<Lease6>(json, "user-context", "[ ]", false);
+ testInvalidElement<Lease6>(json, "user-context", 1234, false);
+ testInvalidElement<Lease6>(json, "user-context", false, false);
+ testInvalidElement<Lease6>(json, "user-context", "foo", false);
}
// Verify that the lease states are correctly returned in the textual format.
diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
index 84735a9e11..8d4a986ad6 100644
--- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
@@ -498,20 +498,20 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCleanup4) {
// stored.
std::string new_file_contents =
"address,hwaddr,client_id,valid_lifetime,expire,"
- "subnet_id,fqdn_fwd,fqdn_rev,hostname,state\n";
+ "subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context\n";
// This string contains the contents of the lease file with exactly
// one lease, but two entries. One of the entries should be removed
// as a result of lease file cleanup.
std::string current_file_contents = new_file_contents +
- "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n"
- "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,1\n";
+ "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1,{ \"foo\": true }\n"
+ "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,1,\n";
LeaseFileIO current_file(getLeaseFilePath("leasefile4_0.csv"));
current_file.writeFile(current_file_contents);
std::string previous_file_contents = new_file_contents +
- "192.0.2.3,03:03:03:03:03:03,,200,200,8,1,1,,1\n"
- "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,1\n";
+ "192.0.2.3,03:03:03:03:03:03,,200,200,8,1,1,,1,\n"
+ "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,1,{ \"bar\": true }\n";
LeaseFileIO previous_file(getLeaseFilePath("leasefile4_0.csv.2"));
previous_file.writeFile(previous_file_contents);
@@ -548,15 +548,15 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCleanup4) {
ASSERT_NO_THROW(lease_mgr->addLease(new_lease));
std::string updated_file_contents = new_file_contents +
- "192.0.2.45,00:00:00:00:00:00,,100,100,1,0,0,,0\n";
+ "192.0.2.45,00:00:00:00:00:00,,100,100,1,0,0,,0,\n";
EXPECT_EQ(updated_file_contents, current_file.readFile());
// This string contains the contents of the lease file we
// expect after the LFC run. It has two leases with one
// entry each.
std::string result_file_contents = new_file_contents +
- "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,1\n"
- "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,1\n";
+ "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,1,\n"
+ "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,1,{ \"bar\": true }\n";
// The LFC should have created a file with the two leases and moved it
// to leasefile4_0.csv.2
@@ -575,24 +575,24 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCleanup6) {
std::string new_file_contents =
"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";
// This string contains the contents of the lease file with exactly
// one lease, but two entries. One of the entries should be removed
// as a result of lease file cleanup.
std::string current_file_contents = new_file_contents +
"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,,,1\n"
+ "8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
- "8,100,0,7,0,1,1,,,1\n";
+ "8,100,0,7,0,1,1,,,1,{ \"foo\": true }\n";
LeaseFileIO current_file(getLeaseFilePath("leasefile6_0.csv"));
current_file.writeFile(current_file_contents);
std::string previous_file_contents = new_file_contents +
"2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,200,"
- "8,100,0,7,0,1,1,,,1\n"
+ "8,100,0,7,0,1,1,,,1,{ \"bar\": true }\n"
"2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
- "8,100,0,7,0,1,1,,,1\n";
+ "8,100,0,7,0,1,1,,,1,\n";
LeaseFileIO previous_file(getLeaseFilePath("leasefile6_0.csv.2"));
previous_file.writeFile(previous_file_contents);
@@ -631,7 +631,7 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCleanup6) {
std::string update_file_contents = new_file_contents +
"3000::1,00:00:00:00:00:00:00:00:00:00:00:00:00,400,"
- "400,2,300,0,123,128,0,0,,,0\n";
+ "400,2,300,0,123,128,0,0,,,0,\n";
EXPECT_EQ(update_file_contents, current_file.readFile());
// This string contains the contents of the lease file we
@@ -639,9 +639,9 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCleanup6) {
// entry each.
std::string result_file_contents = new_file_contents +
"2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
- "8,100,0,7,0,1,1,,,1\n"
+ "8,100,0,7,0,1,1,,,1,{ \"foo\": true }\n"
"2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
- "8,100,0,7,0,1,1,,,1\n";
+ "8,100,0,7,0,1,1,,,1,\n";
// The LFC should have created a file with the two leases and moved it
// to leasefile6_0.csv.2
@@ -659,11 +659,11 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCleanupStartFail) {
// stored.
std::string new_file_contents =
"address,hwaddr,client_id,valid_lifetime,expire,"
- "subnet_id,fqdn_fwd,fqdn_rev,hostname,state\n";
+ "subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context\n";
// Create the lease file to be used by the backend.
std::string current_file_contents = new_file_contents +
- "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n";
+ "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1,\n";
LeaseFileIO current_file(getLeaseFilePath("leasefile4_0.csv"));
current_file.writeFile(current_file_contents);
@@ -700,15 +700,15 @@ TEST_F(MemfileLeaseMgrTest, leaseFileFinish) {
std::string new_file_contents =
"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";
// This string contains the contents of the current lease file.
// It should not be moved.
std::string current_file_contents = new_file_contents +
"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,,,1\n"
+ "8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
- "8,100,0,7,0,1,1,,,1\n";
+ "8,100,0,7,0,1,1,,,1,\n";
LeaseFileIO current_file(getLeaseFilePath("leasefile6_0.csv"));
current_file.writeFile(current_file_contents);
@@ -716,7 +716,7 @@ TEST_F(MemfileLeaseMgrTest, leaseFileFinish) {
// be moved to the previous file.
std::string finish_file_contents = new_file_contents +
"2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
- "8,100,0,7,0,1,1,,,1\n";
+ "8,100,0,7,0,1,1,,,1,\n";
LeaseFileIO finish_file(getLeaseFilePath("leasefile6_0.csv.completed"));
finish_file.writeFile(finish_file_contents);
@@ -763,15 +763,15 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCopy) {
std::string new_file_contents =
"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";
// This string contains the contents of the current lease file.
// It should not be moved.
std::string current_file_contents = new_file_contents +
"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,,,1\n"
+ "8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
- "8,100,0,7,0,1,1,,,1\n";
+ "8,100,0,7,0,1,1,,,1,{ \"foo\": true }\n";
LeaseFileIO current_file(getLeaseFilePath("leasefile6_0.csv"));
current_file.writeFile(current_file_contents);
@@ -781,7 +781,7 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCopy) {
// the same.
std::string input_file_contents = new_file_contents +
"2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
- "8,100,0,7,0,1,1,,,1\n";
+ "8,100,0,7,0,1,1,,,1,{ \"foo\": true }\n";
LeaseFileIO input_file(getLeaseFilePath("leasefile6_0.csv.1"));
input_file.writeFile(input_file_contents);
@@ -1132,22 +1132,22 @@ TEST_F(MemfileLeaseMgrTest, getDeclined6) {
TEST_F(MemfileLeaseMgrTest, load4MultipleLeaseFiles) {
LeaseFileIO io2(getLeaseFilePath("leasefile4_0.csv.2"));
io2.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n"
- "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,200,8,1,1,,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1,\n"
+ "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,200,8,1,1,,1,\n");
LeaseFileIO io1(getLeaseFilePath("leasefile4_0.csv.1"));
io1.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.1,01:01:01:01:01:01,,200,200,8,1,1,,1\n"
- "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,400,8,1,1,,1\n"
- "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,200,8,1,1,,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.1,01:01:01:01:01:01,,200,200,8,1,1,,1,\n"
+ "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,400,8,1,1,,1,\n"
+ "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,200,8,1,1,,1,\n");
LeaseFileIO io(getLeaseFilePath("leasefile4_0.csv"));
io.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.10,0a:0a:0a:0a:0a:0a,,200,200,8,1,1,,1\n"
- "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,400,8,1,1,,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.10,0a:0a:0a:0a:0a:0a,,200,200,8,1,1,,1,\n"
+ "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,400,8,1,1,,1,\n");
startBackend(V4);
@@ -1190,27 +1190,27 @@ TEST_F(MemfileLeaseMgrTest, load4MultipleLeaseFiles) {
TEST_F(MemfileLeaseMgrTest, load4CompletedFile) {
LeaseFileIO io2(getLeaseFilePath("leasefile4_0.csv.2"));
io2.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n"
- "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,200,8,1,1,,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1,\n"
+ "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,200,8,1,1,,1,\n");
LeaseFileIO io1(getLeaseFilePath("leasefile4_0.csv.1"));
io1.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.1,01:01:01:01:01:01,,200,200,8,1,1,,1\n"
- "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,400,8,1,1,,1\n"
- "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,200,8,1,1,,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.1,01:01:01:01:01:01,,200,200,8,1,1,,1,\n"
+ "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,400,8,1,1,,1,\n"
+ "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,200,8,1,1,,1,\n");
LeaseFileIO io(getLeaseFilePath("leasefile4_0.csv"));
io.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.10,0a:0a:0a:0a:0a:0a,,200,200,8,1,1,,1\n"
- "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,400,8,1,1,,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.10,0a:0a:0a:0a:0a:0a,,200,200,8,1,1,,1,\n"
+ "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,400,8,1,1,,1,\n");
LeaseFileIO ioc(getLeaseFilePath("leasefile4_0.csv.completed"));
ioc.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
- "fqdn_fwd,fqdn_rev,hostname,state\n"
- "192.0.2.13,ff:ff:ff:ff:ff:ff,,200,200,8,1,1,,1\n");
+ "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
+ "192.0.2.13,ff:ff:ff:ff:ff:ff,,200,200,8,1,1,,1,\n");
startBackend(V4);
@@ -1266,32 +1266,32 @@ TEST_F(MemfileLeaseMgrTest, load4LFCInProgress) {
TEST_F(MemfileLeaseMgrTest, load6MultipleLeaseFiles) {
LeaseFileIO io2(getLeaseFilePath("leasefile6_0.csv.2"));
io2.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::1,01:01:01:01:01:01:01:01:01:01:01:01:01,"
- "200,200,8,100,0,7,0,1,1,,,1\n"
+ "200,200,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
LeaseFileIO io1(getLeaseFilePath("leasefile6_0.csv.1"));
io1.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::3,03:03:03:03:03:03:03:03:03:03:03:03:03,"
- "200,200,8,100,0,7,0,1,1,,,1\n"
+ "200,200,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02,"
- "300,800,8,100,0,7,0,1,1,,,1\n"
+ "300,800,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::4,04:04:04:04:04:04:04:04:04:04:04:04:04,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
LeaseFileIO io(getLeaseFilePath("leasefile6_0.csv"));
io.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::4,04:04:04:04:04:04:04:04:04:04:04:04:04,"
- "400,1000,8,100,0,7,0,1,1,,,1\n"
+ "400,1000,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::5,05:05:05:05:05:05:05:05:05:05:05:05:05,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
startBackend(V6);
@@ -1332,23 +1332,23 @@ TEST_F(MemfileLeaseMgrTest, load6MultipleLeaseFiles) {
TEST_F(MemfileLeaseMgrTest, load6MultipleNoSecondFile) {
LeaseFileIO io1(getLeaseFilePath("leasefile6_0.csv.1"));
io1.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::3,03:03:03:03:03:03:03:03:03:03:03:03:03,"
- "200,200,8,100,0,7,0,1,1,,,1\n"
+ "200,200,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02,"
- "300,800,8,100,0,7,0,1,1,,,1\n"
+ "300,800,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::4,04:04:04:04:04:04:04:04:04:04:04:04:04,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
LeaseFileIO io(getLeaseFilePath("leasefile6_0.csv"));
io.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::4,04:04:04:04:04:04:04:04:04:04:04:04:04,"
- "400,1000,8,100,0,7,0,1,1,,,1\n"
+ "400,1000,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::5,05:05:05:05:05:05:05:05:05:05:05:05:05,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
startBackend(V6);
@@ -1380,21 +1380,21 @@ TEST_F(MemfileLeaseMgrTest, load6MultipleNoSecondFile) {
TEST_F(MemfileLeaseMgrTest, load6MultipleNoFirstFile) {
LeaseFileIO io2(getLeaseFilePath("leasefile6_0.csv.2"));
io2.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::1,01:01:01:01:01:01:01:01:01:01:01:01:01,"
- "200,200,8,100,0,7,0,1,1,,,1\n"
+ "200,200,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
LeaseFileIO io(getLeaseFilePath("leasefile6_0.csv"));
io.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::4,04:04:04:04:04:04:04:04:04:04:04:04:04,"
- "400,1000,8,100,0,7,0,1,1,,,1\n"
+ "400,1000,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::5,05:05:05:05:05:05:05:05:05:05:05:05:05,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
startBackend(V6);
@@ -1428,39 +1428,39 @@ TEST_F(MemfileLeaseMgrTest, load6MultipleNoFirstFile) {
TEST_F(MemfileLeaseMgrTest, load6CompletedFile) {
LeaseFileIO io2(getLeaseFilePath("leasefile6_0.csv.2"));
io2.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::1,01:01:01:01:01:01:01:01:01:01:01:01:01,"
- "200,200,8,100,0,7,0,1,1,,,1\n"
+ "200,200,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
LeaseFileIO io1(getLeaseFilePath("leasefile6_0.csv.1"));
io1.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::3,03:03:03:03:03:03:03:03:03:03:03:03:03,"
- "200,200,8,100,0,7,0,1,1,,,1\n"
+ "200,200,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02,"
- "300,800,8,100,0,7,0,1,1,,,1\n"
+ "300,800,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::4,04:04:04:04:04:04:04:04:04:04:04:04:04,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
LeaseFileIO io(getLeaseFilePath("leasefile6_0.csv"));
io.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::4,04:04:04:04:04:04:04:04:04:04:04:04:04,"
- "400,1000,8,100,0,7,0,1,1,,,1\n"
+ "400,1000,8,100,0,7,0,1,1,,,1,\n"
"2001:db8:1::5,05:05:05:05:05:05:05:05:05:05:05:05:05,"
- "200,200,8,100,0,7,0,1,1,,,1\n");
+ "200,200,8,100,0,7,0,1,1,,,1,\n");
LeaseFileIO ioc(getLeaseFilePath("leasefile6_0.csv.completed"));
ioc.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
- "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,"
- "state\n"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,user_context\n"
"2001:db8:1::125,ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff,"
- "400,1000,8,100,0,7,0,1,1,,,1\n");
+ "400,1000,8,100,0,7,0,1,1,,,1,\n");
startBackend(V6);
@@ -1521,7 +1521,7 @@ TEST_F(MemfileLeaseMgrTest, leaseUpgrade4) {
std::string header_2_0 =
"address,hwaddr,client_id,valid_lifetime,expire,"
- "subnet_id,fqdn_fwd,fqdn_rev,hostname,state\n";
+ "subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context\n";
// Create 1.0 Schema current lease file with two entries for
// the same lease
@@ -1567,8 +1567,8 @@ TEST_F(MemfileLeaseMgrTest, leaseUpgrade4) {
// Verify cleaned, converted contents
std::string result_file_contents = header_2_0 +
- "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,0\n"
- "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,0\n";
+ "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,0,\n"
+ "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,0,\n";
EXPECT_EQ(result_file_contents, input_file.readFile());
}
@@ -1587,7 +1587,7 @@ TEST_F(MemfileLeaseMgrTest, leaseUpgrade6) {
std::string header_3_0 =
"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";
// The current lease file is schema 1.0 and has two entries for
// the same lease
@@ -1638,9 +1638,9 @@ TEST_F(MemfileLeaseMgrTest, leaseUpgrade6) {
// Verify cleaned, converted contents
std::string result_file_contents = header_3_0 +
"2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
- "8,100,0,7,0,1,1,,,0\n"
+ "8,100,0,7,0,1,1,,,0,\n"
"2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
- "8,100,0,7,0,1,1,,11:22:33:44:55,0\n";
+ "8,100,0,7,0,1,1,,11:22:33:44:55,0,\n";
EXPECT_EQ(result_file_contents, input_file.readFile());
}
diff --git a/src/lib/dhcpsrv/tests/test_utils.cc b/src/lib/dhcpsrv/tests/test_utils.cc
index 0d7463280d..3634e4ceb6 100644
--- a/src/lib/dhcpsrv/tests/test_utils.cc
+++ b/src/lib/dhcpsrv/tests/test_utils.cc
@@ -54,6 +54,14 @@ detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second) {
EXPECT_EQ(first->fqdn_fwd_, second->fqdn_fwd_);
EXPECT_EQ(first->fqdn_rev_, second->fqdn_rev_);
EXPECT_EQ(first->hostname_, second->hostname_);
+ if (first->getContext()) {
+ EXPECT_TRUE(second->getContext());
+ if (second->getContext()) {
+ EXPECT_EQ(first->getContext()->str(), second->getContext()->str());
+ }
+ } else {
+ EXPECT_FALSE(second->getContext());
+ }
}
void
@@ -77,6 +85,14 @@ detailCompareLease(const Lease6Ptr& first, const Lease6Ptr& second) {
EXPECT_EQ(first->fqdn_fwd_, second->fqdn_fwd_);
EXPECT_EQ(first->fqdn_rev_, second->fqdn_rev_);
EXPECT_EQ(first->hostname_, second->hostname_);
+ if (first->getContext()) {
+ EXPECT_TRUE(second->getContext());
+ if (second->getContext()) {
+ EXPECT_EQ(first->getContext()->str(), second->getContext()->str());
+ }
+ } else {
+ EXPECT_FALSE(second->getContext());
+ }
}
int findLastSocketFd() {