]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3840] backport #3831 to 2_6
authorRazvan Becheriu <razvan@isc.org>
Wed, 14 May 2025 17:06:20 +0000 (20:06 +0300)
committerRazvan Becheriu <razvan@isc.org>
Wed, 14 May 2025 19:52:51 +0000 (22:52 +0300)
34 files changed:
doc/sphinx/arm/dhcp6-srv.rst
doc/sphinx/arm/hooks-lease-cmds.rst
doc/sphinx/arm/logging.rst
src/bin/admin/tests/memfile_tests.sh.in
src/bin/agent/tests/ca_process_tests.sh.in
src/bin/d2/tests/d2_cfg_mgr_unittests.cc
src/bin/d2/tests/d2_process_tests.sh.in
src/bin/d2/tests/d2_process_unittests.cc
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/dhcp4_process_tests.sh.in
src/bin/dhcp4/tests/direct_client_unittest.cc
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/dhcp6_process_tests.sh.in
src/bin/dhcp6/tests/dhcp6_test_utils.cc
src/bin/dhcp6/tests/dhcp6_test_utils.h
src/bin/keactrl/kea-ctrl-agent.conf.pre
src/bin/keactrl/kea-dhcp-ddns.conf.pre
src/bin/keactrl/kea-dhcp4.conf.pre
src/bin/keactrl/kea-dhcp6.conf.pre
src/bin/keactrl/kea-netconf.conf.pre
src/bin/keactrl/tests/keactrl_tests.sh.in
src/bin/netconf/tests/shtests/netconf_tests.sh.in
src/bin/shell/tests/basic_auth_tests.sh.in
src/bin/shell/tests/shell_process_tests.sh.in
src/bin/shell/tests/tls_ca_process_tests.sh.in
src/hooks/dhcp/lease_cmds/lease_cmds.cc
src/hooks/dhcp/lease_cmds/tests/lease_cmds4_unittest.cc
src/hooks/dhcp/lease_cmds/tests/lease_cmds6_unittest.cc
src/lib/process/Makefile.am
src/lib/process/log_parser.cc
src/lib/process/log_parser.h
src/lib/process/tests/d_cfg_mgr_unittests.cc
src/lib/process/tests/log_parser_unittests.cc
src/lib/util/filesystem.cc

index f924a447f73ad4dd14377e4af64ad16fa6a4d106..09931616ad796600161c0e883f005c2e3cd42709 100644 (file)
@@ -6236,7 +6236,7 @@ memory lease file into its data directory. By default this directory is
 
 .. note::
 
-    As of Kea 2.7.9, ``data-directory`` is deprecated. The duid and lease
+    As of Kea 2.6.3, ``data-directory`` is deprecated. The duid and lease
     files may only be loaded from the directory determined at
     compilation: ``"[kea-install-dir]/var/lib/kea"``. This path may be
     overridden at startup by setting the environment variable
index 827ddd90b2ca09385ea734ca9b32dc21a038eee7..46e54a03e7d4f86372fe85bcf90d60257a3731a9 100644 (file)
@@ -1089,6 +1089,16 @@ the file in an attempt to synchronize both the files and the in-memory images
 of the lease database. The extension ``.bak`` and the server PID number are added
 to the previous filename: for example, ``.bak14326``.
 
+.. note::
+
+    As of Kea 2.6.3, the lease file may only be written to the data directory
+    determined during compilation: ``"[kea-install-dir]/var/lib/kea"``. This
+    path may be overridden at startup by setting the environment variable
+    ``KEA_DHCP_DATA_DIRECTORY`` to the desired path.  If a path other than
+    this value is used in ``name``, Kea will emit an error and refuse to start
+    or, if already running, log an unrecoverable error.  For ease of use in
+    specifying a custom file name simply omit the path portion from ``filename``.
+
 .. note::
 
    These commands do not replace the LFC mechanism; they should be used
index 2e91edf49c84a799783cb367dc0a5ea768819c58..6ecb024dc2591e82aaa6e717495f33701d7f2c6f 100644 (file)
@@ -647,6 +647,17 @@ output), ``stderr`` (messages are printed on stderr), ``syslog``
 (messages are logged to syslog using a specified name). Any other value is
 interpreted as a filename to which messages should be written.
 
+.. note::
+
+    As of Kea 2.6.3, log files may only be written to the output directory
+    determined during compilation as: ``"[kea-install-dir]/var/log/kea"``. This
+    path may be overridden at startup by setting the environment variable
+    ``KEA_LOG_FILE_DIR`` to the desired path.  If a path other than
+    this value is used in ``output``, Kea will emit an error and refuse to start
+    or, if already running, log an unrecoverable error.  For ease of use simply
+    omit the path component from ``output`` and specify only the file name.
+
+
 The ``flush`` (boolean) Option
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index bd92ed672be4b657c6e9bffec782db08b71be04f..6cec3f129710161c38ee508b9383fa0c8a8935a4 100644 (file)
@@ -15,6 +15,8 @@ set -eu
 . "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
 
 export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/admin/tests"
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/admin/tests"
+
 
 # Locations of memfile tools
 kea_admin="@abs_top_builddir@/src/bin/admin/kea-admin"
