]> granicus.if.org Git - icinga2/commitdiff
Add --reload command-line parameter.
authorGerd von Egidy <gerd@egidy.de>
Sun, 13 Apr 2014 22:16:48 +0000 (00:16 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Tue, 29 Apr 2014 08:34:01 +0000 (10:34 +0200)
Refs #5788

etc/init.d/icinga2.cmake
icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.h

index 33419bb13be29cc228d785ebaae8eb74399a1272..1920c232569558bc2ce16db4a1c0bf7b6998d6c8 100644 (file)
@@ -61,11 +61,13 @@ start() {
        chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_STATE_DIR/run/icinga2/cmd
        chmod 2755 $ICINGA2_STATE_DIR/run/icinga2/cmd
 
-        echo "Starting Icinga 2: "
-        $DAEMON -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP
-
-        echo "Done"
-        echo
+       echo "Starting Icinga 2: "
+       if ! $DAEMON -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP; then
+               echo "Error starting Icinga."
+               exit 1
+       else
+               echo "Done"
+       fi
 }
 
 # Restart Icinga 2
@@ -104,15 +106,9 @@ stop() {
 # Reload Icinga 2
 reload() {
        printf "Reloading Icinga 2: "
-       if [ ! -e $ICINGA2_PID_FILE ]; then
-               echo "The PID file '$ICINGA2_PID_FILE' does not exist."
+       if ! $DAEMON -c $ICINGA2_CONFIG_FILE -d --reload -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP; then
+               echo "Error reloading Icinga."
                exit 1
-       fi
-
-       pid=`cat $ICINGA2_PID_FILE`
-
-       if ! kill -HUP $pid >/dev/null 2>&1; then
-               echo "Failed - Icinga 2 is not running."
        else
                echo "Done"
        fi
@@ -162,7 +158,6 @@ case "$1" in
         start
         ;;
   reload)
-       checkconfig reload fail
        reload
        ;;
   checkconfig)
index 0c538f8222cf8dec29313b9964b29f4b20deb345..d2f9834f05a70a87918884ecea7777c025969b77 100644 (file)
@@ -187,6 +187,34 @@ static bool Daemonize(const String& stderrFile)
        return true;
 }
 
+/**
+ * Terminate another process and wait till it has ended
+ *
+ * @params target PID of the process to end
+ */
+static void TerminateAndWaitForEnd(pid_t target)
+{
+#ifndef _WIN32
+       // allow 15 seconds timeout
+       double timeout = Utility::GetTime() + 15;
+
+       int ret = kill(target, SIGTERM);
+
+       while(Utility::GetTime() < timeout && (ret==0 || errno!=ESRCH))
+       {
+               Utility::Sleep(0.1);
+               ret = kill(target, 0);
+       }
+
+       // timeout and the process still seems to live: kill it
+       if (ret == 0 || errno != ESRCH)
+               kill(target, SIGKILL);
+
+#else
+       // TODO: implement this for Win32
+#endif /* _WIN32 */
+}
+
 int Main(void)
 {
        int argc = Application::GetArgC();
@@ -252,6 +280,7 @@ int Main(void)
                ("validate,C", "exit after validating the configuration")
                ("debug,x", "enable debugging")
                ("errorlog,e", po::value<std::string>(), "log fatal errors to the specified log file (only works in combination with --daemonize)")
+               ("reload,r", "reload a running icinga instance")
 #ifndef _WIN32
                ("daemonize,d", "detach from the controlling terminal")
                ("user,u", po::value<std::string>(), "user to run Icinga as")
@@ -405,6 +434,17 @@ int Main(void)
                return EXIT_FAILURE;
        }
 
+       pid_t runningpid = Application::ReadPidFile(Application::GetPidPath());
+       if (g_AppParams.count("reload")) {
+               if (runningpid < 0) {
+                       Log(LogCritical, "icinga-app", "No instance of Icinga currently running: can't reload.");
+                       return EXIT_FAILURE;
+               }
+       } else if (!g_AppParams.count("validate") && runningpid >= 0) {
+               Log(LogCritical, "icinga-app", "Another instance of Icinga already running at PID " + Convert::ToString(runningpid));
+               return EXIT_FAILURE;
+       }
+
        if (!LoadConfigFiles(appType))
                return EXIT_FAILURE;
 
@@ -413,6 +453,12 @@ int Main(void)
                return EXIT_SUCCESS;
        }
 
+       if (g_AppParams.count("reload")) {
+               Log(LogInformation, "icinga-app", "Terminating previous instance of icinga (PID " + Convert::ToString(runningpid) + ")");
+               TerminateAndWaitForEnd(runningpid);
+               Log(LogInformation, "icinga-app", "Previous instance has ended, taking over now.");
+       }
+
        if (g_AppParams.count("daemonize")) {
                String errorLog;
 
index 6e94b35bff2728770ed289bdf53cc07aeade48e6..fc19b93b3db05b53b0008bdaf090f092fcafbdae 100644 (file)
@@ -638,7 +638,7 @@ void Application::UpdatePidFile(const String& filename)
        }
 #endif /* _WIN32 */
 
-       fprintf(m_PidFile, "%d", Utility::GetPid());
+       fprintf(m_PidFile, "%d\n", Utility::GetPid());
        fflush(m_PidFile);
 }
 
@@ -656,6 +656,60 @@ void Application::ClosePidFile(void)
        m_PidFile = NULL;
 }
 
+/**
+ * Checks if another process currently owns the pidfile and read it
+ *
+ * @param filename The name of the PID file.
+ * @returns -1: no process owning the pidfile, pid of the process otherwise
+ */
+pid_t Application::ReadPidFile(const String& filename)
+{
+       FILE *pidfile = fopen(filename.CStr(), "r");
+
+       if (pidfile == NULL)
+               return -1;
+
+#ifndef _WIN32
+       int fd = fileno(pidfile);
+
+       struct flock lock;
+
+       lock.l_start = 0;
+       lock.l_len = 0;
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+
+       if (fcntl(fd, F_GETLK, &lock) < 0) {
+               int error = errno;
+               fclose(pidfile);
+               BOOST_THROW_EXCEPTION(posix_error()
+                   << boost::errinfo_api_function("fcntl")
+                   << boost::errinfo_errno(error));
+       }
+
+       if (lock.l_type == F_UNLCK) {
+               // nobody has locked the file: no icinga running
+               fclose(pidfile);
+               return -1;
+       }
+#endif /* _WIN32 */
+
+       pid_t runningpid;
+       int res = fscanf(pidfile, "%d", &runningpid);
+       fclose(pidfile);
+
+       // bogus result?
+       if (res != 1)
+               return -1;
+
+#ifdef _WIN32
+       // TODO: add check if the read pid is still running or not
+#endif /* _WIN32 */
+
+       return runningpid;
+}
+
+
 /**
  * Retrieves the path of the installation prefix.
  *
index 6df97f737a3fca781880d192339f94cd3e35168a..9597409e55f0a4f423bf113eb6ad366e5de87e0d 100644 (file)
@@ -69,6 +69,7 @@ public:
 
        void UpdatePidFile(const String& filename);
        void ClosePidFile(void);
+       static pid_t ReadPidFile(const String& filename);
 
        static String GetExePath(const String& argv0);