Browse Source

[master] keactrl now uses server PID files

Merge branch 'trac3939'
Thomas Markwalder 9 years ago
parent
commit
93a720ed7f
3 changed files with 164 additions and 50 deletions
  1. 13 8
      doc/devel/qa.dox
  2. 44 6
      doc/guide/keactrl.xml
  3. 107 36
      src/bin/keactrl/keactrl.in

+ 13 - 8
doc/devel/qa.dox

@@ -48,14 +48,6 @@ make check
 
 The following environment variable can affect unit-tests:
 
-- KEA_SOCKET_TEST_DIR - if set, it specifies the directory where Unix
-  sockets are created. There's OS limitation on how long a Unix socket
-  path can be. It is typcially slightly over 100 characters. If you
-  happen to build and run unit-tests in deeply nested directories, this
-  may become a problem. KEA_SOCKET_TEST_DIR can be specified to instruct
-  unit-test to use a different directory. Must not end with slash (e.g.
-  /tmp).
-
 - KEA_LOCKFILE_DIR - Specifies a directory where the logging system should
   create its lock file. If not specified, it is prefix/var/run/kea, where prefix
   defaults to /usr/local. This variable must not end with a slash. There is one
@@ -68,4 +60,17 @@ The following environment variable can affect unit-tests:
   stdout, stderr and syslog. Any other value is interpreted as a filename.
   Also see Kea User's Guide, section 15.3.
 
+- KEA_PIDFILE_DIR - Specifies the directory which should be used for PID files
+  as used by dhcp::Daemon or its derivatives. If not specified, the default is
+  prefix/var/run/kea, where prefix defaults to /usr/local. This variable must
+  not end with a slash.
+
+- KEA_SOCKET_TEST_DIR - if set, it specifies the directory where Unix
+  sockets are created. There's OS limitation on how long a Unix socket
+  path can be. It is typcially slightly over 100 characters. If you
+  happen to build and run unit-tests in deeply nested directories, this
+  may become a problem. KEA_SOCKET_TEST_DIR can be specified to instruct
+  unit-test to use a different directory. Must not end with slash (e.g.
+  /tmp).
+
  */

+ 44 - 6
doc/guide/keactrl.xml

@@ -157,21 +157,48 @@ kea_verbose=no
       the servers looks similar to the following:
 <screen>
 <userinput>$ keactrl start</userinput>
-INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea.conf
-INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea.conf
-INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea.conf
+INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea.conf -d
+INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea.conf -d
+INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea.conf -d
 </screen>
       </para>
 
+      <para>Kea's servers create PID files upon startup. These files are used
+      by keactrl to deteremine whether or not a given server is running.  If
+      one or more servers are running when the start command is issued, the
+      output will look similiar to the following:
+<screen>
+<userinput>$ keactrl start</userinput>
+INFO/keactrl: kea-dhcp4 appears to be running, see: PID 10918, PID file: /usr/local/var/kea/kea.kea-dhcp4.pid.
+INFO/keactrl: kea-dhcp6 appears to be running, see: PID 10924, PID file: /usr/local/var/kea/kea.kea-dhcp6.pid.
+INFO/keactrl: kea-dhcp-ddns appears to be running, see: PID 10930, PID file: /usr/local/var/kea/kea.kea-dhcp-ddns.pid.
+</screen>
+      During normal shutdowns these PID files are deleted. They may, however,
+      be left over as remnants following a system crash.  It is possible,
+      though highly unlikely, that upon system restart the PIDs they contain
+      actually refer to processes unrelated to Kea.  This condition will cause
+      keactrl to decide that the servers are running, when in fact they are
+      not.  In such a case the PID files as listed in the keactrl output
+      must be manually deleted.
+      </para>
+
       <para>The following command stops all servers:
 <screen>
 <userinput>$ keactrl stop</userinput>
-INFO/keactrl: Skip sending signal 15 to process kea-dhcp6: process is not running
+INFO/keactrl: Stopping kea-dhcp4...
+INFO/keactrl: Stopping kea-dhcp6...
+INFO/keactrl: Stopping kea-dhcp-ddns...
 </screen>
       Note that the <command>stop</command> will attempt to stop all servers
       regardless of whether they are "enabled" in the <filename>keactrl.conf</filename>.