index ab7e47b23d9e946aa99f7dee7973d8d439902d76..a6c6343aea95622278a43cf8eaf0b733bd221163 100644 (file)
@@ -21,6 +21,9 @@ LOG_FILE="@abs_top_builddir@/src/bin/agent/tests/test.log"
 # Set env KEA_HOOKS_PATH  to override DEFAULT_HOOKS_PATH
 export KEA_HOOKS_PATH="@abs_top_builddir@/src/bin/agent/tests/.libs"
 
+# Set env KEA_LOG_FILE_DIR to override default log path
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/agent/tests"
+
 # Control Agent configuration to be stored in the configuration file.
 CONFIG="{
     \"Control-agent\":
index 8d9fe15c1fa2631a1d4f64de7ebd4fdeeea245e1..88da8c681284078aeac9f0b1760fda3e3f566b36 100644 (file)
@@ -241,7 +241,7 @@ public:
 };
 
 /// @brief Convenience macros for invoking runOrConfig()
-#define RUN_CONFIG_OK(a) (runConfigOrFail(a, NO_ERROR, ""))
+#define RUN_CONFIG_OK(a) (static_cast<void>(runConfigOrFail(a, NO_ERROR, "")))
 #define SYNTAX_ERROR(a,b) ASSERT_TRUE(runConfigOrFail(a,SYNTAX_ERROR,b))
 #define LOGIC_ERROR(a,b) ASSERT_TRUE(runConfigOrFail(a,LOGIC_ERROR,b))
 
index cf9de463a36ceabb24d22a020725b57c1e7a5135..ec119f14b39a4d5e3dcd2094c5a57f69f61a4551 100644 (file)
@@ -17,6 +17,10 @@ LOG_FILE="@abs_top_builddir@/src/bin/d2/tests/test.log"
 # D2 configuration to be stored in the configuration file.
 # Set env KEA_HOOKS_PATH  to override DEFAULT_HOOKS_PATH
 export KEA_HOOKS_PATH="@abs_top_builddir@/src/bin/d2/tests/.libs"
