From: Thomas Markwalder Date: Thu, 8 May 2025 19:14:08 +0000 (-0400) Subject: [#3831] Error on bad lease file path X-Git-Tag: Kea-2.7.9~57 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=36b8bfd263fa88ac8996edf96a16922638d2e87b;p=thirdparty%2Fkea.git [#3831] Error on bad lease file path /doc/examples/kea4/all-keys-netconf.json /doc/examples/kea4/all-keys.json /doc/examples/kea4/dhcpv4-over-dhcpv6.json /doc/examples/kea6/all-keys-netconf.json /doc/examples/kea6/all-keys.json /doc/examples/kea6/dhcpv4-over-dhcpv6.json Remove "/tmp" from lease file names /src/bin/admin/tests/memfile_tests.sh.in /src/bin/dhcp4/tests/dhcp4_process_tests.sh.in /src/bin/dhcp6/tests/dhcp6_process_tests.sh.in export KEA_DHCP_DATA_DIR /src/bin/shell/tests/dhcp4_basic_auth_tests.sh.in /src/bin/shell/tests/dhcp6_basic_auth_tests.sh.in /src/bin/shell/tests/shell_dhcp4_process_tests.sh.in /src/bin/shell/tests/shell_dhcp6_process_tests.sh.in /src/bin/shell/tests/tls_dhcp4_process_tests.sh.in /src/bin/shell/tests/tls_dhcp6_process_tests.sh.in /src/lib/dhcpsrv/dhcpsrv_messages.* Replace WARN message with DHCPSRV_MEMFILE_FAILED_TO_OPEN error /src/lib/dhcpsrv/memfile_lease_mgr.cc Memfile_LeaseMgr::getDefaultLeaseFilePath() - uses CfgMgr::getDataDir() Memfile_LeaseMgr::initLeaseFilePath() - call CfgMgr::validatePath() without try-catch Memfile_LeaseMgr::factory() - log error and rethrow /src/lib/dhcpsrv/tests/cfgmgr_unittest.cc Added use of EnvVarWrapper /src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc Updated tests TEST_F(MemfileLeaseMgrTest, defaultDataDir) TEST_F(MemfileLeaseMgrTest, dataDirEnvVarOverride) TEST_F(MemfileLeaseMgrTest, dataDirExplicitOveride) - new tests /src/lib/testutils/Makefile.am Added env_var_wrapper.* --- diff --git a/doc/examples/kea4/all-keys-netconf.json b/doc/examples/kea4/all-keys-netconf.json index 1b956edec8..b595fe703a 100644 --- a/doc/examples/kea4/all-keys-netconf.json +++ b/doc/examples/kea4/all-keys-netconf.json @@ -550,7 +550,7 @@ // 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 diff --git a/doc/examples/kea4/all-keys.json b/doc/examples/kea4/all-keys.json index 0582233e2c..5117e04a3b 100644 --- a/doc/examples/kea4/all-keys.json +++ b/doc/examples/kea4/all-keys.json @@ -672,7 +672,7 @@ // 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 diff --git a/doc/examples/kea4/dhcpv4-over-dhcpv6.json b/doc/examples/kea4/dhcpv4-over-dhcpv6.json index c622c4225e..8cf61b7782 100644 --- a/doc/examples/kea4/dhcpv4-over-dhcpv6.json +++ b/doc/examples/kea4/dhcpv4-over-dhcpv6.json @@ -12,7 +12,7 @@ "lease-database": { "type": "memfile", - "name": "/tmp/kea-dhcp4.csv", + "name": "kea-dhcp4.csv", "lfc-interval": 3600 }, diff --git a/doc/examples/kea6/all-keys-netconf.json b/doc/examples/kea6/all-keys-netconf.json index 8f812e0f5b..7a980f80eb 100644 --- a/doc/examples/kea6/all-keys-netconf.json +++ b/doc/examples/kea6/all-keys-netconf.json @@ -476,7 +476,7 @@ // 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 diff --git a/doc/examples/kea6/all-keys.json b/doc/examples/kea6/all-keys.json index bb6842ab49..1b2dc6e11d 100644 --- a/doc/examples/kea6/all-keys.json +++ b/doc/examples/kea6/all-keys.json @@ -598,7 +598,7 @@ // 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 diff --git a/doc/examples/kea6/dhcpv4-over-dhcpv6.json b/doc/examples/kea6/dhcpv4-over-dhcpv6.json index 56e371e3ce..d832ca5651 100644 --- a/doc/examples/kea6/dhcpv4-over-dhcpv6.json +++ b/doc/examples/kea6/dhcpv4-over-dhcpv6.json @@ -13,7 +13,7 @@ "lease-database": { "type": "memfile", - "name": "/tmp/kea-dhcp6.csv" + "name": "kea-dhcp6.csv" }, "preferred-lifetime": 3000, diff --git a/src/bin/admin/tests/memfile_tests.sh.in b/src/bin/admin/tests/memfile_tests.sh.in index 14b1904e85..bd92ed672b 100755 --- a/src/bin/admin/tests/memfile_tests.sh.in +++ b/src/bin/admin/tests/memfile_tests.sh.in @@ -14,6 +14,8 @@ set -eu # 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" diff --git a/src/bin/dhcp4/tests/dhcp4_process_tests.sh.in b/src/bin/dhcp4/tests/dhcp4_process_tests.sh.in index cd2d4bf17e..1b6b87f595 100755 --- a/src/bin/dhcp4/tests/dhcp4_process_tests.sh.in +++ b/src/bin/dhcp4/tests/dhcp4_process_tests.sh.in @@ -15,6 +15,7 @@ CFG_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/test_config.json" # 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" diff --git a/src/bin/dhcp6/tests/dhcp6_process_tests.sh.in b/src/bin/dhcp6/tests/dhcp6_process_tests.sh.in index 20dfcc04db..06356538de 100755 --- a/src/bin/dhcp6/tests/dhcp6_process_tests.sh.in +++ b/src/bin/dhcp6/tests/dhcp6_process_tests.sh.in @@ -15,6 +15,7 @@ CFG_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test_config.json" # 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" diff --git a/src/bin/shell/tests/dhcp4_basic_auth_tests.sh.in b/src/bin/shell/tests/dhcp4_basic_auth_tests.sh.in index 36e044edd0..33b737ec8f 100755 --- a/src/bin/shell/tests/dhcp4_basic_auth_tests.sh.in +++ b/src/bin/shell/tests/dhcp4_basic_auth_tests.sh.in @@ -20,6 +20,7 @@ test_suite="dhcp4" 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. diff --git a/src/bin/shell/tests/dhcp6_basic_auth_tests.sh.in b/src/bin/shell/tests/dhcp6_basic_auth_tests.sh.in index b02b083df3..07bf165077 100755 --- a/src/bin/shell/tests/dhcp6_basic_auth_tests.sh.in +++ b/src/bin/shell/tests/dhcp6_basic_auth_tests.sh.in @@ -20,6 +20,7 @@ test_suite="dhcp6" 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. diff --git a/src/bin/shell/tests/shell_dhcp4_process_tests.sh.in b/src/bin/shell/tests/shell_dhcp4_process_tests.sh.in index a3805cf173..1b06ef1eb5 100755 --- a/src/bin/shell/tests/shell_dhcp4_process_tests.sh.in +++ b/src/bin/shell/tests/shell_dhcp4_process_tests.sh.in @@ -20,6 +20,7 @@ test_suite="dhcp4" 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. diff --git a/src/bin/shell/tests/shell_dhcp6_process_tests.sh.in b/src/bin/shell/tests/shell_dhcp6_process_tests.sh.in index f253f66c50..26e4711b63 100755 --- a/src/bin/shell/tests/shell_dhcp6_process_tests.sh.in +++ b/src/bin/shell/tests/shell_dhcp6_process_tests.sh.in @@ -20,6 +20,7 @@ test_suite="dhcp6" 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. diff --git a/src/bin/shell/tests/tls_dhcp4_process_tests.sh.in b/src/bin/shell/tests/tls_dhcp4_process_tests.sh.in index bd59b1cf76..7e200994de 100755 --- a/src/bin/shell/tests/tls_dhcp4_process_tests.sh.in +++ b/src/bin/shell/tests/tls_dhcp4_process_tests.sh.in @@ -21,6 +21,7 @@ test_suite="dhcp4" 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. diff --git a/src/bin/shell/tests/tls_dhcp6_process_tests.sh.in b/src/bin/shell/tests/tls_dhcp6_process_tests.sh.in index 6df92a2ccf..7f5269d9f7 100755 --- a/src/bin/shell/tests/tls_dhcp6_process_tests.sh.in +++ b/src/bin/shell/tests/tls_dhcp6_process_tests.sh.in @@ -21,6 +21,7 @@ test_suite="dhcp6" 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. diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.cc b/src/lib/dhcpsrv/dhcpsrv_messages.cc index 6ab28a4192..f47bbfe464 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.cc +++ b/src/lib/dhcpsrv/dhcpsrv_messages.cc @@ -100,6 +100,7 @@ extern const isc::log::MessageID DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED6 = "DH 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"; @@ -275,6 +276,7 @@ const char* values[] = { "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", diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.h b/src/lib/dhcpsrv/dhcpsrv_messages.h index 6a2c7e6ed1..bc69ddb0ef 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.h +++ b/src/lib/dhcpsrv/dhcpsrv_messages.h @@ -101,6 +101,7 @@ extern const isc::log::MessageID DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED6; 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; diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes index e8f82ac1e2..78586d5c19 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.mes +++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes @@ -994,3 +994,11 @@ included in the message. % 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. diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc index 7e9630d53d..9bc45d8034 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -2257,11 +2257,18 @@ Memfile_LeaseMgr::appendSuffix(const std::string& file_name, } 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()); } @@ -2310,8 +2317,12 @@ Memfile_LeaseMgr::initLeaseFilePath(Universe u) { 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); } @@ -3487,9 +3498,15 @@ Memfile_LeaseMgr::writeLeases6Internal(const std::string& filename) { 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 diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h index e1a3d733ae..ae77a5e9c1 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.h +++ b/src/lib/dhcpsrv/memfile_lease_mgr.h @@ -992,7 +992,9 @@ public: /// @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. /// diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc index 1b72f665fe..1a2ce09964 100644 --- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -33,6 +34,7 @@ using namespace isc::dhcp::test; using namespace isc::util; using namespace isc::stats; using namespace isc::process; +using namespace isc::test; using namespace isc; namespace { @@ -256,7 +258,7 @@ TEST(ValueStorageTest, StringTesting) { 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(); } @@ -313,6 +315,9 @@ public: 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_; }; diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc index afe22f7a70..0faa336482 100644 --- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -45,6 +46,7 @@ using namespace isc::db; using namespace isc::dhcp; using namespace isc::dhcp::test; using namespace isc::util; +using namespace isc::test; namespace { @@ -105,16 +107,19 @@ public: /// @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_); @@ -165,6 +170,9 @@ public: 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. @@ -202,7 +210,7 @@ public: /// @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()); } @@ -386,12 +394,6 @@ public: 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_; @@ -400,6 +402,12 @@ public: /// @brief List of names of other files to removed. vector 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 @@ -446,6 +454,68 @@ TEST_F(MemfileLeaseMgrTest, constructor) { 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 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 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 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(); diff --git a/src/lib/testutils/Makefile.am b/src/lib/testutils/Makefile.am index 34942b5158..266fa86a8c 100644 --- a/src/lib/testutils/Makefile.am +++ b/src/lib/testutils/Makefile.am @@ -16,6 +16,7 @@ libkea_testutils_la_SOURCES += unix_control_client.cc unix_control_client.h 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) diff --git a/src/lib/testutils/env_var_wrapper.cc b/src/lib/testutils/env_var_wrapper.cc new file mode 100644 index 0000000000..4b3b3dd1e9 --- /dev/null +++ b/src/lib/testutils/env_var_wrapper.cc @@ -0,0 +1,43 @@ +// 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 + +#include + +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 diff --git a/src/lib/testutils/env_var_wrapper.h b/src/lib/testutils/env_var_wrapper.h new file mode 100644 index 0000000000..0f43af385f --- /dev/null +++ b/src/lib/testutils/env_var_wrapper.h @@ -0,0 +1,54 @@ +// 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 + +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