diff options
author | Francis Dupont <fdupont@isc.org> | 2018-07-07 19:23:16 +0200 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2018-07-07 19:23:16 +0200 |
commit | 12ebb96c01dfdc397faead1945569853d5b617eb (patch) | |
tree | 7645b9243ec0f49a0613508d14c6580e7dc59293 /src/lib/dhcpsrv | |
parent | [master] spurious spaces (diff) | |
parent | [5584] Addressed comments (diff) | |
download | kea-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.h | 5 | ||||
-rw-r--r-- | src/lib/dhcpsrv/cql_lease_mgr.cc | 114 | ||||
-rw-r--r-- | src/lib/dhcpsrv/csv_lease_file4.cc | 29 | ||||
-rw-r--r-- | src/lib/dhcpsrv/csv_lease_file4.h | 8 | ||||
-rw-r--r-- | src/lib/dhcpsrv/csv_lease_file6.cc | 27 | ||||
-rw-r--r-- | src/lib/dhcpsrv/csv_lease_file6.h | 8 | ||||
-rw-r--r-- | src/lib/dhcpsrv/lease.cc | 33 | ||||
-rw-r--r-- | src/lib/dhcpsrv/lease.h | 6 | ||||
-rw-r--r-- | src/lib/dhcpsrv/memfile_lease_mgr.h | 3 | ||||
-rw-r--r-- | src/lib/dhcpsrv/mysql_connection.h | 2 | ||||
-rw-r--r-- | src/lib/dhcpsrv/mysql_lease_mgr.cc | 164 | ||||
-rw-r--r-- | src/lib/dhcpsrv/pgsql_connection.h | 4 | ||||
-rw-r--r-- | src/lib/dhcpsrv/pgsql_lease_mgr.cc | 116 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/csv_lease_file4_unittest.cc | 43 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/csv_lease_file6_unittest.cc | 81 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc | 34 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc | 74 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/lease_unittest.cc | 152 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc | 200 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/test_utils.cc | 16 |
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() { |