+
+# Set env KEA_LOG_FILE_DIR to override default log path
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/d2/tests"
+
 CONFIG="{
     \"DhcpDdns\":
     {
index c5e3c958109038aa3fd2859404ae31bf160d5896..845544af5d37c2ded4863bc19510075e593d4bf5 100644 (file)
@@ -646,7 +646,7 @@ TEST_F(D2ProcessTest, notLoopbackTest) {
     // Note we don't care nor can we predict if this
     // succeeds or fails. The address and port may or may
     // not be valid on the test host.
-    runWithConfig(config);
+    static_cast<void>(runWithConfig(config));
 }
 
 /// @brief Used to permit visual inspection of logs to ensure
index 187afde3c8197aac0650ed501205aa3c808f6d0a..f4960588effd73ff92058d455b397a63eb0c31ad 100644 (file)
@@ -22,6 +22,7 @@
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <hooks/hooks_manager.h>
 #include <log/logger_support.h>
+#include <process/log_parser.h>
 #include <stats/stats_mgr.h>
 #include <util/multi_threading_mgr.h>
 #include <util/chrono_time_utils.h>
@@ -53,6 +54,7 @@ using namespace isc::hooks;
 using namespace isc::stats;
 using namespace isc::test;
 using namespace isc::util;
+using namespace isc::process;
 namespace ph = std::placeholders;
 
 namespace {
@@ -113,6 +115,7 @@ public:
     ///
     /// Sets socket path to its default value.
     CtrlChannelDhcpv4SrvTest() : interfaces_("\"*\"") {
+        resetLogPath();
         const char* env = getenv("KEA_SOCKET_TEST_DIR");
         if (env) {
             socket_path_ = string(env) + "/kea4.sock";
@@ -127,6 +130,7 @@ public:
 
     /// @brief Destructor
     ~CtrlChannelDhcpv4SrvTest() {
+        resetLogPath();
         LeaseMgrFactory::destroy();
         StatsMgr::instance().removeAll();
 
@@ -144,6 +148,18 @@ public:
         IfaceMgr::instance().detectIfaces();
     }
 
+    /// @brief Sets the log path where log output may be written.
+    /// @param explicit_path path to use as the log path.
+    void setLogTestPath(const std::string explicit_path = "") {
+        LogConfigParser::getLogPath(true, (!explicit_path.empty() ?
+                                           explicit_path : TEST_DATA_BUILDDIR));
+    }
+
+    /// @brief Resets the log path to TEST_DATA_BUILDDIR.
+    void resetLogPath() {
+        LogConfigParser::getLogPath(true);
+    }
+
     /// @brief Returns pointer to the server's IO service.
     ///
     /// @return Pointer to the server's IO service or null pointer if the server
@@ -647,6 +663,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, controlChannelStats) {
 
 // Check that the "config-set" command will replace current configuration
 TEST_F(CtrlChannelDhcpv4SrvTest, configSet) {
+    setLogTestPath("/dev");
     createUnixChannelServer();
 
     // Define strings to permutate the config arguments
@@ -884,6 +901,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, configHashGet) {
 
 // Verify that the "config-test" command will do what we expect.
 TEST_F(CtrlChannelDhcpv4SrvTest, configTest) {
+    setLogTestPath("/dev");
     createUnixChannelServer();
 
     // Define strings to permutate the config arguments
index 987c919630f964f2bc9238ef84834f47e99ee11f..bc4dffa6bccc3034428efb77302fd14b52168cf2 100644 (file)
@@ -23,11 +23,14 @@ export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc"
 HOOK_FAIL_LOAD_PATH="@abs_top_builddir@/src/bin/dhcp4/tests/.libs/libco3.so"
 # Path to test hooks library
 HOOK_FAIL_POLL_PATH="@abs_top_builddir@/src/bin/dhcp4/tests/.libs/libco4.so"
-# Kea configuration to be stored in the configuration file.
 
-# Set env KEA_HOOKS_PATH  to override DEFAULT_HOOKS_PATH
+# Set env KEA_HOOKS_PATH to override DEFAULT_HOOKS_PATH
 export KEA_HOOKS_PATH="@abs_top_builddir@/src/bin/dhcp4/tests/.libs"
 
+# Set env KEA_LOG_FILE_DIR to override default log path.
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/dhcp4/tests"
+
+# Kea configuration to be stored in the configuration file.
 CONFIG="{
     \"Dhcp4\":
     {
index 913885ea63823f0b0bf016bdf0264f84b31b1937..3921dabe88ee4d35e85a8f8624fa820981df0302 100644 (file)
@@ -219,7 +219,7 @@ DirectClientTest::createClientMessage(const Pkt4Ptr& msg,
     // local and remote address are set like it was a message sent from the
     // directly connected client.
     Pkt4Ptr received;
-    createPacketFromBuffer(msg, received);
+    static_cast<void>(createPacketFromBuffer(msg, received));
     received->setIface(iface);
     received->setIndex(ifindex);
     received->setLocalAddr(IOAddress("255.255.255.255"));
index 6e7103bee8b74ce6f082efbbb4f0ccb165a9f39b..87bee8e493c0e0c1401de90f7bf932171a6f627f 100644 (file)
@@ -559,6 +559,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, controlChannelShutdown) {
 
 // Check that the "config-set" command will replace current configuration
 TEST_F(CtrlChannelDhcpv6SrvTest, configSet) {
+    setLogTestPath("/dev");
     createUnixChannelServer();
 
     // Define strings to permutate the config arguments
@@ -797,6 +798,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, configHashGet) {
 
 // Verify that the "config-test" command will do what we expect.
 TEST_F(CtrlChannelDhcpv6SrvTest, configTest) {
+    setLogTestPath("/dev");
     createUnixChannelServer();
 
     // Define strings to permutate the config arguments
index 85b0c927d177ae20fc67eb57c25245461f624902..34d7267334d0f2499a43a9022ce2b548a23aba25 100644 (file)
@@ -23,10 +23,14 @@ export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc"
 HOOK_FAIL_LOAD_PATH="@abs_top_builddir@/src/bin/dhcp6/tests/.libs/libco3.so"
 # Path to test hooks library
 HOOK_FAIL_POLL_PATH="@abs_top_builddir@/src/bin/dhcp6/tests/.libs/libco4.so"
-# Kea configuration to be stored in the configuration file.
-# Set env KEA_HOOKS_PATH  to override DEFAULT_HOOKS_PATH
+
+# Set env KEA_HOOKS_PATH to override DEFAULT_HOOKS_PATH
 export KEA_HOOKS_PATH="@abs_top_builddir@/src/bin/dhcp6/tests/.libs"
 
+# Set env KEA_LOG_FILE_DIR to override default log path
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/dhcp6/tests"
+
+# Kea configuration to be stored in the configuration file.
 CONFIG="{
     \"Dhcp6\":
     {
index ac050770409cab82d8795020d1479bdc9ae144a0..35872e339ea4d8f6ed019b44ca0d413a9911c87c 100644 (file)
@@ -13,6 +13,7 @@
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/json_config_parser.h>
 #include <log/logger_support.h>
+#include <process/log_parser.h>
 #include <stats/stats_mgr.h>
 #include <util/pointer_util.h>
 #include <cstdio>
@@ -24,6 +25,7 @@ using namespace isc::dhcp;
 using namespace isc::asiolink;
 using namespace isc::stats;
 using namespace isc::util;
+using namespace isc::process;
 using namespace boost::posix_time;
 
 namespace isc {
@@ -37,6 +39,7 @@ BaseServerTest::BaseServerTest() {
     CfgMgr::instance().setFamily(AF_INET6);
     original_datadir_ = CfgMgr::instance().getDataDir();
     CfgMgr::instance().getDataDir(true, TEST_DATA_BUILDDIR);
+    resetLogPath();
 }
 
 BaseServerTest::~BaseServerTest() {
@@ -59,6 +62,18 @@ BaseServerTest::~BaseServerTest() {
 
     // Revert to unit test logging, in case the test reconfigured it.
     isc::log::initLogger();
+    resetLogPath();
+}
+
+void
+BaseServerTest::setLogTestPath(const std::string explicit_path /* = "" */) {
+    LogConfigParser::getLogPath(true, (!explicit_path.empty() ?
+                                       explicit_path : TEST_DATA_BUILDDIR));
+}
+
+void
+BaseServerTest::resetLogPath() {
+    LogConfigParser::getLogPath(true);
 }
 
 Dhcpv6SrvTest::Dhcpv6SrvTest()
index fd7a11f474d5b0bd41c342fc8372dafc5ea4455d..938d67ca4816ec28cfb50f9f96fe5a64a209d38b 100644 (file)
@@ -125,6 +125,13 @@ public:
     /// @brief Destructor.
     virtual ~BaseServerTest();
 
+    /// @brief Sets the log path where log output may be written.
+    /// @param explicit_path path to use as the log path.
+    void setLogTestPath(const std::string explicit_path = "");
+
+    /// @brief Resets the log path to TEST_DATA_BUILDDIR.
+    void resetLogPath();
+
 private:
 
     /// @brief Holds the original data directory.
index d8e04296cef7bc60a903b5f8272d50ea848c64a2..604ba0d6d4e5613fa243d0e585503867113b6bd8 100644 (file)
@@ -73,7 +73,7 @@
                 // - syslog (logs to syslog)
                 // - syslog:name (logs to syslog using specified name)
                 // Any other value is considered a name of the file
-                "output": "@localstatedir@/log/kea-ctrl-agent.log"
+                "output": "kea-ctrl-agent.log"
 
                 // Shorter log pattern suitable for use with systemd,
                 // avoids redundant information
index b75b51f390ce7faf49d741c821acb80ae84bc224..0d7f11536e364061a665a324c513dd8cc69a2f62 100644 (file)
@@ -44,7 +44,7 @@
                 // - syslog (logs to syslog)
                 // - syslog:name (logs to syslog using specified name)
                 // Any other value is considered a name of the file
-                "output": "@localstatedir@/log/kea-ddns.log"
+                "output": "kea-ddns.log"
 
                 // Shorter log pattern suitable for use with systemd,
                 // avoids redundant information
index 55af9dbf61e59f73bc02bd4090a74e5bf3a461a9..06070508fc8c99a46aede140b48c4d35e4a5fbe7 100644 (file)
                 // - syslog (logs to syslog)
                 // - syslog:name (logs to syslog using specified name)
                 // Any other value is considered a name of the file
-                "output": "@localstatedir@/log/kea-dhcp4.log"
+                "output": "kea-dhcp4.log"
 
                 // Shorter log pattern suitable for use with systemd,
                 // avoids redundant information
index 271021b2f86375a6533455811dceb774a0bfedde..183866d58b21e4891a25d713963480855ea2c8d7 100644 (file)
                 // - syslog (logs to syslog)
                 // - syslog:name (logs to syslog using specified name)
                 // Any other value is considered a name of the file
-                "output": "@localstatedir@/log/kea-dhcp6.log"
+                "output": "kea-dhcp6.log"
 
                 // Shorter log pattern suitable for use with systemd,
                 // avoids redundant information
index c8a3878b414f27db64e112f8ee720b850aab3b45..bc7b3926f4203891d1eacde4d4d50d4e0bd211be 100644 (file)
@@ -69,7 +69,7 @@
                 // - syslog (logs to syslog)
                 // - syslog:name (logs to syslog using specified name)
                 // Any other value is considered a name of a time
-                "output": "@localstatedir@/log/kea-netconf.log"
+                "output": "kea-netconf.log"
 
                 // Shorter log pattern suitable for use with systemd,
                 // avoids redundant information
index 6c7c17b47b429ab5de572b3747311d25f2611673..f35e34c18922627b64d4c7ca75d1d9604ca53e21 100644 (file)
@@ -59,6 +59,10 @@ KEACTRL_BUILD_DIR="@abs_top_builddir@"
 KEACTRL_CFG_FILE="@abs_top_builddir@/src/bin/keactrl/tests/keactrl_test.conf"
 # Path to the Kea log file.
 LOG_FILE="@abs_top_builddir@/src/bin/keactrl/tests/test.log"
+
+# Set env KEA_LOG_FILE_DIR to override default log path
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/keactrl/tests"
+
 # Binaries' names
 wildcard_name="kea-"
 kea4_name="${wildcard_name}dhcp4"
index 5432b259dfe5b6a3b845b03a7a21930c2f1feac5..3e956c330c2d6fde56bf9b4d7f7471738ad418a6 100644 (file)
@@ -13,6 +13,7 @@ set -eu
 # Path to the temporary configuration file.
 CFG_FILE="@abs_top_builddir@/src/bin/netconf/tests/shtests/test_config.json"
 # Path to the Kea log file.
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/netconf/tests/shtests"
 LOG_FILE="@abs_top_builddir@/src/bin/netconf/tests/shtests/test.log"
 
 # Kea-netconf configuration to be stored in the configuration file.
index f25a2cc86243e40978e8c548e4fde9feadb115b8..43a27ae20318d26a9fc671590147bbbc4a36f3b8 100644 (file)
@@ -19,6 +19,9 @@ CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
 # Path to the Control Agent log file.
 LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
 
+# Set env KEA_LOG_FILE_DIR to override default log path.
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/shell/tests"
+
 # Control Agent configuration to be stored in the configuration file.
 # todo: use actual configuration once we support it.
 CONFIG="{
index 3ed4071fb1b7f8a86b714fab3fb7ce8d09076885..968983fc3dde690a8b9560344bc13b6e77b8a66f 100644 (file)
@@ -19,6 +19,9 @@ CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
 # Path to the Control Agent log file.
 LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
 
+# Set env KEA_LOG_FILE_DIR to override default log path.
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/shell/tests"
+
 # Control Agent configuration to be stored in the configuration file.
 # todo: use actual configuration once we support it.
 CONFIG="{
index 94d608f48eab9fe0e9bdee12340888dcbdd53c46..0e4e51cc4c9a735e0a01f17f7d0c61e2cd73d211 100644 (file)
@@ -15,10 +15,13 @@ set -eu
 . "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
 
 # Path to the temporary configuration file.
-CFG_FILE="@abs_top_builddir@/src/bin/agent/tests/test_config.json"
+CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
 
 # Path to the Control Agent log file.
-LOG_FILE="@abs_top_builddir@/src/bin/agent/tests/test.log"
+LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
+
+# Set env KEA_LOG_FILE_DIR to override default log path.
+export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/shell/tests"
 
 # Path to the test certificate authority directory.
 TEST_CA_DIR="@abs_top_srcdir@/src/lib/asiolink/testutils/ca"
index b0baf990796443c544ac231c7c5f762f3ec0152c..86f31f85dc9c7018963456eb5e385dfa70b4f33d 100644 (file)
@@ -2674,9 +2674,12 @@ LeaseCmdsImpl::leaseWriteHandler(CalloutHandle& handle) {
         if (file->getType() != Element::string) {
             isc_throw(BadValue, "'filename' parameter must be a string");
         }
-        string filename = file->stringValue();
-        if (filename.empty()) {
-            isc_throw(BadValue, "'filename' parameter is empty");
+
+        std::string filename;
+        try {
+          filename = CfgMgr::instance().validatePath(file->stringValue());
+        } catch (const std::exception& ex) {
+            isc_throw(BadValue, "'filename' parameter is invalid: " << ex.what());
         }
 
         if (v4) {
@@ -2684,6 +2687,7 @@ LeaseCmdsImpl::leaseWriteHandler(CalloutHandle& handle) {
         } else {
             LeaseMgrFactory::instance().writeLeases6(filename);
         }
+
         ostringstream s;
         s << (v4 ? "IPv4" : "IPv6")
           << " lease database into '"
index 9416e34d45e1a02dcacb04c156d7b0531320cbc7..825390e16310ea29c00de4d69618f4b3138827da 100644 (file)
@@ -3429,8 +3429,23 @@ void Lease4CmdsTest::testLease4Write() {
         "        \"filename\": \"\"\n"
         "    }\n"
         "}";
-    exp_rsp = "'filename' parameter is empty";
+    exp_rsp = "'filename' parameter is invalid: path: '' has no filename";
     testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Filename must use supported path.
+    txt =
+        "{\n"
+        "    \"command\": \"lease4-write\",\n"
+        "    \"arguments\": {"
+        "        \"filename\": \"/tmp/myleases.txt\"\n"
+        "    }\n"
+        "}";
+
+    std::ostringstream os;
+    os << "'filename' parameter is invalid: invalid path specified:"
+       << " '/tmp', supported path is '" << CfgMgr::instance().getDataDir() << "'";
+
+    testCommand(txt, CONTROL_RESULT_ERROR, os.str());
 }
 
 TEST_F(Lease4CmdsTest, lease4AddMissingParams) {
index 65cdda2275205553e0465c8acaab635db75d5dff..2fb2d796a254bf2e3e34866ab25014da17fff98c 100644 (file)
@@ -4129,7 +4129,7 @@ void Lease6CmdsTest::testLease6ConflictingBulkApplyAdd() {
 }
 
 void Lease6CmdsTest::testLease6Write() {
-    // lease4-write negative tests. Positive tests are in the
+    // lease6-write negative tests. Positive tests are in the
     // memfile_lease_mgr_unittest.cc file.
 
     // Initialize lease manager (true = v6, false = don't add leases)
@@ -4164,8 +4164,21 @@ void Lease6CmdsTest::testLease6Write() {
         "        \"filename\": \"\"\n"
         "    }\n"
         "}";
-    exp_rsp = "'filename' parameter is empty";
+    exp_rsp = "'filename' parameter is invalid: path: '' has no filename";
     testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Filename must use supported path.
+    txt =
+        "{\n"
+        "    \"command\": \"lease6-write\",\n"
+        "    \"arguments\": {"
+        "        \"filename\": \"/tmp/myleases.txt\"\n"
+        "    }\n"
+        "}";
+
+    std::ostringstream os;
+    os << "'filename' parameter is invalid: invalid path specified:"
+       << " '/tmp', supported path is '" << CfgMgr::instance().getDataDir() << "'";
 }
 
 TEST_F(Lease6CmdsTest, lease6AddMissingParams) {
index fc7e36270daf9e8bf464722611ccd31da0deb47b..df251286a8994b3fb1f022e7dc6b0d89776246a8 100644 (file)
@@ -3,6 +3,8 @@ SUBDIRS = cfgrpt . testutils tests
 dhcp_data_dir = @runstatedir@/@PACKAGE@
 AM_CPPFLAGS  = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += -DDATA_DIR="\"$(dhcp_data_dir)\""
+log_file_dir = @localstatedir@/log/@PACKAGE@
+AM_CPPFLAGS += -DLOGFILE_DIR="\"$(log_file_dir)\""
 
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CXXFLAGS  = $(KEA_CXXFLAGS)
index 413e8444c1d7bd67d62d995bab237a94c75a1d31..f052730cfc0a93b82b81dc0319809cb9282e5242 100644 (file)
 #include <log/logger_support.h>
 #include <log/logger_manager.h>
 #include <log/logger_name.h>
+#include <util/filesystem.h>
 
 using namespace isc::data;
 using namespace isc::log;
+using namespace isc::util::file;
 
 namespace isc {
 namespace process {
 
+namespace {
+    // Singleton PathChecker to set and hold valid log file path.
+    PathCheckerPtr log_path_checker_;
+};
+
 LogConfigParser::LogConfigParser(const ConfigPtr& storage)
     :config_(storage), verbose_(false) {
     if (!storage) {
@@ -126,6 +133,28 @@ void LogConfigParser::parseConfigEntry(isc::data::ConstElementPtr entry) {
     config_->addLoggingInfo(info);
 }
 
+std::string
+LogConfigParser::getLogPath(bool reset /* = false */, const std::string explicit_path /* = "" */) {
+    if (!log_path_checker_ || reset) {
+        log_path_checker_.reset(new PathChecker(LOGFILE_DIR, "KEA_LOG_FILE_DIR"));
+        if (!explicit_path.empty()) {
+            log_path_checker_->getPath(true, explicit_path);
+        }
+    }
+
+    return (log_path_checker_->getPath());
+}
+
+std::string
+LogConfigParser::validatePath(const std::string logpath,
+                                   bool enforce_path /* = true */) {
+    if (!log_path_checker_) {
+        getLogPath();
+    }
+
+    return (log_path_checker_->validatePath(logpath, enforce_path));
+}
+
 void LogConfigParser::parseOutputOptions(std::vector<LoggingDestination>& destination,
                                          isc::data::ConstElementPtr output_options) {
     if (!output_options) {
@@ -141,7 +170,20 @@ void LogConfigParser::parseOutputOptions(std::vector<LoggingDestination>& destin
             isc_throw(BadValue, "output-options entry does not have a mandatory 'output' "
                       "element (" << output_option->getPosition() << ")");
         }
-        dest.output_ = output->stringValue();
+
+        auto output_str = output->stringValue();
+        if ((output_str == "stdout") ||
+            (output_str == "stderr") ||
+            (output_str == "syslog")) {
+            dest.output_ = output_str;
+        } else {
+            try {
+                dest.output_ = validatePath(output_str);
+            } catch (const std::exception& ex) {
+                isc_throw(BadValue, "invalid path in `output`: " << ex.what()
+                          << " (" << output_option->getPosition() << ")");
+            }
+        }
 
         isc::data::ConstElementPtr maxver_ptr = output_option->get("maxver");
         if (maxver_ptr) {
index bfb80d0ddc2ae8e311527d073f890fd4596b0289..cf3a7f2c246bd76547b8174528d6cdbe27d5d123 100644 (file)
@@ -58,6 +58,29 @@ public:
     void parseConfiguration(const isc::data::ConstElementPtr& log_config,
                             bool verbose = false);
 
+    /// @brief Fetches the supported log file path.
+    ///
+    /// The first call to this function with no arguments will set the default
+    /// hooks path to either the value of LOGFILE_DIR or the environment
+    /// variable KEA_LOG_FILE_DIR if it is defined. Subsequent calls with no
+    /// arguments will simply return this value.
+    ///
+    /// @param reset recalculate when true, defaults to false.
+    /// @param explicit_path set default log path to this value. This is
+    /// for testing purposes only.
+    ///
+    /// @return String containing the default log file path.
+    static std::string getLogPath(bool reset = false, const std::string explicit_path = "");
+
+    /// @brief Validates a library path against the supported path for log files.
+    ///
+    /// @param logpath path to validate.
+    /// @param enforce_path enables validation against the supported path.
+    /// If false verifies only that the path contains a file name.
+    ///
+    /// @return validated path
+    static std::string validatePath(const std::string logpath, bool enforce_path = true);
+
 private:
 
     /// @brief Parses one JSON structure in Server/loggers" array
index 7cfa746a857999d43aecc9e129f366e454a81980..676abb27dbacd6b6708c90512359c173c02b52e2 100644 (file)
@@ -260,7 +260,7 @@ TEST_F(DStubCfgMgrTest, simpleParseConfig) {
     string config = "{ \"bool_test\": true , \n"
                     "  \"uint32_test\": 77 , \n"
                     "  \"string_test\": \"hmmm chewy\" }";
-    ASSERT_NO_THROW(fromJSON(config));
+    ASSERT_NO_THROW(static_cast<void>(fromJSON(config)));
 
     answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
     EXPECT_TRUE(checkAnswer(0));
@@ -272,7 +272,7 @@ TEST_F(DStubCfgMgrTest, simpleParseConfigWithCallback) {
     string config = "{ \"bool_test\": true , \n"
                     "  \"uint32_test\": 77 , \n"
                     "  \"string_test\": \"hmmm chewy\" }";
-    ASSERT_NO_THROW(fromJSON(config));
+    ASSERT_NO_THROW(static_cast<void>(fromJSON(config)));
 
     answer_ = cfg_mgr_->simpleParseConfig(config_set_, false,
                                           []() {
index 2a6970c664360e8301babfb71d563d3c832565ae..b833ed9642b91dbfcbbf6570556b802f598fa772 100644 (file)
@@ -32,7 +32,9 @@ namespace {
 class LoggingTest : public ::testing::Test {
     public:
         /// @brief Constructor
-        LoggingTest() {}
+        LoggingTest() {
+            resetLogPath();
+        }
 
         /// @brief Destructor
         ///
@@ -40,6 +42,7 @@ class LoggingTest : public ::testing::Test {
         ~LoggingTest() {
             isc::log::initLogger();
             wipeFiles();
+            resetLogPath();
         }
 
     /// @brief Generates a log file name suffixed with a rotation number
@@ -63,6 +66,19 @@ class LoggingTest : public ::testing::Test {
         static_cast<void>(remove(os.str().c_str()));
     }
 
+    /// @brief Sets the Hooks path from which hooks can be loaded.
+    /// @param explicit_path path to use as the hooks path.
+    void setLogTestPath(const std::string explicit_path = "") {
+        LogConfigParser::getLogPath(true,
+                                     (!explicit_path.empty() ?
+                                      explicit_path : TEST_DATA_BUILDDIR));
+    }
+
+    /// @brief Resets the log path to default.
+    void resetLogPath() {
+        LogConfigParser::getLogPath(true);
+    }
+
     /// @brief Name of the log file
     static const char* TEST_LOG_NAME;
 
@@ -309,7 +325,8 @@ TEST_F(LoggingTest, parsingFile) {
     EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
 
     ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
-    EXPECT_EQ("logfile.txt" , storage->getLoggingInfo()[0].destinations_[0].output_);
+    EXPECT_EQ(LogConfigParser::validatePath("logfile.txt"),
+              storage->getLoggingInfo()[0].destinations_[0].output_);
     // Default for immediate flush is true
     EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].flush_);
 
@@ -365,14 +382,15 @@ TEST_F(LoggingTest, multipleLoggers) {
     EXPECT_EQ(0, storage->getLoggingInfo()[0].debuglevel_);
     EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
     ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
-    EXPECT_EQ("logfile.txt" , storage->getLoggingInfo()[0].destinations_[0].output_);
+    EXPECT_EQ(LogConfigParser::validatePath("logfile.txt"),
+              storage->getLoggingInfo()[0].destinations_[0].output_);
     EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].flush_);
-
     EXPECT_EQ("wombat", storage->getLoggingInfo()[1].name_);
     EXPECT_EQ(99, storage->getLoggingInfo()[1].debuglevel_);
     EXPECT_EQ(isc::log::DEBUG, storage->getLoggingInfo()[1].severity_);
     ASSERT_EQ(1, storage->getLoggingInfo()[1].destinations_.size());
-    EXPECT_EQ("logfile2.txt" , storage->getLoggingInfo()[1].destinations_[0].output_);
+    EXPECT_EQ(LogConfigParser::validatePath("logfile2.txt"),
+              storage->getLoggingInfo()[1].destinations_[0].output_);
     EXPECT_FALSE(storage->getLoggingInfo()[1].destinations_[0].flush_);
 }
 
@@ -380,7 +398,7 @@ TEST_F(LoggingTest, multipleLoggers) {
 // into Configuration usable by log4cplus. This test checks that more than
 // one logging destination can be configured.
 TEST_F(LoggingTest, multipleLoggingDestinations) {
-
+    setLogTestPath();
     const char* config_txt =
     "{ \"loggers\": ["
     "    {"
@@ -415,7 +433,8 @@ TEST_F(LoggingTest, multipleLoggingDestinations) {
     EXPECT_EQ(0, storage->getLoggingInfo()[0].debuglevel_);
     EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
     ASSERT_EQ(2, storage->getLoggingInfo()[0].destinations_.size());
-    EXPECT_EQ("logfile.txt" , storage->getLoggingInfo()[0].destinations_[0].output_);
+    EXPECT_EQ(LogConfigParser::validatePath("logfile.txt"),
+              storage->getLoggingInfo()[0].destinations_[0].output_);
     EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].flush_);
     EXPECT_EQ("stdout" , storage->getLoggingInfo()[0].destinations_[1].output_);
     EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[1].flush_);
@@ -427,6 +446,7 @@ TEST_F(LoggingTest, multipleLoggingDestinations) {
 // we can correctly configure logging such that rotation occurs as
 // expected.
 TEST_F(LoggingTest, logRotate) {
+    setLogTestPath();
     wipeFiles();
 
     std::ostringstream os;
@@ -467,7 +487,7 @@ TEST_F(LoggingTest, logRotate) {
     EXPECT_EQ(TEST_MAX_VERS, server_cfg->getLoggingInfo()[0].destinations_[0].maxver_);
 
     // Make sure we have the initial log file.
-    ASSERT_TRUE(isc::test::fileExists(TEST_LOG_NAME));
+    ASSERT_TRUE(isc::test::fileExists(LogConfigParser::validatePath(TEST_LOG_NAME)));
 
     // Now generate a log we know will be large enough to force a rotation.
     // We borrow a one argument log message for the test.
@@ -477,7 +497,7 @@ TEST_F(LoggingTest, logRotate) {
     for (int i = 1; i < TEST_MAX_VERS + 1; i++) {
         // Output the big log and make sure we get the expected rotation file.
         LOG_INFO(logger, DCTL_CONFIG_COMPLETE).arg(big_arg);
-        EXPECT_TRUE(isc::test::fileExists(logName(i).c_str()));
+        EXPECT_TRUE(isc::test::fileExists(LogConfigParser::validatePath(logName(i).c_str())));
     }
 
     // Clean up.
@@ -604,6 +624,7 @@ void testMaxSize(uint64_t maxsize_candidate, uint64_t expected_maxsize) {
 
 // Test that maxsize can be configured with high values.
 TEST_F(LoggingTest, maxsize) {
+    setLogTestPath();
     testMaxSize(TEST_MAX_SIZE, TEST_MAX_SIZE);
     testMaxSize(std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
     testMaxSize(std::numeric_limits<uint32_t>::max(), std::numeric_limits<uint32_t>::max());
index d8e1cffd1871b4d5833aa0668b34d60a94bb1d38..495091dad29d8e5e3b3f92ee885e5746d2bc5904 100644 (file)
@@ -248,7 +248,7 @@ PathChecker::validatePath(const std::string input_path_str,
     auto filename = input_path.filename();
     if (filename.empty()) {
         isc_throw(BadValue, "path: '" << input_path.str() << "' has no filename");
-     }
+    }
 
     auto parent_path = input_path.parentPath();
     if (!parent_path.empty()) {