From 06b3c5041ee6884427decde39c83984ea13e0932 Mon Sep 17 00:00:00 2001 From: Shawn Routhier Date: Mon, 26 Jan 2015 20:34:10 -0800 Subject: [PATCH] [trac3687] Add PIDFile class to manage PID files Add the PIDFile class to manage PID files (check, write, delete) Update the LFC code to use the PIDFile class to run only a single instance at a time. --- src/bin/lfc/kea-lfc.xml | 18 ++++- src/bin/lfc/lfc_controller.cc | 79 ++++++++++++++----- src/bin/lfc/lfc_controller.h | 8 +- src/bin/lfc/tests/lfc_controller_unittests.cc | 23 ++++-- 4 files changed, 94 insertions(+), 34 deletions(-) diff --git a/src/bin/lfc/kea-lfc.xml b/src/bin/lfc/kea-lfc.xml index d7cb9bb274..119efca163 100644 --- a/src/bin/lfc/kea-lfc.xml +++ b/src/bin/lfc/kea-lfc.xml @@ -46,7 +46,8 @@ kea-lfc - + + @@ -117,7 +118,7 @@ Configuration file including the configuration for kea-lfc process. It may also contain configuration entries for other Kea services. - Currently kea-lfc gets all of its arguments from + Currently kea-lfc gets all of its arguments from the comamnd line, in the future it will be extended to get some arguments from the config file. @@ -126,7 +127,18 @@ - Previous lease file - When kea-lfc starts this + PID file - When the kea-lfc process starts + it attempts to determine if another instance of the process is + already running by examining the pid file. If one is running + it aborts the new process. If one isn't running it writes its + pid into the pid file. + + + + + + + Previous or ex lease file - When kea-lfc starts this is the result of any previous run of kea-lfc. When kea-lfc finishes it is the result of this run. If kea-lfc is interrupted before compelting diff --git a/src/bin/lfc/lfc_controller.cc b/src/bin/lfc/lfc_controller.cc index eb1a3ac64d..ae908e63bf 100644 --- a/src/bin/lfc/lfc_controller.cc +++ b/src/bin/lfc/lfc_controller.cc @@ -13,6 +13,7 @@ // PERFORMANCE OF THIS SOFTWARE. #include +#include #include #include #include @@ -21,6 +22,7 @@ #include using namespace std; +using namespace isc::util; namespace isc { namespace lfc { @@ -42,12 +44,38 @@ LFCController::~LFCController() { void LFCController::launch(int argc, char* argv[]) { - try { - parseArgs(argc, argv); - } catch (const InvalidUsage& ex) { - usage(ex.what()); - throw; // rethrow it - } + try { + parseArgs(argc, argv); + } catch (const InvalidUsage& ex) { + usage(ex.what()); + throw; // rethrow it + } + + std::cerr << "Starting lease file cleanup" << std::endl; + + // verify we are the only instance + PIDFile pid_file(pid_file_); + if (pid_file.check() == true) { + // Already running instance, bail out + std::cerr << "LFC instance already running" << std::endl; + return; + } + + // create the pid file for this instance + try { + pid_file.write(); + } catch (const PIDFileError& pid_ex) { + std::cerr << pid_ex.what() << std::endl; + return; + } + + // do other work (TBD) + std::cerr << "Add code to perform lease cleanup" << std::endl; + + // delete the pid file for this instance + pid_file.deleteFile(); + + std::cerr << "LFC complete" << std::endl; } void @@ -56,7 +84,7 @@ LFCController::parseArgs(int argc, char* argv[]) { opterr = 0; optind = 1; - while ((ch = getopt(argc, argv, ":46dvVp:i:o:c:f:")) != -1) { + while ((ch = getopt(argc, argv, ":46dvVp:x:i:o:c:f:")) != -1) { switch (ch) { case '4': // Process DHCPv4 lease files. @@ -84,9 +112,17 @@ LFCController::parseArgs(int argc, char* argv[]) { break; case 'p': - // Previous file name. + // PID file name. + if (optarg == NULL) { + isc_throw(InvalidUsage, "PID file name missing"); + } + pid_file_ = optarg; + break; + + case 'x': + // Previous (or ex) file name. if (optarg == NULL) { - isc_throw(InvalidUsage, "Previous file name missing"); + isc_throw(InvalidUsage, "Previous (ex) file name missing"); } previous_file_ = optarg; break; @@ -108,7 +144,7 @@ LFCController::parseArgs(int argc, char* argv[]) { break; case 'f': - // Output file name. + // Finish file name. if (optarg == NULL) { isc_throw(InvalidUsage, "Finish file name missing"); } @@ -116,7 +152,7 @@ LFCController::parseArgs(int argc, char* argv[]) { break; case 'c': - // Previous file name. + // Configuration file name if (optarg == NULL) { isc_throw(InvalidUsage, "Configuration file name missing"); } @@ -151,6 +187,10 @@ LFCController::parseArgs(int argc, char* argv[]) { isc_throw(InvalidUsage, "DHCP version required"); } + if (pid_file_.empty()) { + isc_throw(InvalidUsage, "PID file not specified"); + } + if (previous_file_.empty()) { isc_throw(InvalidUsage, "Previous file not specified"); } @@ -174,12 +214,12 @@ LFCController::parseArgs(int argc, char* argv[]) { // If verbose is set echo the input information if (verbose_ == true) { std::cerr << "Protocol version: DHCPv" << protocol_version_ << std::endl - << "Previous lease file: " << previous_file_ << std::endl - << "Copy lease file: " << copy_file_ << std::endl - << "Output lease file: " << output_file_ << std::endl - << "Finishn file: " << finish_file_ << std::endl - << "Config file: " << config_file_ << std::endl - << "PID file: " << pid_file_ << std::endl; + << "Previous or ex lease file: " << previous_file_ << std::endl + << "Copy lease file: " << copy_file_ << std::endl + << "Output lease file: " << output_file_ << std::endl + << "Finishn file: " << finish_file_ << std::endl + << "Config file: " << config_file_ << std::endl + << "PID file: " << pid_file_ << std::endl; } } @@ -190,9 +230,10 @@ LFCController::usage(const std::string& text) { } std::cerr << "Usage: " << lfc_bin_name_ << std::endl - << " [-4|-6] -p file -i file -o file -f file -c file" << std::endl + << " [-4|-6] -p file -x file -i file -o file -f file -c file" << std::endl << " -4 or -6 clean a set of v4 or v6 lease files" << std::endl - << " -p : previous lease file" << std::endl + << " -p : PID file" << std::endl + << " -x : previous or ex lease file" << std::endl << " -i : copy of lease file" << std::endl << " -o : output lease file" << std::endl << " -f : finish file" << std::endl diff --git a/src/bin/lfc/lfc_controller.h b/src/bin/lfc/lfc_controller.h index 84f42d7f9f..d7fed8fcd8 100644 --- a/src/bin/lfc/lfc_controller.h +++ b/src/bin/lfc/lfc_controller.h @@ -59,10 +59,10 @@ public: /// of the process. Provides the control logic: /// /// -# parse command line arguments - /// -# verifies that it is the only instance - /// -# creates pid file (TBD) + /// -# verify that it is the only instance + /// -# create pid file /// -# .... TBD - /// -# remove pid file (TBD) + /// -# remove pid file /// -# exit to the caller /// /// @param argc Number of strings in the @c argv array. @@ -111,7 +111,7 @@ public: return (config_file_); } - /// @brief Gets the prevous file name + /// @brief Gets the previous file name /// /// @return Returns the path to the previous file std::string getPreviousFile() const { diff --git a/src/bin/lfc/tests/lfc_controller_unittests.cc b/src/bin/lfc/tests/lfc_controller_unittests.cc index 163a1606b0..16814cd6d4 100644 --- a/src/bin/lfc/tests/lfc_controller_unittests.cc +++ b/src/bin/lfc/tests/lfc_controller_unittests.cc @@ -45,7 +45,7 @@ TEST(LFCControllerTest, fullCommandLine) { // Verify that standard options can be parsed without error char* argv[] = { const_cast("progName"), const_cast("-4"), - const_cast("-p"), + const_cast("-x"), const_cast("previous"), const_cast("-i"), const_cast("copy"), @@ -54,8 +54,10 @@ TEST(LFCControllerTest, fullCommandLine) { const_cast("-c"), const_cast("config"), const_cast("-f"), - const_cast("finish") }; - int argc = 12; + const_cast("finish"), + const_cast("-p"), + const_cast("pid") }; + int argc = 14; ASSERT_NO_THROW(lfc_controller.parseArgs(argc, argv)); @@ -66,6 +68,7 @@ TEST(LFCControllerTest, fullCommandLine) { EXPECT_EQ(lfc_controller.getCopyFile(), "copy"); EXPECT_EQ(lfc_controller.getOutputFile(), "output"); EXPECT_EQ(lfc_controller.getFinishFile(), "finish"); + EXPECT_EQ(lfc_controller.getPidFile(), "pid"); } /// @brief Verify that parsing a correct but incomplete line fails. @@ -80,7 +83,7 @@ TEST(LFCControllerTest, notEnoughData) { // to the parse routine via the argc variable. char* argv[] = { const_cast("progName"), const_cast("-4"), - const_cast("-p"), + const_cast("-x"), const_cast("previous"), const_cast("-i"), const_cast("copy"), @@ -89,11 +92,13 @@ TEST(LFCControllerTest, notEnoughData) { const_cast("-c"), const_cast("config"), const_cast("-f"), - const_cast("finish") }; + const_cast("finish"), + const_cast("-p"), + const_cast("pid") }; int argc = 1; - for (; argc < 12; ++argc) { + for (; argc < 14; ++argc) { EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage) << "test failed for argc = " << argc; } @@ -114,7 +119,7 @@ TEST(LFCControllerTest, tooMuchData) { char* argv[] = { const_cast("progName"), const_cast("-4"), - const_cast("-p"), + const_cast("-x"), const_cast("previous"), const_cast("-i"), const_cast("copy"), @@ -124,11 +129,13 @@ TEST(LFCControllerTest, tooMuchData) { const_cast("config"), const_cast("-f"), const_cast("finish"), + const_cast("-p"), + const_cast("pid"), const_cast("some"), const_cast("other"), const_cast("args"), }; - int argc = 15; + int argc = 17; // We expect an error as we have arguments that aren't valid EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage); -- 2.47.3