Parcourir la source

[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.
Shawn Routhier il y a 10 ans
Parent
commit
06b3c5041e

+ 15 - 3
src/bin/lfc/kea-lfc.xml

@@ -46,7 +46,8 @@
       <command>kea-lfc</command>
       <arg><option>-4|-6</option></arg>
       <arg><option>-c <replaceable class="parameter">config-file</replaceable></option></arg>
-      <arg><option>-p <replaceable class="parameter">previous-file</replaceable></option></arg>
+      <arg><option>-p <replaceable class="parameter">pid-file</replaceable></option></arg>
+      <arg><option>-x <replaceable class="parameter">previous-file</replaceable></option></arg>
       <arg><option>-i <replaceable class="parameter">copy-file</replaceable></option></arg>
       <arg><option>-o <replaceable class="parameter">output-file</replaceable></option></arg>
       <arg><option>-f <replaceable class="parameter">finish-file</replaceable></option></arg>
@@ -117,7 +118,7 @@
           Configuration file including the configuration for
           <command>kea-lfc</command> process.  It may also
           contain configuration entries for other Kea services.
-          Currently <command>kea-lfc</command> gets all of its arguments from 
+          Currently <command>kea-lfc</command> gets all of its arguments from
           the comamnd line, in the future it will be extended to get some arguments
           from the config file.
         </para></listitem>
@@ -126,7 +127,18 @@
       <varlistentry>
         <term><option>-p</option></term>
         <listitem><para>
-          Previous lease file - When <command>kea-lfc</command> starts this
+          PID file - When the <command>kea-lfc</command> 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.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-x</option></term>
+        <listitem><para>
+          Previous or ex lease file - When <command>kea-lfc</command> starts this
           is the result of any previous run of <command>kea-lfc</command>.
           When <command>kea-lfc</command> finishes it is the result of this run.
           If <command>kea-lfc</command> is interrupted before compelting

+ 60 - 19
src/bin/lfc/lfc_controller.cc

@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <lfc/lfc_controller.h>
+#include <util/pid_file.h>
 #include <exceptions/exceptions.h>
 #include <config.h>
 #include <iostream>
@@ -21,6 +22,7 @@
 #include <stdlib.h>
 
 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 <file>: previous lease file" << std::endl
+              << "   -p <file>: PID file" << std::endl
+              << "   -x <file>: previous or ex lease file" << std::endl
               << "   -i <file>: copy of lease file" << std::endl
               << "   -o <file>: output lease file" << std::endl
               << "   -f <file>: finish file" << std::endl

+ 4 - 4
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 {

+ 15 - 8
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<char*>("progName"),
                      const_cast<char*>("-4"),
-                     const_cast<char*>("-p"),
+                     const_cast<char*>("-x"),
                      const_cast<char*>("previous"),
                      const_cast<char*>("-i"),
                      const_cast<char*>("copy"),
@@ -54,8 +54,10 @@ TEST(LFCControllerTest, fullCommandLine) {
                      const_cast<char*>("-c"),
                      const_cast<char*>("config"),
                      const_cast<char*>("-f"),
-                     const_cast<char*>("finish") };
-    int argc = 12;
+                     const_cast<char*>("finish"),
+                     const_cast<char*>("-p"),
+                     const_cast<char*>("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<char*>("progName"),
                      const_cast<char*>("-4"),
-                     const_cast<char*>("-p"),
+                     const_cast<char*>("-x"),
                      const_cast<char*>("previous"),
                      const_cast<char*>("-i"),
                      const_cast<char*>("copy"),
@@ -89,11 +92,13 @@ TEST(LFCControllerTest, notEnoughData) {
                      const_cast<char*>("-c"),
                      const_cast<char*>("config"),
                      const_cast<char*>("-f"),
-                     const_cast<char*>("finish") };
+                     const_cast<char*>("finish"),
+                     const_cast<char*>("-p"),
+                     const_cast<char*>("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<char*>("progName"),
                      const_cast<char*>("-4"),
-                     const_cast<char*>("-p"),
+                     const_cast<char*>("-x"),
                      const_cast<char*>("previous"),
                      const_cast<char*>("-i"),
                      const_cast<char*>("copy"),
@@ -124,11 +129,13 @@ TEST(LFCControllerTest, tooMuchData) {
                      const_cast<char*>("config"),
                      const_cast<char*>("-f"),
                      const_cast<char*>("finish"),
+                     const_cast<char*>("-p"),
+                     const_cast<char*>("pid"),
                      const_cast<char*>("some"),
                      const_cast<char*>("other"),
                      const_cast<char*>("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);