-      If any of the servers is not running, an informational message
-      is displayed as in the <command>stop</command> command output above.
+      If any of the servers are not running, an informational message
+      is displayed as in the <command>stop</command> command output below.
+<screen>
+<userinput>$ keactrl stop</userinput>
+INFO/keactrl: kea-dhcp4 isn't running.
+INFO/keactrl: kea-dhcp6 isn't running.
+INFO/keactrl: kea-dhcp-ddns isn't running.
+</screen>
       </para>
 
       <para>
@@ -184,6 +211,17 @@ INFO/keactrl: Skip sending signal 15 to process kea-dhcp6: process is not runnin
         valid, uses the new configuration. A reload is executed as follows:
 <screen>
 <userinput>$ keactrl reload</userinput>
+INFO/keactrl: Reloading kea-dhcp4...
+INFO/keactrl: Reloading kea-dhcp6...
+INFO/keactrl: Reloading kea-dhcp-ddns...
+</screen>
+      If any of the servers are not running, an informational message
+      is displayed as in the <command>reload</command> command output below.
+<screen>
+<userinput>$ keactrl stop</userinput>
+INFO/keactrl: kea-dhcp4 isn't running.
+INFO/keactrl: kea-dhcp6 isn't running.
+INFO/keactrl: kea-dhcp-ddns isn't running.
 </screen>
       </para>
 

+ 107 - 36
src/bin/keactrl/keactrl.in

@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -65,48 +65,75 @@ usage() {
 }
 
 ### Functions managing Kea processes ###
+# Contructs a server's PID file based on its binary name, the config file,
+# and the --localstatedir and returns the contents as $_pid.   If the file
+# does not exist, the value of $_pid is 0.  If the file exists but cannot
+# be read the function exists with a error message. Note the PID file name
+# is always returned in $_pid_file.
+get_pid_from_file() {
+    local proc_name=${1} # Process name.
+
+    # Extract the name portion of the config file
+    local conf_name=$(basename ${kea_config_file} | cut -f1 -d'.')
+
+    # Default the directory to --localstatedir
+    local pid_file_dir=@localstatedir@/@PACKAGE@
+
+    # Use directory override if set (primarily for testing only)
+    if [ ! -z $KEA_PIDFILE_DIR ]; then
+        pid_file_dir=${KEA_PIDFILE_DIR}
+    fi
 
-# Returns a list of existing PIDs and a number of PIDs for the process
-# having a name specified as an argument to the function.
-get_pids() {
-    local proc_name=${1}  # Process name.
-    # Return the list of PIDs.
-    _get_pids=$(ps axwwo pid,command | grep ${proc_name} | grep -v grep \
-        | awk '{print $1}')
-    # Return the number of PIDs.
-    _get_pids_num=$(printf "%s" "${_get_pids}" | wc -w | awk '{print $1}')
+    # construct the PID file name
+    _pid_file="${pid_file_dir}/${conf_name}.${proc_name}.pid"
+
+    # Grab the PID if the file exists
+    if [ -e ${_pid_file} ]; then
+        _pid=`cat ${_pid_file}`
+        if [ $? -ne 0 ]; then
+            log_error "Error reading PID file: ${_pid_file}"
+        fi
+    else
+        # No file, means no pid
+        _pid=0;
+    fi
 }
 
-# Checks if the specified process is running. Internally it calls get_pids
-# to get the number of processes.
+
+# Checks if the specified process is running by reading its
+# PID file and checking the PID it contains.  If the file does
+# not exist, the process is assumed to not be running.
 check_running() {
     local proc_name=${1} # Process name.
     # Initially mark the process as not running.
     _running=0
-    get_pids ${proc_name}
-    # If the number of pids is non-zero, the process is running.
-    if [ ${_get_pids_num} -gt 0 ]; then
-        _running=1
+
+    # Get the PID from the PID file (if it exists)
+    get_pid_from_file ${proc_name}
+    if [ ${_pid} -gt 0 ]; then
+        # Use kill -0 to check if PID is alive
+        kill -0 ${_pid}
+        if [ $? -eq 0 ]; then
+            # No error, so PID IS ALIVE
+            _running=1
+        fi
     fi
 }
 
-# Sends a signal to a group of processes having a specified name.
+# Sends a signal to a process based on its PID file
 send_signal() {
     local sig=${1}        # Signal number
     local proc_name=${2}  # Process name.
-    # Get all PIDs for the specified process name.
-    get_pids ${proc_name}
-    # If no processes running, there is no process we can send the signal
-    # to. This is not neccessarily an error.
-    if [ -z ${_get_pids} ]; then
+
+    get_pid_from_file ${proc_name}
+    if [ ${_pid} -eq 0 ]; then
         log_info "Skip sending signal ${sig} to process ${proc_name}: \
 process is not running\n"
-        return
-    fi
-    # Send a signal to all processes.
-    kill -${sig} ${_get_pids} >/dev/null 2>&1
-    if [ $? -ne 0 ]; then
-        log_error "Failed to send signal ${sig} to process ${proc_name}.\n"
+    else
+        kill -${sig} ${_pid}
+        if [ $? -ne 0 ]; then
+            log_error "Failed to send signal ${sig} to process ${proc_name}, PID {$_pid}.\n"
+        fi
     fi
 }
 
@@ -121,8 +148,8 @@ start_server() {
     check_running ${binary_name}
     # If process is running, don't start another one. Just log a message.
     if [ ${_running} -ne 0 ]; then
-        log_info "Skip starting ${binary_name} \
-as another instance is already running."
+        log_info "${binary_name} appears to be running, see: \
+PID ${_pid}, PID file: ${_pid_file}."
     else
         log_info "Starting ${binary_name} ${args}"
         # Start the process.
@@ -130,6 +157,50 @@ as another instance is already running."
     fi
 }
 
+# Instruct Kea process to shutdown by sending it signal 15
+stop_server() {
+    binary_path=${1}   # Full path to the binary.
+    local sig=15
+    # Extract the name of the binary from the path.
+    local binary_name=$(basename ${binary_path})
+
+    # Use the binary name to check if the process is already running.
+    check_running ${binary_name}
+    # If process isn't running, don't start another one. Just log a message.
+    if [ ${_running} -eq 0 ]; then
+        log_info "${binary_name} isn't running."
+    else
+        log_info "Stopping ${binary_name}..."
+        kill -${sig} ${_pid}
+        if [ $? -ne 0 ]; then
+            log_error "Stop failed, could not send signal ${sig} \
+to process ${proc_name}, PID ${_pid}.\n"
+        fi
+    fi
+}
+
+# Instruct Kea process to reload config by sending it signal 1
+reload_server() {
+    binary_path=${1}   # Full path to the binary.
+    local sig=1
+    # Extract the name of the binary from the path.
+    local binary_name=$(basename ${binary_path})
+
+    # Use the binary name to check if the process is already running.
+    check_running ${binary_name}
+    # If process isn't running, don't start another one. Just log a message.
+    if [ ${_running} -eq 0 ]; then
+        log_info "${binary_name} isn't running."
+    else
+        log_info "Reloading ${binary_name}..."
+        kill -${sig} ${_pid}
+        if [ $? -ne 0 ]; then
+            log_error "Reload failed, could not send signal ${sig} \
+to process ${proc_name}, PID ${_pid}.\n"
+        fi
+    fi
+}
+
 # Run the specified command if the server has been enabled.
 # In order for the command to run, the following conditions have to be met:
 # - server must be on the list of servers (e.g. specified from command line)
@@ -301,18 +372,18 @@ case ${command} in
     # Stop running servers.
     stop)
         # Stop all servers or servers specified from the command line.
