// Name of the lease file. In the case of a database it specifies the
// database name.
- "name": "/tmp/kea-dhcp4.csv",
+ "name": "kea-dhcp4.csv",
// memfile-specific parameter indicating whether leases should
// be saved on persistent storage (disk) or not. The true value
// Name of the lease file. In the case of a database it specifies the
// database name.
- "name": "/tmp/kea-dhcp4.csv",
+ "name": "kea-dhcp4.csv",
// memfile-specific parameter indicating whether leases should
// be saved on persistent storage (disk) or not. The true value
"lease-database": {
"type": "memfile",
- "name": "/tmp/kea-dhcp4.csv",
+ "name": "kea-dhcp4.csv",
"lfc-interval": 3600
},
// Name of the lease file. In the case of a database it specifies the
// database name.
- "name": "/tmp/kea-dhcp6.csv",
+ "name": "kea-dhcp6.csv",
// memfile-specific parameter indicating whether leases should
// be saved on persistent storage (disk) or not. The true value
// Name of the lease file. In the case of a database it specifies the
// database name.
- "name": "/tmp/kea-dhcp6.csv",
+ "name": "kea-dhcp6.csv",
// memfile-specific parameter indicating whether leases should
// be saved on persistent storage (disk) or not. The true value
"lease-database": {
"type": "memfile",
- "name": "/tmp/kea-dhcp6.csv"
+ "name": "kea-dhcp6.csv"
},
"preferred-lifetime": 3000,
# shellcheck source=src/lib/testutils/dhcp_test_lib.sh.in
. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/admin/tests"
+
# Locations of memfile tools
kea_admin="@abs_top_builddir@/src/bin/admin/kea-admin"
kea_lfc="@abs_top_builddir@/src/bin/lfc/kea-lfc"
# Path to the Kea log file.
LOG_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/test.log"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/dhcp4/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/test_leases.csv"
# Path to the Kea LFC application
export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc"
# Path to the Kea log file.
LOG_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test.log"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/dhcp6/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test_leases.csv"
# Path to the Kea LFC application
export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc"
CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/shell/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/shell/tests/test_leases.csv"
# Path to the Dhcp4 Server log file.
CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/shell/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/shell/tests/test_leases.csv"
# Path to the Dhcp6 Server log file.
CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/shell/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/shell/tests/test_leases.csv"
# Path to the Dhcp4 Server log file.
CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/shell/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/shell/tests/test_leases.csv"
# Path to the Dhcp6 Server log file.
CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/shell/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/shell/tests/test_leases.csv"
# Path to the Dhcp4 Server log file.
CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
# Path to the Kea lease file.
+export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/shell/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/shell/tests/test_leases.csv"
# Path to the Dhcp6 Server log file.
extern const isc::log::MessageID DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED_START = "DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED_START";
extern const isc::log::MessageID DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4 = "DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4";
extern const isc::log::MessageID DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4_ERROR = "DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4_ERROR";
+extern const isc::log::MessageID DHCPSRV_MEMFILE_FAILED_TO_OPEN = "DHCPSRV_MEMFILE_FAILED_TO_OPEN";
extern const isc::log::MessageID DHCPSRV_MEMFILE_GET4 = "DHCPSRV_MEMFILE_GET4";
extern const isc::log::MessageID DHCPSRV_MEMFILE_GET6 = "DHCPSRV_MEMFILE_GET6";
extern const isc::log::MessageID DHCPSRV_MEMFILE_GET6_DUID = "DHCPSRV_MEMFILE_GET6_DUID";
"DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED_START", "starting deletion of %1 expired-reclaimed leases",
"DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4", "extracting extended info saw %1 leases, extended info sanity checks modified %2 / updated %3 leases and %4 leases have relay or remote id",
"DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4_ERROR", "extracting extended info got an exception on the lease for %1: %2",
+ "DHCPSRV_MEMFILE_FAILED_TO_OPEN", "Could not open lease file: %1",
"DHCPSRV_MEMFILE_GET4", "obtaining all IPv4 leases",
"DHCPSRV_MEMFILE_GET6", "obtaining all IPv6 leases",
"DHCPSRV_MEMFILE_GET6_DUID", "obtaining IPv6 leases for DUID %1",
extern const isc::log::MessageID DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED_START;
extern const isc::log::MessageID DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4;
extern const isc::log::MessageID DHCPSRV_MEMFILE_EXTRACT_EXTENDED_INFO4_ERROR;
+extern const isc::log::MessageID DHCPSRV_MEMFILE_FAILED_TO_OPEN;
extern const isc::log::MessageID DHCPSRV_MEMFILE_GET4;
extern const isc::log::MessageID DHCPSRV_MEMFILE_GET6;
extern const isc::log::MessageID DHCPSRV_MEMFILE_GET6_DUID;
% DHCPSRV_UNKNOWN_DB unknown database type: %1
The database access string specified a database type (given in the
message) that is unknown to the software. This is a configuration error.
+
+% DHCPSRV_MEMFILE_FAILED_TO_OPEN Could not open lease file: %1
+This error is issued when the lease file could not be opened. The
+argument contains the details. The most likely cause is that the `name`
+parameter for memfile back end contains a path other than the supported
+path. The argument will contain the details. The path component may
+simply be omitted. To override the default supported path, set the
+environment variable KEA_DHCP_DATA_DIR prior to starting the server.
}
std::string
-Memfile_LeaseMgr::getDefaultLeaseFilePath(Universe u) const {
- std::ostringstream s;
- s << CfgMgr::instance().getDataDir() << "/kea-leases";
- s << (u == V4 ? "4" : "6");
- s << ".csv";
+Memfile_LeaseMgr::getDefaultLeaseFilePath(Universe u,
+ std::string filename /* = "" */) const {
+ std::ostringstream s;;
+ s << CfgMgr::instance().getDataDir();
+ if (filename.empty()) {
+ s << "/kea-leases";
+ s << (u == V4 ? "4" : "6");
+ s << ".csv";
+ } else {
+ s << "/" << filename;
+ }
+
return (s.str());
}
try {
lease_file = conn_.getParameter("name");
} catch (const Exception&) {
- lease_file = getDefaultLeaseFilePath(u);
+ // Not specified, use the defualt.
+ return (getDefaultLeaseFilePath(u));
}
+
+ // If path is invalid this will throw.
+ lease_file = CfgMgr::instance().validatePath(lease_file);
return (lease_file);
}
TrackingLeaseMgrPtr
Memfile_LeaseMgr::factory(const isc::db::DatabaseConnection::ParameterMap& parameters) {
- LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_DB)
- .arg(DatabaseConnection::redactedAccessString(parameters));
- return (TrackingLeaseMgrPtr(new Memfile_LeaseMgr(parameters)));
+ try {
+ LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_DB)
+ .arg(DatabaseConnection::redactedAccessString(parameters));
+ return (TrackingLeaseMgrPtr(new Memfile_LeaseMgr(parameters)));
+ } catch (const std::exception& ex) {
+ LOG_ERROR(dhcpsrv_logger, DHCPSRV_MEMFILE_FAILED_TO_OPEN)
+ .arg(ex.what());
+ throw ex;
+ }
}
} // namespace dhcp
/// @brief Returns default path to the lease file.
///
/// @param u Universe (V4 or V6).
- std::string getDefaultLeaseFilePath(Universe u) const;
+ /// @param filename optional filename to use.
+ std::string getDefaultLeaseFilePath(Universe u,
+ const std::string filename = "") const;
/// @brief Returns an absolute path to the lease file.
///
#include <process/logging_info.h>
#include <stats/stats_mgr.h>
#include <util/chrono_time_utils.h>
+#include <testutils/env_var_wrapper.h>
#include <gtest/gtest.h>
using namespace isc::util;
using namespace isc::stats;
using namespace isc::process;
+using namespace isc::test;
using namespace isc;
namespace {
class CfgMgrTest : public ::testing::Test {
public:
- CfgMgrTest() {
+ CfgMgrTest() : data_dir_env_var_("KEA_DHCP_DATA_DIR") {
// make sure we start with a clean configuration
clear();
}
CfgMgr::instance().setFamily(family);
}
+ /// @brief RAII wrapper for KEA_DHCP_DATA_DIR env variable.
+ EnvVarWrapper data_dir_env_var_;
+
/// used in client classification (or just empty container for other tests)
isc::dhcp::ClientClasses classify_;
};
#include <util/pid_file.h>
#include <util/range_utilities.h>
#include <util/stopwatch.h>
+#include <testutils/env_var_wrapper.h>
#include <gtest/gtest.h>
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::util;
+using namespace isc::test;
namespace {
/// @brief Test fixture class for @c Memfile_LeaseMgr
class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
public:
-
/// @brief memfile lease mgr test constructor
///
/// Creates memfile and stores it in lmptr_ pointer
MemfileLeaseMgrTest() :
- io4_(getLeaseFilePath("leasefile4_0.csv")),
- io6_(getLeaseFilePath("leasefile6_0.csv")),
io_service_(getIOService()),
timer_mgr_(TimerMgr::instance()),
- extra_files_() {
+ extra_files_(),
+ data_dir_env_var_("KEA_DHCP_DATA_DIR") {
+
+ // Save the pre-test data dir and set it to the test directory.
+ CfgMgr::instance().clear();
+ original_datadir_ = CfgMgr::instance().getDataDir();
+ CfgMgr::instance().getDataDir(true, TEST_DATA_BUILDDIR);
timer_mgr_->setIOService(io_service_);
DatabaseConnection::setIOService(io_service_);
MultiThreadingMgr::instance().setMode(false);
getIOService()->stopAndPoll();
+
+ // Revert to original data directory.
+ CfgMgr::instance().getDataDir(true, original_datadir_);
}
/// @brief Remove files being products of Lease File Cleanup.
/// @return Full path to the lease file.
static std::string getLeaseFilePath(const std::string& filename) {
std::ostringstream s;
- s << TEST_DATA_BUILDDIR << "/" << filename;
+ s << CfgMgr::instance().getDataDir() << "/" << filename;
return (s.str());
}
return (lease);
}
- /// @brief Object providing access to v4 lease IO.
- LeaseFileIO io4_;
-
- /// @brief Object providing access to v6 lease IO.
- LeaseFileIO io6_;
-
/// @brief Pointer to the IO service used by the tests.
IOServicePtr io_service_;
/// @brief List of names of other files to removed.
vector<string> extra_files_;
+
+ /// @brief RAII wrapper for KEA_DHCP_DATA_DIR env variable.
+ EnvVarWrapper data_dir_env_var_;
+
+ /// @brief Stores the pre-test DHCP data directory.
+ std::string original_datadir_;
};
/// @brief This test checks if the LeaseMgr can be instantiated and that it
EXPECT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
}
+/// @brief Verifies that the supported path is the enforced.
+TEST_F(MemfileLeaseMgrTest, defaultDataDir) {
+ ASSERT_TRUE(data_dir_env_var_.getValue().empty());
+ DatabaseConnection::ParameterMap pmap;
+ pmap["universe"] = "6";
+ pmap["persist"] = "true";
+ pmap["lfc-interval"] = "0";
+ pmap["name"] = "leasefile6_1.csv";
+ boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+ ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+ EXPECT_EQ(lease_mgr->getLeaseFilePath(Memfile_LeaseMgr::V6),
+ CfgMgr::instance().validatePath("leasefile6_1.csv"));
+
+ pmap["name"] = "/tmp/leasefile6_1.csv";
+ std::ostringstream os;
+ os << "invalid path specified: '/tmp', supported path is '"
+ << CfgMgr::instance().getDataDir() << "'";
+
+ ASSERT_THROW_MSG(lease_mgr.reset(new Memfile_LeaseMgr(pmap)),
+ BadValue, os.str());
+}
+
+/// @brief Verifies that the supported path may be overriden witn
+/// the environment variable KEA_DHCP_DATA_DIR.
+TEST_F(MemfileLeaseMgrTest, dataDirEnvVarOverride) {
+ ASSERT_TRUE(data_dir_env_var_.getValue().empty());
+ data_dir_env_var_.setValue("/tmp");
+ auto valid_path = CfgMgr::instance().getDataDir(true);
+ ASSERT_EQ(valid_path, "/tmp");
+
+ DatabaseConnection::ParameterMap pmap;
+ pmap["universe"] = "6";
+ pmap["persist"] = "true";
+ pmap["lfc-interval"] = "0";
+ pmap["name"] = "leasefile6_1.csv";
+ boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+ ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+ EXPECT_EQ(lease_mgr->getLeaseFilePath(Memfile_LeaseMgr::V6),
+ "/tmp/leasefile6_1.csv");
+}
+
+/// @brief Verifies that the supported path may be overriden with
+/// an explicit path even though its really only for UT testing.
+TEST_F(MemfileLeaseMgrTest, dataDirExplicitOveride) {
+ ASSERT_TRUE(data_dir_env_var_.getValue().empty());
+ auto valid_path = CfgMgr::instance().getDataDir(true, "/tmp");
+ ASSERT_EQ(valid_path, "/tmp");
+
+ DatabaseConnection::ParameterMap pmap;
+ pmap["universe"] = "6";
+ pmap["persist"] = "true";
+ pmap["lfc-interval"] = "0";
+ pmap["name"] = "leasefile6_1.csv";
+ boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+ ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+ EXPECT_EQ(lease_mgr->getLeaseFilePath(Memfile_LeaseMgr::V6),
+ "/tmp/leasefile6_1.csv");
+}
+
/// @brief Checks if there is no lease manager NoLeaseManager is thrown.
TEST_F(MemfileLeaseMgrTest, noLeaseManager) {
LeaseMgrFactory::destroy();
libkea_testutils_la_SOURCES += user_context_utils.cc user_context_utils.h
libkea_testutils_la_SOURCES += gtest_utils.h
libkea_testutils_la_SOURCES += multi_threading_utils.h
+libkea_testutils_la_SOURCES += env_var_wrapper.cc env_var_wrapper.h
libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libkea_testutils_la_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
--- /dev/null
+// Copyright (C) 2025 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <testutils/env_var_wrapper.h>
+
+namespace isc {
+namespace test {
+
+EnvVarWrapper::EnvVarWrapper(const std::string& name) : name_(name) {
+ original_value_ = getValue();
+}
+
+EnvVarWrapper::~EnvVarWrapper() {
+ setValue(original_value_);
+}
+
+std::string
+EnvVarWrapper::getOriginalValue() const {
+ return (original_value_);
+}
+
+std::string
+EnvVarWrapper::getValue() const {
+ auto value = getenv(name_.c_str());
+ return (value ? std::string(value) : std::string(""));
+}
+
+void
+EnvVarWrapper::setValue(const std::string value /* = "" */) {
+ if (value.empty()) {
+ unsetenv(name_.c_str());
+ } else {
+ setenv(name_.c_str(), value.c_str(), 1);
+ }
+}
+
+} // end of isc::test namespace
+} // end of isc namespace
--- /dev/null
+// Copyright (C) 2025 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef ENV_VAR_WRAPPER_H
+#define ENV_VAR_WRAPPER_H
+
+#include <string>
+
+namespace isc {
+namespace test {
+
+/// @brief Wrapper for environment varible that restores
+class EnvVarWrapper {
+public:
+ /// @brief Constructor
+ ///
+ /// Fetchs and retains the variable's current value as
+ /// the "original" value.
+ EnvVarWrapper(const std::string& name);
+
+ /// @brief Destructor.
+ ///
+ /// Restores the original value (if one), otherwise it
+ /// unsets it.
+ ~EnvVarWrapper();
+
+ /// @brief Fetches the original value of the env variable.
+ std::string getOriginalValue() const;
+
+ /// @brief Fetches the current value of the env variable.
+ std::string getValue() const;
+
+ /// @brief Sets the current value of the env variable.
+ ///
+ /// @param value new value of the variable. If empty the
+ /// variable is unset.
+ void setValue(const std::string value = "" );
+
+private:
+ /// @brief Name of the variable.
+ std::string name_;
+
+ /// @brief Value of the env variable at the time the wrapper
+ /// was constructed.
+ std::string original_value_;
+};
+
+} // end of isc::test namespace
+} // end of isc namespace
+
+#endif // ENV_VAR_WRAPPER_H