# Get the query appropriate to lease version. Explicitly specify all columns
# so that they are returned in expected order.
if [ $dump_type -eq 4 ]; then
- dump_query="SELECT address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state FROM lease4"
+ dump_query="SELECT address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context FROM lease4"
elif [ $dump_type -eq 6 ]; then
- dump_query="SELECT address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state FROM lease6"
+ dump_query="SELECT address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state,user_context FROM lease6"
else
log_error "lease-dump: lease type ( -4 or -6 ) needs to be specified"
usage
#!/bin/sh
-# Copyright (C) 2014-2017 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
assert_eq 0 $? "schema_version table check failed, expected exit code: %d, actual: %d"
# Check lease4 table
- cql_execute "SELECT address, hwaddr, client_id, valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, state FROM lease4;"
+ cql_execute "SELECT address, hwaddr, client_id, valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, state, user_context FROM lease4;"
assert_eq 0 $? "lease4 table check failed, expected exit code: %d, actual: %d"
# Check lease6 table
- cql_execute "SELECT address, duid, valid_lifetime, expire, subnet_id, pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state FROM lease6;"
+ cql_execute "SELECT address, duid, valid_lifetime, expire, subnet_id, pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state, user_context FROM lease6;"
assert_eq 0 $? "lease6 table check failed, expected exit code: %d, actual: %d"
# Check lease6_types table
# Verify that kea-admin lease-version returns the correct version.
version=$($keaadmin lease-version cql -u $db_user -p $db_password -n $db_name)
- assert_str_eq "2.0" $version "Expected kea-admin to return %s, returned value was %s"
+ assert_str_eq "3.0" $version "Expected kea-admin to return %s, returned value was %s"
# Wipe the database.
cql_execute_script $db_scripts_dir/cql/dhcpdb_drop.cql
# 1436173267 corresponds to 2015-06-06 11:01:07
insert_cql="\
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(-1073741302,textAsBlob('20'),textAsBlob('30'),40,1430694930,50,true,true,\
- 'one.example.com', 0);\
+ 'one.example.com', 0, '');\
INSERT INTO lease4(address, hwaddr, client_id, valid_lifetime, expire, subnet_id,\
- fqdn_fwd, fqdn_rev, hostname, state)\
- VALUES(-1073741301,NULL,textAsBlob('123'),40,1433464245,50,true,true,'', 1);\
+ fqdn_fwd, fqdn_rev, hostname, state, user_context)\
+ VALUES(-1073741301,NULL,textAsBlob('123'),40,1433464245,50,true,true,'', 1, '');\
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(-1073741300,textAsBlob('22'),NULL,40,1436173267,50,true,true,\
- 'three.example.com', 2);"
+ 'three.example.com', 2, '');"
cql_execute "$insert_cql"
assert_eq 0 $? "insert into lease4 failed, expected exit code %d, actual %d"
insert_cql="\
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)\
+ hwaddr, hwtype, hwaddr_source, state, user_context)\
VALUES('2001:db8::10',textAsBlob('20'),30,1430694930,40,50,1,60,70,true,true,\
- 'one.example.com',textAsBlob('80'),90,16,0);\
+ 'one.example.com',textAsBlob('80'),90,16,0,'');\
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)\
+ hwaddr, hwtype, hwaddr_source, state, user_context)\
VALUES('2001:db8::11',NULL,30,1433464245,40,50,1,60,70,true,true,\
- '',textAsBlob('80'),90,1,1);\
+ '',textAsBlob('80'),90,1,1,'');\
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)\
+ hwaddr, hwtype, hwaddr_source, state, user_context)\
VALUES('2001:db8::12',textAsBlob('21'),30,1436173267,40,50,1,60,70,true,true,\
- 'three.example.com',textAsBlob('80'),90,4,2);"
+ 'three.example.com',textAsBlob('80'),90,4,2,'');"
cql_execute "$insert_cql"
assert_eq 0 $? "insert into lease6 failed, expected exit code %d, actual %d"
-address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state
--1073741302,0x3230,0x3330,40,1430694930,50,True,True,one.example.com,0
--1073741301,null,0x313233,40,1433464245,50,True,True,,1
--1073741300,0x3232,null,40,1436173267,50,True,True,three.example.com,2
+address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context
+-1073741302,0x3230,0x3330,40,1430694930,50,True,True,one.example.com,0,
+-1073741301,null,0x313233,40,1433464245,50,True,True,,1,
+-1073741300,0x3232,null,40,1436173267,50,True,True,three.example.com,2,
-address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state
-2001:db8::12,0x3231,30,1436173267,40,50,1,60,70,True,True,three.example.com,0x3830,90,4,2
-2001:db8::11,null,30,1433464245,40,50,1,60,70,True,True,,0x3830,90,1,1
-2001:db8::10,0x3230,30,1430694930,40,50,1,60,70,True,True,one.example.com,0x3830,90,16,0
+address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state,user_context
+2001:db8::12,0x3231,30,1436173267,40,50,1,60,70,True,True,three.example.com,0x3830,90,4,2,
+2001:db8::11,null,30,1433464245,40,50,1,60,70,True,True,,0x3830,90,1,1,
+2001:db8::10,0x3230,30,1430694930,40,50,1,60,70,True,True,one.example.com,0x3830,90,16,0,
-address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state
-0.0.0.10,3230,3330,40,2015-01-01 01:15:30,50,1,1,one.example.com,default
-0.0.0.11,,313233,40,2015-02-02 02:30:45,50,1,1,,declined
-0.0.0.12,3232,,40,2015-03-03 11:01:07,50,1,1,three.example.com,expired-reclaimed
+address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context
+0.0.0.10,3230,3330,40,2015-01-01 01:15:30,50,1,1,one.example.com,default,
+0.0.0.11,,313233,40,2015-02-02 02:30:45,50,1,1,,declined,
+0.0.0.12,3232,,40,2015-03-03 11:01:07,50,1,1,three.example.com,expired-reclaimed,
-address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state
-10,3230,30,2015-04-04 01:15:30,40,50,IA_TA,60,70,1,1,one.example.com,3830,90,HWADDR_SOURCE_REMOTE_ID,default
-11,,30,2015-05-05 02:30:45,40,50,IA_TA,60,70,1,1,,3830,90,HWADDR_SOURCE_RAW,declined
-12,3231,30,2015-06-06 11:01:07,40,50,IA_TA,60,70,1,1,three.example.com,3830,90,HWADDR_SOURCE_DUID,expired-reclaimed
+address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state,user_context
+10,3230,30,2015-04-04 01:15:30,40,50,IA_TA,60,70,1,1,one.example.com,3830,90,HWADDR_SOURCE_REMOTE_ID,default,
+11,,30,2015-05-05 02:30:45,40,50,IA_TA,60,70,1,1,,3830,90,HWADDR_SOURCE_RAW,declined,
+12,3231,30,2015-06-06 11:01:07,40,50,IA_TA,60,70,1,1,three.example.com,3830,90,HWADDR_SOURCE_DUID,expired-reclaimed,
-address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state
-0.0.0.10,20,30,40,<timestamp1>,50,1,1,one.example.com,default
-0.0.0.11,,013233,40,<timestamp2>,50,1,1,,declined
-0.0.0.12,22,,40,<timestamp3>,50,1,1,three.example.com,expired-reclaimed
+address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context
+0.0.0.10,20,30,40,<timestamp1>,50,1,1,one.example.com,default,
+0.0.0.11,,013233,40,<timestamp2>,50,1,1,,declined,
+0.0.0.12,22,,40,<timestamp3>,50,1,1,three.example.com,expired-reclaimed,
-address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,state,hwaddr,hwtype,hwaddr_source
-10,20,30,<timestamp1>,40,50,IA_TA,60,70,1,1,one.example.com,default,80,90,HWADDR_SOURCE_REMOTE_ID
-11,,30,<timestamp2>,40,50,IA_TA,60,70,1,1,,declined,80,90,HWADDR_SOURCE_RAW
-12,21,30,<timestamp3>,40,50,IA_TA,60,70,1,1,three.example.com,expired-reclaimed,80,90,HWADDR_SOURCE_DUID
+address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,state,user_context,hwaddr,hwtype,hwaddr_source
+10,20,30,<timestamp1>,40,50,IA_TA,60,70,1,1,one.example.com,default,,80,90,HWADDR_SOURCE_REMOTE_ID
+11,,30,<timestamp2>,40,50,IA_TA,60,70,1,1,,declined,,80,90,HWADDR_SOURCE_RAW
+12,21,30,<timestamp3>,40,50,IA_TA,60,70,1,1,three.example.com,expired-reclaimed,,80,90,HWADDR_SOURCE_DUID
assert_str_eq "1.0" ${version} "Expected kea-admin to return %s, returned value was %s"
- # Ok, we have a 1.0 database. Let's upgrade it to 6.0
+ # Ok, we have a 1.0 database. Let's upgrade it to 6.1
${keaadmin} lease-upgrade mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir
ERRCODE=$?
# lease4/6_stats changes are tested separately
- # Verify upgraded schema reports version 6.0
+ #table: user_context to lease4 and lease6 (upgrade 6.0 -> 6.1)
+ # verify that lease4 table includes user_context
+ qry="select user_context from lease4";
+ count=`mysql_execute "${qry}"`
+ ERRCODE=$?
+ assert_eq 0 $ERRCODE "select user_context from lease4 failed. (expected status code %d, returned %d)"
+
+ # verify that lease6 table includes user_context
+ qry="select user_context from lease6";
+ count=`mysql_execute "${qry}"`
+ ERRCODE=$?
+ assert_eq 0 $ERRCODE "select user_context from lease6 failed. (expected status code %d, returned %d)"
+
+ #table: logs (upgrade 6.0 -> 6.1)
+ mysql -u$db_user -p$db_password $db_name >/dev/null 2>&1 <<EOF
+ SELECT timestamp, address, log FROM logs;
+EOF
+ ERRCODE=$?
+ assert_eq 0 $ERRCODE "logs table is missing or broken. (expected status code %d, returned %d)"
+
+ # Verify upgraded schema reports version 6.1
version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir)
- assert_str_eq "6.0" ${version} "Expected kea-admin to return %s, returned value was %s"
+ assert_str_eq "6.1" ${version} "Expected kea-admin to return %s, returned value was %s"
+
# Let's wipe the whole database
mysql_wipe
# Insert the reference record
insert_sql="\
-insert into lease4 values(10,20,30,40,'2015-01-01 01:15:30',50,1,1,'one.example.com', 0);\
-insert into lease4 values(11,NULL,123,40,'2015-02-02 02:30:45',50,1,1,'', 1);\
-insert into lease4 values(12,22,NULL,40,'2015-03-03 11:01:07',50,1,1,'three.example.com', 2);"
+insert into lease4 values(10,20,30,40,'2015-01-01 01:15:30',50,1,1,'one.example.com', 0,NULL);\
+insert into lease4 values(11,NULL,123,40,'2015-02-02 02:30:45',50,1,1,'', 1,NULL);\
+insert into lease4 values(12,22,NULL,40,'2015-03-03 11:01:07',50,1,1,'three.example.com', 2,NULL);"
mysql_execute "$insert_sql"
ERRCODE=$?
# Insert the reference record
insert_sql="\
-insert into lease6 values(10,20,30,'2015-04-04 01:15:30',40,50,1,60,70,1,1,'one.example.com',80,90,16,0);\
-insert into lease6 values(11,NULL,30,'2015-05-05 02:30:45',40,50,1,60,70,1,1,'',80,90,1,1);\
-insert into lease6 values(12,21,30,'2015-06-06 11:01:07',40,50,1,60,70,1,1,'three.example.com',80,90,4,2);"
+insert into lease6 values(10,20,30,'2015-04-04 01:15:30',40,50,1,60,70,1,1,'one.example.com',80,90,16,0,NULL);\
+insert into lease6 values(11,NULL,30,'2015-05-05 02:30:45',40,50,1,60,70,1,1,'',80,90,1,1,NULL);\
+insert into lease6 values(12,21,30,'2015-06-06 11:01:07',40,50,1,60,70,1,1,'three.example.com',80,90,4,2,NULL);"
mysql_execute "$insert_sql"
ERRCODE=$?
assert_eq 0 $? "schema_version table check failed, expected exit code: %d, actual: %d"
# Check lease4 table
- RESULT=`pgsql_execute "SELECT address, hwaddr, client_id, valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, state FROM lease4;"`
+ RESULT=`pgsql_execute "SELECT address, hwaddr, client_id, valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, state, user_context FROM lease4;"`
assert_eq 0 $? "lease4 table check failed, expected exit code: %d, actual: %d"
# Check lease6 table
- RESULT=`pgsql_execute "SELECT address, duid, valid_lifetime, expire, subnet_id, pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state FROM lease6;"`
+ RESULT=`pgsql_execute "SELECT address, duid, valid_lifetime, expire, subnet_id, pref_lifetime, lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state, user_context FROM lease6;"`
assert_eq 0 $? "lease6 table check failed, expected exit code: %d, actual: %d"
# Check lease6_types table
# Verify that kea-admin lease-version returns the correct version
version=$(${keaadmin} lease-version pgsql -u $db_user -p $db_password -n $db_name)
- assert_str_eq "4.0" ${version} "Expected kea-admin to return %s, returned value was %s"
+ assert_str_eq "4.1" ${version} "Expected kea-admin to return %s, returned value was %s"
# Let's wipe the whole database
pgsql_wipe
assert_eq 1 "$output" "lease_hwaddr_source does not contain entry for HWADDR_SOURCE_UNKNOWN. (record count %d, expected %d)"
}
-pgsql_upgrade_3_0_to_4_0() {
- # Verify upgraded schema reports version 4.0.
+pgsql_upgrade_3_0_to_4_1() {
+ # Verify upgraded schema reports version 4.1.
version=$(${keaadmin} lease-version pgsql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir)
- assert_str_eq "4.0" ${version} "Expected kea-admin to return %s, returned value was %s"
+ assert_str_eq "4.1" ${version} "Expected kea-admin to return %s, returned value was %s"
+
+ # Added user_context to lease4
+ output=`pgsql_execute "select user_context from lease4;"`
+ ERRCODE=$?
+ assert_eq 0 $ERRCODE "lease4 is missing user_context column. (expected status code %d, returned %d)"
+
+ # Added user_context to lease6
+ output=`pgsql_execute "select user_context from lease6;"`
+ ERRCODE=$?
+ assert_eq 0 $ERRCODE "lease6 is missing user_context column. (expected status code %d, returned %d)"
+
+ # Added logs table
+ output=`pgsql_execute "select timestamp, address, log from logs;"`
+ ERRCODE=$?
+ assert_eq 0 $ERRCODE "logs table is missing or broken. (expected status code %d, returned %d)"
}
pgsql_upgrade_test() {
# Check 2.0 to 3.0 upgrade
pgsql_upgrade_2_0_to_3_0
- # Check 3.0 to 4.0 upgrade
- pgsql_upgrade_3_0_to_4_0
+ # Check 3.0 to 4.1 upgrade
+ pgsql_upgrade_3_0_to_4_1
# Let's wipe the whole database
pgsql_wipe
# Insert the reference records
insert_sql="\
-insert into lease4 values(10,E'\\x20',E'\\x30',40,'$timestamp1',50,'t','t','one.example.com', 0);\
-insert into lease4 values(11,'',E'\\x0123',40,'$timestamp2',50,'t','t','', 1);\
-insert into lease4 values(12,E'\\x22','',40,'$timestamp3',50,'t','t','three.example.com', 2);"
+insert into lease4 values(10,E'\\x20',E'\\x30',40,'$timestamp1',50,'t','t','one.example.com', 0, '');\
+insert into lease4 values(11,'',E'\\x0123',40,'$timestamp2',50,'t','t','', 1, '');\
+insert into lease4 values(12,E'\\x22','',40,'$timestamp3',50,'t','t','three.example.com', 2, '');"
pgsql_execute "$insert_sql"
ERRCODE=$?
# Insert the reference records
insert_sql="\
-insert into lease6 values(10,E'\\x20',30,'$timestamp1',40,50,1,60,70,'t','t','one.example.com', 0,decode('80','hex'),90,16);\
-insert into lease6 values(11,'',30,'$timestamp2',40,50,1,60,70,'t','t','', 1,decode('80','hex'),90,1);\
-insert into lease6 values(12,E'\\x21',30,'$timestamp3',40,50,1,60,70,'t','t','three.example.com', 2,decode('80','hex'),90,4);"
+insert into lease6 values(10,E'\\x20',30,'$timestamp1',40,50,1,60,70,'t','t','one.example.com', 0,decode('80','hex'),90,16,'');\
+insert into lease6 values(11,'',30,'$timestamp2',40,50,1,60,70,'t','t','', 1,decode('80','hex'),90,1,'');\
+insert into lease6 values(12,E'\\x21',30,'$timestamp3',40,50,1,60,70,'t','t','three.example.com', 2,decode('80','hex'),90,4,'');"
pgsql_execute "$insert_sql"
ERRCODE=$?
ConstElementPtr ctx;
if (!user_context_.empty()) {
ctx = Element::fromJSON(user_context_);
- isc_throw(BadValue, "user context '" << user_context_
- << "' is not a JSON map");
+ 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(),
ConstElementPtr ctx;
if (!user_context_.empty()) {
ctx = Element::fromJSON(user_context_);
- isc_throw(BadValue, "user context '" << user_context_
- << "' is not a JSON map");
+ 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
<< "State: " << statesToText(state_) << "\n";
if (getContext()) {
- stream << "User context: " << getContext() << "\n";
+ stream << "User context: " << getContext()->str() << "\n";
}
return (stream.str());
<< "State: " << statesToText(state_) << "\n";
if (getContext()) {
- stream << "User context: " << getContext() << "\n";
+ stream << "User context: " << getContext()->str() << "\n";
}
return (stream.str());
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::util;
"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.
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
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
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));
"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());
}
// 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.
EXPECT_EQ("one.example.com", lease->hostname_);
// Verify that added state is DEFAULT
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
{
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("two.example.com", lease->hostname_);
EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
{
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());
}
}
EXPECT_TRUE(lease->fqdn_rev_);
EXPECT_EQ("three.example.com", lease->hostname_);
EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
}
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::util;
"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"
"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.
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.
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.
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
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));
"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"
"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());
}
// 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_);
EXPECT_FALSE(lease->hwaddr_);
// Verify that added state is STATE_DEFAULT
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ EXPECT_FALSE(lease->getContext());
}
{
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());
}
{
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());
}
}
"lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
"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");
+ "200,200,8,100,0,7,0,1,1,three.example.com,0a:0b:0c:0d:0e,1,"
+ "{ \"foobar\": true },BOGUS\n");
// Open should succeed in the event someone is downgrading.
CSVLeaseFile6 lf(filename_);
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());
}
}
using namespace std;
using namespace isc::asiolink;
+using namespace isc::data;
namespace isc {
namespace dhcp {
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
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.
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
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.
// 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();
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.
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.
// 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();
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.
// 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
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();
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();
using namespace isc;
using namespace isc::asiolink;
+using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
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";
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);
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);
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";
std::string b_2 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,"
"100,200,8,0,2,16,64,0,0,,,1,\n";
-
// Create a lease file with three valid leases: 2001:db8:1::1,
// 3000:1:: and 2001:db8:2::10.
test_str = v6_hdr_ + a_1 + a_2 + b_1 + c_1 + b_2 + a_3;
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);
EXPECT_TRUE(lease.fqdn_fwd_);
EXPECT_TRUE(lease.fqdn_rev_);
EXPECT_EQ(Lease::STATE_DEFAULT, lease.state_);
+ EXPECT_FALSE(lease.getContext());
}
}
// 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);
// 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_);
// 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.
// 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_);
// 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
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);
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
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"
<< "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"
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\","
"\"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\","
"\"ip-address\": \"192.0.2.3\","
"\"state\": 0,"
"\"subnet-id\": 789,"
+ "\"user-context\": { \"foo\": \"bar\" },"
"\"valid-lft\": 3600 "
"}";
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
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.
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.
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
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_;
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
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.
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"
<< "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"
lease.cltt_ = 12345678;
lease.state_ = Lease::STATE_DECLINED;
lease.hostname_ = "urania.example.org";
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
std::string expected = "{"
"\"cltt\": 12345678,"
"\"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,"
lease.cltt_ = 12345678;
lease.state_ = Lease::STATE_DEFAULT;
lease.hostname_ = "urania.example.org";
+ lease.setContext(Element::fromJSON("{ \"foobar\": 1234 }"));
ElementPtr l = lease.toElement();
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.
"\"state\": 1,"
"\"subnet-id\": 5678,"
"\"type\": \"IA_NA\","
+ "\"user-context\": { \"foobar\": 1234 },"
"\"valid-lft\": 800"
"}";
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_);
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,"
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_);
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.
// 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,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,800,8,1,1,,1,{ \"bar\": true }\n";
LeaseFileIO previous_file(getLeaseFilePath("leasefile4_0.csv.2"));
previous_file.writeFile(previous_file_contents);
// 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.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
"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"
"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";
LeaseFileIO previous_file(getLeaseFilePath("leasefile6_0.csv.2"));
// 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";
"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"
"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);
// 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);
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
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() {
ALTER TABLE lease6 ADD user_context text;
-- -----------------------------------------------------
--- Table `logs`
+-- Table \`logs\`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS logs (
timeuuid timeuuid, -- creation timeuuid, use dateOf() to get timestamp
ALTER TABLE lease4 ADD COLUMN user_context TEXT NULL;
ALTER TABLE lease6 ADD COLUMN user_context TEXT NULL;
+DROP PROCEDURE IF EXISTS lease4DumpHeader;
+DELIMITER $$
+CREATE PROCEDURE lease4DumpHeader()
+BEGIN
+SELECT 'address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context';
+END $$
+DELIMITER ;
+
+# FUNCTION that returns a result set containing the data for lease4 dumps
+DROP PROCEDURE IF EXISTS lease4DumpData;
+DELIMITER $$
+CREATE PROCEDURE lease4DumpData()
+BEGIN
+SELECT
+ INET_NTOA(l.address),
+ IFNULL(HEX(l.hwaddr), ''),
+ IFNULL(HEX(l.client_id), ''),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.fqdn_fwd,
+ l.fqdn_rev,
+ l.hostname,
+ s.name,
+ IFNULL(l.user_context, '')
+FROM
+ lease4 l
+ LEFT OUTER JOIN lease_state s on (l.state = s.state)
+ORDER BY l.address;
+END $$
+DELIMITER ;
+
+DROP PROCEDURE IF EXISTS lease6DumpHeader;
+DELIMITER $$
+CREATE PROCEDURE lease6DumpHeader()
+BEGIN
+SELECT 'address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state,user_context';
+END $$
+DELIMITER ;
+
+# FUNCTION that returns a result set containing the data for lease6 dumps
+DROP PROCEDURE IF EXISTS lease6DumpData;
+DELIMITER $$
+CREATE PROCEDURE lease6DumpData()
+BEGIN
+SELECT
+ l.address,
+ IFNULL(HEX(l.duid), ''),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.pref_lifetime,
+ IFNULL(t.name, ''),
+ l.iaid,
+ l.prefix_len,
+ l.fqdn_fwd,
+ l.fqdn_rev,
+ l.hostname,
+ IFNULL(HEX(l.hwaddr), ''),
+ IFNULL(l.hwtype, ''),
+ IFNULL(h.name, ''),
+ IFNULL(s.name, ''),
+ IFNULL(l.user_context, '')
+FROM lease6 l
+ left outer join lease6_types t on (l.lease_type = t.lease_type)
+ left outer join lease_state s on (l.state = s.state)
+ left outer join lease_hwaddr_source h on (l.hwaddr_source = h.hwaddr_source)
+ORDER BY l.address;
+END $$
+DELIMITER ;
+
# Create logs table
CREATE TABLE logs (
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, # creation timestamp
ALTER TABLE lease4 ADD COLUMN user_context TEXT NULL;
ALTER TABLE lease6 ADD COLUMN user_context TEXT NULL;
+DROP PROCEDURE IF EXISTS lease4DumpHeader;
+DELIMITER $$
+CREATE PROCEDURE lease4DumpHeader()
+BEGIN
+SELECT 'address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context';
+END $$
+DELIMITER ;
+
+# FUNCTION that returns a result set containing the data for lease4 dumps
+DROP PROCEDURE IF EXISTS lease4DumpData;
+DELIMITER $$
+CREATE PROCEDURE lease4DumpData()
+BEGIN
+SELECT
+ INET_NTOA(l.address),
+ IFNULL(HEX(l.hwaddr), ''),
+ IFNULL(HEX(l.client_id), ''),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.fqdn_fwd,
+ l.fqdn_rev,
+ l.hostname,
+ s.name,
+ IFNULL(l.user_context, '')
+FROM
+ lease4 l
+ LEFT OUTER JOIN lease_state s on (l.state = s.state)
+ORDER BY l.address;
+END $$
+DELIMITER ;
+
+DROP PROCEDURE IF EXISTS lease6DumpHeader;
+DELIMITER $$
+CREATE PROCEDURE lease6DumpHeader()
+BEGIN
+SELECT 'address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state,user_context';
+END $$
+DELIMITER ;
+
+# FUNCTION that returns a result set containing the data for lease6 dumps
+DROP PROCEDURE IF EXISTS lease6DumpData;
+DELIMITER $$
+CREATE PROCEDURE lease6DumpData()
+BEGIN
+SELECT
+ l.address,
+ IFNULL(HEX(l.duid), ''),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.pref_lifetime,
+ IFNULL(t.name, ''),
+ l.iaid,
+ l.prefix_len,
+ l.fqdn_fwd,
+ l.fqdn_rev,
+ l.hostname,
+ IFNULL(HEX(l.hwaddr), ''),
+ IFNULL(l.hwtype, ''),
+ IFNULL(h.name, ''),
+ IFNULL(s.name, ''),
+ IFNULL(l.user_context, '')
+FROM lease6 l
+ left outer join lease6_types t on (l.lease_type = t.lease_type)
+ left outer join lease_state s on (l.state = s.state)
+ left outer join lease_hwaddr_source h on (l.hwaddr_source = h.hwaddr_source)
+ORDER BY l.address;
+END $$
+DELIMITER ;
+
# Create logs table
CREATE TABLE logs (
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, # creation timestamp
ALTER TABLE lease4 ADD COLUMN user_context TEXT;
ALTER TABLE lease6 ADD COLUMN user_context TEXT;
+--
+DROP FUNCTION IF EXISTS lease4DumpHeader();
+CREATE FUNCTION lease4DumpHeader() RETURNS text AS $$
+ select cast('address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context' as text) as result;
+$$ LANGUAGE SQL;
+--
+
+--
+DROP FUNCTION IF EXISTS lease4DumpData();
+CREATE FUNCTION lease4DumpData() RETURNS
+ table (address inet,
+ hwaddr text,
+ client_id text,
+ valid_lifetime bigint,
+ expire timestamp with time zone,
+ subnet_id bigint,
+ fqdn_fwd int,
+ fqdn_rev int,
+ hostname text,
+ state text,
+ user_context text
+ ) as $$
+ SELECT ('0.0.0.0'::inet + l.address),
+ encode(l.hwaddr,'hex'),
+ encode(l.client_id,'hex'),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.fqdn_fwd::int,
+ l.fqdn_rev::int,
+ l.hostname,
+ s.name,
+ l.user_context
+ FROM lease4 l
+ left outer join lease_state s on (l.state = s.state)
+ ORDER BY l.address;
+$$ LANGUAGE SQL;
+--
+
+--
+DROP FUNCTION IF EXISTS lease6DumpHeader();
+CREATE FUNCTION lease6DumpHeader() RETURNS text AS $$
+ select cast('address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,state,user_context,hwaddr,hwtype,hwaddr_source' as text) as result;
+$$ LANGUAGE SQL;
+--
+
+--
+DROP FUNCTION IF EXISTS lease6DumpData();
+CREATE FUNCTION lease6DumpData() RETURNS
+ TABLE (
+ address text,
+ duid text,
+ valid_lifetime bigint,
+ expire timestamp with time zone,
+ subnet_id bigint,
+ pref_lifetime bigint,
+ name text,
+ iaid integer,
+ prefix_len smallint,
+ fqdn_fwd int,
+ fqdn_rev int,
+ hostname text,
+ state text,
+ user_context text,
+ hwaddr text,
+ hwtype smallint,
+ hwaddr_source text
+ ) AS $$
+ SELECT (l.address,
+ encode(l.duid,'hex'),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.pref_lifetime,
+ t.name,
+ l.iaid,
+ l.prefix_len,
+ l.fqdn_fwd::int,
+ l.fqdn_rev::int,
+ l.hostname,
+ s.name,
+ l.user_context,
+ encode(l.hwaddr,'hex'),
+ l.hwtype,
+ h.name
+ )
+ FROM lease6 l
+ left outer join lease6_types t on (l.lease_type = t.lease_type)
+ left outer join lease_state s on (l.state = s.state)
+ left outer join lease_hwaddr_source h on (l.hwaddr_source = h.hwaddr_source)
+ ORDER BY l.address;
+$$ LANGUAGE SQL;
+--
+
-- Create logs table
CREATE TABLE logs (
timestamp TIMESTAMP WITH TIME ZONE
ALTER TABLE lease4 ADD COLUMN user_context TEXT;
ALTER TABLE lease6 ADD COLUMN user_context TEXT;
+--
+-- FUNCTION that returns a result set containing the column names for lease4 dumps
+DROP FUNCTION IF EXISTS lease4DumpHeader();
+CREATE FUNCTION lease4DumpHeader() RETURNS text AS \$\$
+ select cast('address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context' as text) as result;
+\$\$ LANGUAGE SQL;
+--
+
+--
+-- FUNCTION that returns a result set containing the data for lease4 dumps
+DROP FUNCTION IF EXISTS lease4DumpData();
+CREATE FUNCTION lease4DumpData() RETURNS
+ table (address inet,
+ hwaddr text,
+ client_id text,
+ valid_lifetime bigint,
+ expire timestamp with time zone,
+ subnet_id bigint,
+ fqdn_fwd int,
+ fqdn_rev int,
+ hostname text,
+ state text,
+ user_context text
+ ) as \$\$
+ SELECT ('0.0.0.0'::inet + l.address),
+ encode(l.hwaddr,'hex'),
+ encode(l.client_id,'hex'),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.fqdn_fwd::int,
+ l.fqdn_rev::int,
+ l.hostname,
+ s.name,
+ l.user_context
+ FROM lease4 l
+ left outer join lease_state s on (l.state = s.state)
+ ORDER BY l.address;
+\$\$ LANGUAGE SQL;
+--
+
+--
+-- FUNCTION that returns a result set containing the column names for lease6 dumps
+DROP FUNCTION IF EXISTS lease6DumpHeader();
+CREATE FUNCTION lease6DumpHeader() RETURNS text AS \$\$
+ select cast('address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,state,user_context,hwaddr,hwtype,hwaddr_source' as text) as result;
+\$\$ LANGUAGE SQL;
+--
+
+--
+-- FUNCTION that returns a result set containing the data for lease6 dumps
+DROP FUNCTION IF EXISTS lease6DumpData();
+CREATE FUNCTION lease6DumpData() RETURNS
+ TABLE (
+ address text,
+ duid text,
+ valid_lifetime bigint,
+ expire timestamp with time zone,
+ subnet_id bigint,
+ pref_lifetime bigint,
+ name text,
+ iaid integer,
+ prefix_len smallint,
+ fqdn_fwd int,
+ fqdn_rev int,
+ hostname text,
+ state text,
+ user_context text,
+ hwaddr text,
+ hwtype smallint,
+ hwaddr_source text
+ ) AS \$\$
+ SELECT (l.address,
+ encode(l.duid,'hex'),
+ l.valid_lifetime,
+ l.expire,
+ l.subnet_id,
+ l.pref_lifetime,
+ t.name,
+ l.iaid,
+ l.prefix_len,
+ l.fqdn_fwd::int,
+ l.fqdn_rev::int,
+ l.hostname,
+ s.name,
+ l.user_context,
+ encode(l.hwaddr,'hex'),
+ l.hwtype,
+ h.name
+ )
+ FROM lease6 l
+ left outer join lease6_types t on (l.lease_type = t.lease_type)
+ left outer join lease_state s on (l.state = s.state)
+ left outer join lease_hwaddr_source h on (l.hwaddr_source = h.hwaddr_source)
+ ORDER BY l.address;
+\$\$ LANGUAGE SQL;
+--
+
-- Create logs table
CREATE TABLE logs (
timestamp TIMESTAMP WITH TIME ZONE