-        run_conditional "dhcp4" "send_signal 15 $(basename ${dhcp4_srv})" 0
-        run_conditional "dhcp6" "send_signal 15 $(basename ${dhcp6_srv})" 0
-        run_conditional "dhcp_ddns" "send_signal 15 $(basename ${dhcp_ddns_srv})" 0
+        run_conditional "dhcp4" "stop_server ${dhcp4_srv}" 0
+        run_conditional "dhcp6" "stop_server ${dhcp6_srv}" 0
+        run_conditional "dhcp_ddns" "stop_server ${dhcp_ddns_srv}" 0
 
         exit 0 ;;
 
     # Reconfigure the servers.
     reload)
         # Reconfigure all servers or servers specified from the command line.
-        run_conditional "dhcp4" "send_signal 1 $(basename ${dhcp4_srv})" 0
-        run_conditional "dhcp6" "send_signal 1 $(basename ${dhcp6_srv})" 0
-        run_conditional "dhcp_ddns" "send_signal 1 $(basename ${dhcp_ddns_srv})" 0
+        run_conditional "dhcp4" "reload_server ${dhcp4_srv}" 0
+        run_conditional "dhcp6" "reload_server ${dhcp6_srv}" 0
+        run_conditional "dhcp_ddns" "reload_server ${dhcp_ddns_srv}" 0
 
         exit 0 ;;