"server-id": {
"type": "EN",
"enterprise-id": 2495,
- "identifier": "87ABEF7A5BB545",
+ "identifier": "87ABEF7A5BB545"
},
...
}
"server-id": {
"type": "LL",
"htype": 8,
- "identifier": "A65DC7410F05",
+ "identifier": "A65DC7410F05"
},
...
}
location: <userinput>[kea-install-dir]/var/kea/kea-dhcp6-serverid
</userinput>.
</para>
+
+ <para>In some uncommon deployments where no stable storage is
+ available, it is desired to configure the server to not try to
+ store the server identifier on the hard drive. It is controlled
+ by the value of <command>persist</command> boolean parameter:
+<screen>
+"Dhcp6": {
+ "server-id": {
+ "type": "EN",
+ "enterprise-id": 2495,
+ "identifier": "87ABEF7A5BB545",
+ "persist": false
+ },
+ ...
+}
+</screen>
+ </para>
+ <para>The default value of the "persist" parameter is
+ <command>true</command> which configures the server to store the
+ server identifier on a disk.</para>
+
+ <para>In the example above, the server is configured to not store
+ the generated server identifier on a disk. But, if the server
+ identifier is not modified in the configuration the same value
+ will be used after server restart, because entire server
+ identifier is explicitly specified in a configuration.</para>
</section>
<section id="stateless-dhcp6">
"item_type": "integer",
"item_optional": true,
"item_default": 0
+ },
+ {
+ "item_name": "persist",
+ "item_type": "boolean",
+ "item_optional": true,
+ "item_default": true
}
]
},
const std::string Dhcpv6Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
-/// @brief file name of a server-id file
-///
-/// Server must store its duid in persistent storage that must not change
-/// between restarts. This is name of the file that is created in dataDir
-/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
-/// double digit hex values separated by colons format, e.g.
-/// 01:ff:02:03:06:80:90:ab:cd:ef. Server will create it during first
-/// run and then use it afterwards.
-static const char* SERVER_DUID_FILE = "kea-dhcp6-serverid";
-
Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
: port_(port), serverid_(), shutdown_(true), alloc_engine_()
{
return;
}
- string duid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_DUID_FILE);
- DUIDFactory duid_factory(duid_file);
+ // Create a DUID instance but do not store it into a file.
+ DUIDFactory duid_factory;
DuidPtr duid = duid_factory.get();
serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid()));
#include <dhcpsrv/lease.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
#include <hooks/hooks_manager.h>
#include <stats/stats_mgr.h>
#include <testutils/unix_control_client.h>
using Dhcpv6Srv::receivePacket;
};
-class CtrlDhcpv6SrvTest : public ::testing::Test {
+class CtrlDhcpv6SrvTest : public BaseServerTest {
public:
- CtrlDhcpv6SrvTest() {
+ CtrlDhcpv6SrvTest()
+ : BaseServerTest() {
reset();
}
/// @brief Base class for test fixure classes used to validate the DHCPv6
/// message processing by the server.
-class Dhcpv6MessageTest : public isc::dhcp::test::Dhcpv6SrvTest {
+class Dhcpv6MessageTest : public Dhcpv6SrvTest {
public:
/// @brief Constructor.
///
{ \"interfaces-config\": {
\"interfaces\": [ ]
},
+ \"server-id\": {
+ \"type\": \"LLT\",
+ \"persist\": false
+ },
\"preferred-lifetime\": 3000,
\"valid-lifetime\": 4000,
\"renew-timer\": 1000,
# Create a configuration with the LFC enabled, by replacing the section
# with the lfc-interval and persist parameters.
LFC_CONFIG=$(printf "${CONFIG}" | sed -e 's/\"lfc-interval\": 0/\"lfc-interval\": 1/g' \
- | sed -e 's/\"persist\": false/\"persist\": true/g')
+ | sed -e 's/\"persist\": false,/\"persist\": true,/g')
# Create new configuration file.
create_config "${LFC_CONFIG}"
# Instruct Kea to log to the specific file.
#include <util/pointer_util.h>
#include <cc/command_interpreter.h>
#include <stats/stats_mgr.h>
+#include <cstdio>
+#include <sstream>
#include <string.h>
using namespace isc::data;
namespace dhcp {
namespace test {
-const char* NakedDhcpv6SrvTest::DUID_FILE = "server-id-test.txt";
+const char* BaseServerTest::DUID_FILE = "kea-dhcp6-serverid";
+
+BaseServerTest::BaseServerTest()
+ : original_datadir_(CfgMgr::instance().getDataDir()) {
+ CfgMgr::instance().setDataDir(TEST_DATA_BUILDDIR);
+}
+
+BaseServerTest::~BaseServerTest() {
+ // Remove test DUID file.
+ std::ostringstream s;
+ s << CfgMgr::instance().getDataDir() << "/" << DUID_FILE;
+ static_cast<void>(::remove(s.str().c_str()));
+ // Revert to original data directory.
+ CfgMgr::instance().setDataDir(original_datadir_);
+}
Dhcpv6SrvTest::Dhcpv6SrvTest()
-:srv_(0) {
+ : NakedDhcpv6SrvTest(), srv_(0) {
subnet_ = isc::dhcp::Subnet6Ptr
(new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
48, 1000, 2000, 3000, 4000));
namespace dhcp {
namespace test {
+/// @brief Base class for DHCPv6 server testing.
+///
+/// Currently it configures the test data path directory in
+/// the @c CfgMgr. When the object is destroyed, the original
+/// path is reverted.
+class BaseServerTest : public ::testing::Test {
+public:
+
+ /// @brief Location of a test DUID file
+ static const char* DUID_FILE;
+
+ /// @brief Constructor.
+ BaseServerTest();
+
+ /// @brief Destructor.
+ virtual ~BaseServerTest();
+
+private:
+
+ /// @brief Holds the original data directory.
+ std::string original_datadir_;
+
+};
+
/// @brief "naked" Dhcpv6Srv class that exposes internal members
class NakedDhcpv6Srv: public isc::dhcp::Dhcpv6Srv {
public:
/// @brief Test fixture for any tests requiring blank/empty configuration
/// serves as base class for additional tests
-class NakedDhcpv6SrvTest : public ::testing::Test {
+class NakedDhcpv6SrvTest : public BaseServerTest {
public:
/// @brief Constructor
NakedDhcpv6SrvTest();
- /// @brief Location of a test DUID file
- static const char* DUID_FILE;
-
// Generate IA_NA or IA_PD option with specified parameters
boost::shared_ptr<isc::dhcp::Option6IA> generateIA
(uint16_t type, uint32_t iaid, uint32_t t1, uint32_t t2);
#include <dhcp/duid.h>
#include <dhcp/iface_mgr.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/lease_mgr_factory.h>
};
-class JSONFileBackendTest : public ::testing::Test {
+class JSONFileBackendTest : public dhcp::test::BaseServerTest {
public:
- JSONFileBackendTest() {
+ JSONFileBackendTest()
+ : BaseServerTest() {
}
~JSONFileBackendTest() {
\"interfaces-config\": {
\"interfaces\": [ ]
},
+ \"server-id\": {
+ \"type\": \"LLT\",
+ \"persist\": false
+ },
\"preferred-lifetime\": 3000,
\"valid-lifetime\": 4000,
\"renew-timer\": 1000,
# The following build order must be maintained.
-SUBDIRS = exceptions util log hooks cryptolink dns cc asiolink dhcp config stats \
- asiodns testutils dhcp_ddns eval dhcpsrv cfgrpt
+SUBDIRS = exceptions util log hooks cryptolink dns cc asiolink testutils dhcp config \
+ stats asiodns dhcp_ddns eval dhcpsrv cfgrpt
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+libdhcp___unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
libdhcp___unittests_LDADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS)
libdhcp___unittests_LDADD += $(BOOST_LIBS) $(GTEST_LDADD)
endif
#include <dhcp/dhcp4.h>
#include <dhcp/duid_factory.h>
#include <dhcp/tests/iface_mgr_test_config.h>
+#include <testutils/io_utils.h>
#include <util/encode/hex.h>
#include <util/range_utilities.h>
#include <boost/algorithm/string.hpp>
std::string
DUIDFactoryTest::readDefaultFile() const {
- std::ifstream ifs;
- ifs.open(absolutePath(DEFAULT_DUID_FILE).c_str(), std::ifstream::in);
- if (!ifs.good()) {
- return (std::string());
- }
- std::string buf;
- std::ostringstream output;
- while (!ifs.eof() && ifs.good()) {
- ifs >> buf;
- output << buf;
- }
- ifs.close();
-
- return (output.str());
+ return (dhcp::test::readFile(absolutePath(DEFAULT_DUID_FILE)));
}
std::vector<uint8_t>
CfgDUID::CfgDUID()
: type_(DUID::DUID_LLT), identifier_(), htype_(0), time_(0),
- enterprise_id_(0) {
+ enterprise_id_(0), persist_(true) {
}
void
DuidPtr
CfgDUID::create(const std::string& duid_file_path) const {
// Use DUID factory to create a DUID instance.
- DUIDFactory factory(duid_file_path);
+ DUIDFactory factory(persist() ? duid_file_path : "");
switch (getType()) {
case DUID::DUID_LLT:
enterprise_id_ = enterprise_id;
}
+ /// @brief Checks if server identifier should be stored on disk.
+ ///
+ /// @return true if the server identifier should be stored on
+ /// the disk, false otherwise.
+ bool persist() const {
+ return (persist_);
+ }
+
+ /// @brief Sets a boolean flag indicating if the server identifier
+ /// should be stored on the disk (if true) or not (if false).
+ ///
+ /// @param persist New value of the flag.
+ void setPersist(const bool persist) {
+ persist_ = persist;
+ }
+
/// @brief Creates instance of a DUID from the current configuration.
///
/// @param duid_file_path Absolute path to a DUID file.
/// @brief Enterprise id used for DUID-EN.
uint32_t enterprise_id_;
+ /// @brief Boolean flag which indicates if server identifier should
+ /// be stored on the disk.
+ bool persist_;
};
/// @name Pointers to the @c CfgDUID objects.
}
-std::string CfgMgr::getDataDir() {
+std::string CfgMgr::getDataDir() const {
return (datadir_);
}
+void
+CfgMgr::setDataDir(const std::string& datadir) {
+ datadir_ = datadir;
+}
+
bool
CfgMgr::isDuplicate(const Subnet6& subnet) const {
for (Subnet6Collection::const_iterator subnet_it = subnets6_.begin();
/// This method returns a path to writeable directory that DHCP servers
/// can store data in.
/// @return data directory
- std::string getDataDir();
+ std::string getDataDir() const;
+
+ /// @brief Sets new data directory.
+ ///
+ /// @param datadir New data directory.
+ void setDataDir(const std::string& datadir);
/// @brief Sets whether server should send back client-id in DHCPv4
///
setTime(element.second->intValue());
} else if (element.first == "enterprise-id") {
setEnterpriseId(element.second->intValue());
+ } else if (element.first == "persist") {
+ setPersist(element.second->boolValue());
} else {
isc_throw(DhcpConfigError, "unsupported configuration "
"parameter '" << element.first << "'");
cfg->setEnterpriseId(static_cast<uint32_t>(enterprise_id));
}
+void
+DUIDConfigParser::setPersist(const bool persist) {
+ const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ cfg->setPersist(persist);
+}
+
template<typename NumericType>
void
DUIDConfigParser::checkRange(const std::string& parameter_name,
/// @param enterprise_id Enterprise id.
void setEnterpriseId(const int64_t enterprise_id) const;
+ /// @brief Set persistence flag.
+ ///
+ /// @param persist A boolean value indicating if the server
+ /// identifier should be stored on the disk (if true) or
+ /// not (if false).
+ void setPersist(const bool persist);
+
/// @brief Verifies if the specified parameter is in range.
///
/// Each numeric value must be in range of [0 .. max_value], where
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
libdhcpsrv_unittests_LDADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS)
libdhcpsrv_unittests_LDADD += $(BOOST_LIBS) $(GTEST_LDADD)
endif
#include <dhcp/duid.h>
#include <dhcpsrv/cfg_duid.h>
#include <exceptions/exceptions.h>
+#include <testutils/io_utils.h>
#include <util/encode/hex.h>
#include <gtest/gtest.h>
#include <stdint.h>
EXPECT_EQ(0, cfg_duid.getHType());
EXPECT_EQ(0, cfg_duid.getTime());
EXPECT_EQ(0, cfg_duid.getEnterpriseId());
+ EXPECT_TRUE(cfg_duid.persist());
}
// This test verifies that it is possible to set values for the CfgDUID.
ASSERT_NO_THROW(cfg_duid.setHType(100));
ASSERT_NO_THROW(cfg_duid.setTime(32100));
ASSERT_NO_THROW(cfg_duid.setEnterpriseId(10));
+ ASSERT_NO_THROW(cfg_duid.setPersist(false));
// Check that values have been set correctly.
EXPECT_EQ(DUID::DUID_EN, cfg_duid.getType());
EXPECT_EQ(100, cfg_duid.getHType());
EXPECT_EQ(32100, cfg_duid.getTime());
EXPECT_EQ(10, cfg_duid.getEnterpriseId());
+ EXPECT_FALSE(cfg_duid.persist());
}
// This test checks positive scenarios for setIdentifier.
// Verify if the DUID is correct.
EXPECT_EQ("00:01:00:08:00:00:11:23:12:56:43:25:a6:3f",
duid->toText());
+
+ // Verify that the DUID file has been created.
+ EXPECT_TRUE(dhcp::test::fileExists(absolutePath(DUID_FILE_NAME)));
}
// This method checks that the DUID-EN can be created from the
// Verify if the DUID is correct.
EXPECT_EQ("00:02:00:00:10:10:25:0f:3e:26:a7:62", duid->toText());
+
+ // Verify that the DUID file has been created.
+ EXPECT_TRUE(dhcp::test::fileExists(absolutePath(DUID_FILE_NAME)));
}
// This method checks that the DUID-LL can be created from the
// Verify if the DUID is correct.
EXPECT_EQ("00:03:00:02:12:41:34:a4:b3:67", duid->toText());
+
+ // Verify that the DUID file has been created.
+ EXPECT_TRUE(dhcp::test::fileExists(absolutePath(DUID_FILE_NAME)));
+}
+
+// This test verifies that it is possible to disable storing
+// generated DUID on a hard drive.
+TEST_F(CfgDUIDTest, createDisableWrite) {
+ CfgDUID cfg;
+ ASSERT_NO_THROW(cfg.setType(DUID::DUID_EN));
+ ASSERT_NO_THROW(cfg.setIdentifier("250F3E26A762"));
+ ASSERT_NO_THROW(cfg.setEnterpriseId(0x1010));
+ ASSERT_NO_THROW(cfg.setPersist(false));
+
+ // Generate DUID from this configuration.
+ DuidPtr duid;
+ ASSERT_NO_THROW(duid = cfg.create(absolutePath(DUID_FILE_NAME)));
+ ASSERT_TRUE(duid);
+
+ // Verify if the DUID is correct.
+ EXPECT_EQ("00:02:00:00:10:10:25:0f:3e:26:a7:62", duid->toText());
+
+ // DUID persistence is disabled so there should be no DUID file.
+ EXPECT_FALSE(dhcp::test::fileExists(absolutePath(DUID_FILE_NAME)));
}
} // end of anonymous namespace
" \"identifier\": \"ABCDEF\","
" \"time\": 100,"
" \"htype\": 8,"
- " \"enterprise-id\": 2024"
+ " \"enterprise-id\": 2024,"
+ " \"persist\": false"
"}"));
// Verify that parameters have been set correctly.
EXPECT_EQ(8, cfg_duid->getHType());
EXPECT_EQ(100, cfg_duid->getTime());
EXPECT_EQ(2024, cfg_duid->getEnterpriseId());
+ EXPECT_FALSE(cfg_duid->persist());
}
// Test out of range values for time.
if HAVE_GTEST
noinst_LTLIBRARIES = libkea-testutils.la
-libkea_testutils_la_SOURCES = unix_control_client.h unix_control_client.cc
+libkea_testutils_la_SOURCES = io_utils.cc io_utils.h
+libkea_testutils_la_SOURCES += unix_control_client.h unix_control_client.cc
libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <testutils/io_utils.h>
+#include <gtest/gtest.h>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+bool fileExists(const std::string& file_path) {
+ std::ifstream fs(file_path.c_str());
+ const bool file_exists = fs.good();
+ fs.close();
+ return (file_exists);
+}
+
+std::string readFile(const std::string& file_path) {
+ std::ifstream ifs;
+ ifs.open(file_path.c_str(), std::ifstream::in);
+ if (!ifs.good()) {
+ return (std::string());
+ }
+ std::string buf;
+ std::ostringstream output;
+ while (!ifs.eof() && ifs.good()) {
+ ifs >> buf;
+ output << buf;
+ }
+ ifs.close();
+
+ return (output.str());
+}
+
+}; // end of isc::dhcp::test namespace
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef TEST_IO_UTILS_H
+#define TEST_IO_UTILS_H
+
+#include <string>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief Checks if specified file exists.
+///
+/// @param file_path Path to a file.
+/// @return true if the file exists, false otherwise.
+bool fileExists(const std::string& file_path);
+
+/// @brief Reads contents of the specified file.
+///
+/// @param file_path Path to a file.
+/// @return File contents.
+std::string readFile(const std::string& file_path);
+
+}; // end of isc::dhcp::test namespace
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // TEST_IO_UTILS_H