namespace dhcp {
CSVLeaseFile4::CSVLeaseFile4(const std::string& filename)
- : CSVFile(filename) {
+ : VersionedCSVFile(filename) {
initColumns();
}
void
CSVLeaseFile4::open(const bool seek_to_end) {
// Call the base class to open the file
- CSVFile::open(seek_to_end);
+ VersionedCSVFile::open(seek_to_end);
// and clear any statistics we may have
clearStatistics();
row.writeAt(getColumnIndex("state"), lease.state_);
try {
- CSVFile::append(row);
+ VersionedCSVFile::append(row);
} catch (const std::exception&) {
// Catch any errors so we can bump the error counter than rethrow it
++write_errs_;
try {
// Get the row of CSV values.
CSVRow row;
- CSVFile::next(row);
+ VersionedCSVFile::next(row);
// The empty row signals EOF.
if (row == CSVFile::EMPTY_ROW()) {
lease.reset();
void
CSVLeaseFile4::initColumns() {
- addColumn("address");
- addColumn("hwaddr");
- addColumn("client_id");
- addColumn("valid_lifetime");
- addColumn("expire");
- addColumn("subnet_id");
- addColumn("fqdn_fwd");
- addColumn("fqdn_rev");
- addColumn("hostname");
- addColumn("state");
+ addColumn("address", "1.0");
+ addColumn("hwaddr", "1.0");
+ addColumn("client_id", "1.0");
+ addColumn("valid_lifetime", "1.0");
+ addColumn("expire", "1.0");
+ addColumn("subnet_id", "1.0");
+ addColumn("fqdn_fwd", "1.0");
+ addColumn("fqdn_rev", "1.0");
+ addColumn("hostname", "1.0");
+ addColumn("state", "2.0", "0");
+ // Any file with less than hostname is invalid
+ setMinimumValidColumns("hostname");
}
IOAddress
#include <dhcpsrv/lease.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/lease_file_stats.h>
-#include <util/csv_file.h>
+#include <util/versioned_csv_file.h>
#include <stdint.h>
#include <string>
#include <time.h>
/// validation (see http://kea.isc.org/ticket/2405). However, when #2405
/// is implemented, the @c next function may need to be updated to use the
/// validation capablity of @c Lease4.
-class CSVLeaseFile4 : public isc::util::CSVFile, public LeaseFileStats {
+class CSVLeaseFile4 : public isc::util::VersionedCSVFile, public LeaseFileStats {
public:
/// @brief Constructor.
namespace dhcp {
CSVLeaseFile6::CSVLeaseFile6(const std::string& filename)
- : CSVFile(filename) {
+ : VersionedCSVFile(filename) {
initColumns();
}
void
CSVLeaseFile6::open(const bool seek_to_end) {
// Call the base class to open the file
- CSVFile::open(seek_to_end);
+ VersionedCSVFile::open(seek_to_end);
// and clear any statistics we may have
clearStatistics();
}
row.writeAt(getColumnIndex("state"), lease.state_);
try {
- CSVFile::append(row);
+ VersionedCSVFile::append(row);
} catch (const std::exception&) {
// Catch any errors so we can bump the error counter than rethrow it
++write_errs_;
try {
// Get the row of CSV values.
CSVRow row;
- CSVFile::next(row);
+ VersionedCSVFile::next(row);
// The empty row signals EOF.
if (row == CSVFile::EMPTY_ROW()) {
lease.reset();
void
CSVLeaseFile6::initColumns() {
- addColumn("address");
- addColumn("duid");
- addColumn("valid_lifetime");
- addColumn("expire");
- addColumn("subnet_id");
- addColumn("pref_lifetime");
- addColumn("lease_type");
- addColumn("iaid");
- addColumn("prefix_len");
- addColumn("fqdn_fwd");
- addColumn("fqdn_rev");
- addColumn("hostname");
- addColumn("hwaddr");
- addColumn("state");
+ addColumn("address", "1.0");
+ addColumn("duid", "1.0");
+ addColumn("valid_lifetime", "1.0");
+ addColumn("expire", "1.0");
+ addColumn("subnet_id", "1.0");
+ addColumn("pref_lifetime", "1.0");
+ addColumn("lease_type", "1.0");
+ addColumn("iaid", "1.0");
+ addColumn("prefix_len", "1.0");
+ addColumn("fqdn_fwd", "1.0");
+ addColumn("fqdn_rev", "1.0");
+ addColumn("hostname", "1.0");
+ addColumn("hwaddr", "2.0");
+ addColumn("state", "3.0", "0");
+
+ // Any file with less than hostname is invalid
+ setMinimumValidColumns("hostname");
}
Lease::Type
#include <dhcpsrv/lease.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/lease_file_stats.h>
-#include <util/csv_file.h>
+#include <util/versioned_csv_file.h>
#include <stdint.h>
#include <string>
/// validation (see http://kea.isc.org/ticket/2405). However, when #2405
/// is implemented, the @c next function may need to be updated to use the
/// validation capablity of @c Lease6.
-class CSVLeaseFile6 : public isc::util::CSVFile, public LeaseFileStats {
+class CSVLeaseFile6 : public isc::util::VersionedCSVFile, public LeaseFileStats {
public:
/// @brief Constructor.
io_.readFile());
}
+// Verifies that a schema 1.0 file with records from
+// schema 1.0 and 2.0 loads correctly.
+TEST_F(CSVLeaseFile4Test, mixedSchemaload) {
+ // Create mixed schema file
+ io_.writeFile(
+ // schema 1.0 header
+ "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
+ "fqdn_fwd,fqdn_rev,hostname\n"
+ // schema 1.0 record
+ "192.0.2.1,06:07:08:09:1a:bc,,200,200,8,1,1,"
+ "one.example.com\n"
+ // 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
+ "192.0.2.3,06:07:08:09:3a:bc,,200,200,8,1,1,"
+ "three.example.com,2\n"
+ );
+
+ // Open the lease file.
+ boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
+ ASSERT_NO_THROW(lf->open());
+
+ Lease4Ptr lease;
+
+ // Reading first read should be successful.
+ {
+ SCOPED_TRACE("First lease valid");
+ EXPECT_TRUE(lf->next(lease));
+ ASSERT_TRUE(lease);
+
+ // Verify that the lease attributes are correct.
+ EXPECT_EQ("192.0.2.1", lease->addr_.toText());
+ HWAddr hwaddr1(*lease->hwaddr_);
+ EXPECT_EQ("06:07:08:09:1a:bc", hwaddr1.toText(false));
+ EXPECT_FALSE(lease->client_id_);
+ EXPECT_EQ(200, lease->valid_lft_);
+ EXPECT_EQ(0, lease->cltt_);
+ EXPECT_EQ(8, lease->subnet_id_);
+ EXPECT_TRUE(lease->fqdn_fwd_);
+ EXPECT_TRUE(lease->fqdn_rev_);
+ EXPECT_EQ("one.example.com", lease->hostname_);
+ // Verify that added state is DEFAULT
+ EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ }
+
+ {
+ SCOPED_TRACE("Second lease valid");
+ EXPECT_TRUE(lf->next(lease));
+ ASSERT_TRUE(lease);
+
+ // Verify that the lease attributes are correct.
+ EXPECT_EQ("192.0.2.2", lease->addr_.toText());
+ HWAddr hwaddr1(*lease->hwaddr_);
+ EXPECT_EQ("06:07:08:09:2a:bc", hwaddr1.toText(false));
+ EXPECT_FALSE(lease->client_id_);
+ EXPECT_EQ(200, lease->valid_lft_);
+ EXPECT_EQ(0, lease->cltt_);
+ EXPECT_EQ(8, lease->subnet_id_);
+ EXPECT_TRUE(lease->fqdn_fwd_);
+ EXPECT_TRUE(lease->fqdn_rev_);
+ EXPECT_EQ("two.example.com", lease->hostname_);
+ EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+ }
+
+ {
+ SCOPED_TRACE("Third lease valid");
+ EXPECT_TRUE(lf->next(lease));
+ ASSERT_TRUE(lease);
+
+ // Verify that the third lease is correct.
+ EXPECT_EQ("192.0.2.3", lease->addr_.toText());
+ HWAddr hwaddr1(*lease->hwaddr_);
+ EXPECT_EQ("06:07:08:09:3a:bc", hwaddr1.toText(false));
+ EXPECT_FALSE(lease->client_id_);
+ EXPECT_EQ(200, lease->valid_lft_);
+ EXPECT_EQ(0, lease->cltt_);
+ EXPECT_EQ(8, lease->subnet_id_);
+ EXPECT_TRUE(lease->fqdn_fwd_);
+ EXPECT_TRUE(lease->fqdn_rev_);
+ EXPECT_EQ("three.example.com", lease->hostname_);
+ EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
+ }
+}
+
+
+// Verifies that a lease file with fewer header columns than the
+// minimum allowed will not open.
+TEST_F(CSVLeaseFile4Test, tooFewHeaderColumns) {
+ // Create 1.0 file
+ io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
+ "fqdn_fwd,fqdn_rev\n");
+
+ // Open the lease file.
+ boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
+ ASSERT_THROW(lf->open(), CSVFileError);
+}
+
+// Verifies that a lease file with an unrecognized column header
+// will not open.
+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");
+
+ // Open the lease file.
+ boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
+ ASSERT_THROW(lf->open(), CSVFileError);
+}
+
+// Verifies that a lease file with more header columns than defined
+// columns will not open.
+TEST_F(CSVLeaseFile4Test, tooManyHeaderColumns) {
+ // Create 1.0 file
+ io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
+ "fqdn_fwd,fqdn_rev,state,FUTRE_COL\n");
+
+ // Open the lease file.
+ boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
+ ASSERT_THROW(lf->open(), CSVFileError);
+}
+
+
/// @todo Currently we don't check invalid lease attributes, such as invalid
/// lease type, invalid preferred lifetime vs valid lifetime etc. The Lease6
/// should be extended with the function that validates lease attributes. Once
io_.readFile());
}
+// Verifies that a 1.0 schema file with records from
+// schema 1.0, 2.0, and 3.0 loads correctly.
+TEST_F(CSVLeaseFile6Test, mixedSchemaLoad) {
+ // Create a mixed schema file
+ io_.writeFile(
+ // schema 1.0 header
+ "address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname\n"
+ // schema 1.0 record
+ "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:01,"
+ "200,200,8,100,0,7,0,1,1,one.example.com\n"
+
+ // schema 2.0 record - has hwaddr
+ "2001:db8:1::2,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:02,"
+ "200,200,8,100,0,7,0,1,1,two.example.com,01:02:03:04:05\n"
+
+ // 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");
+
+ // Open the lease file.
+ boost::scoped_ptr<CSVLeaseFile6> lf(new CSVLeaseFile6(filename_));
+ ASSERT_NO_THROW(lf->open());
+
+ Lease6Ptr lease;
+ {
+ SCOPED_TRACE("First lease valid");
+ EXPECT_TRUE(lf->next(lease));
+ ASSERT_TRUE(lease);
+
+ // Verify that the lease attributes are correct.
+ EXPECT_EQ("2001:db8:1::1", lease->addr_.toText());
+ ASSERT_TRUE(lease->duid_);
+ EXPECT_EQ("00:01:02:03:04:05:06:0a:0b:0c:0d:0e:01", 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("one.example.com", lease->hostname_);
+ // Verify that added HWaddr is empty
+ EXPECT_FALSE(lease->hwaddr_);
+ // Verify that added state is STATE_DEFAULT
+ EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+ }
+
+ {
+ SCOPED_TRACE("Second lease valid");
+ EXPECT_TRUE(lf->next(lease));
+ ASSERT_TRUE(lease);
+
+ // Verify that the lease attributes are correct.
+ EXPECT_EQ("2001:db8:1::2", lease->addr_.toText());
+ ASSERT_TRUE(lease->duid_);
+ EXPECT_EQ("00:01:02:03:04:05:06:0a:0b:0c:0d:0e:02", 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("two.example.com", lease->hostname_);
+ ASSERT_TRUE(lease->hwaddr_);
+ 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_);
+ }
+
+ {
+ SCOPED_TRACE("Third lease valid");
+ EXPECT_TRUE(lf->next(lease));
+ ASSERT_TRUE(lease);
+
+ // Verify that the lease attributes are correct.
+ EXPECT_EQ("2001:db8:1::3", 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_);
+ }
+
+}
+
+// Verifies that a lease file with fewer header columns than the
+// minimum allowed will not open.
+TEST_F(CSVLeaseFile6Test, tooFewHeaderColumns) {
+ io_.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev\n");
+
+ // Open should fail.
+ boost::scoped_ptr<CSVLeaseFile6> lf(new CSVLeaseFile6(filename_));
+ ASSERT_THROW(lf->open(), CSVFileError);
+}
+
+// Verifies that a lease file with an unrecognized column header
+// will not open.
+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");
+
+ // Open should fail.
+ boost::scoped_ptr<CSVLeaseFile6> lf(new CSVLeaseFile6(filename_));
+ ASSERT_THROW(lf->open(), CSVFileError);
+}
+
+// Verifies that a lease file with more header columns than defined
+// columns will not open.
+TEST_F(CSVLeaseFile6Test, tooManyHeaderColumns) {
+ io_.writeFile("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
+ "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,"
+ "hwaddr,state,FUTURE_COL\n");
+
+ // Open should fail.
+ boost::scoped_ptr<CSVLeaseFile6> lf(new CSVLeaseFile6(filename_));
+ ASSERT_THROW(lf->open(), CSVFileError);
+}
+
+
/// @todo Currently we don't check invalid lease attributes, such as invalid
/// lease type, invalid preferred lifetime vs valid lifetime etc. The Lease6
/// should be extended with the function that validates lease attributes. Once