]> granicus.if.org Git - icinga2/commitdiff
Fork new process from previous daemon on reload.
authorGerd von Egidy <gerd@egidy.de>
Sun, 27 Apr 2014 19:47:25 +0000 (21:47 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Tue, 29 Apr 2014 08:34:01 +0000 (10:34 +0200)
The previously planned logic of forking a new daemon from the reload-process didn't work with
systemd: systemd does not allow long-running processes started from within the reload command.

Replaces parameter --reload with --reload-internal which is used when starting the new daemon.

Refs #5788

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

index 1920c232569558bc2ce16db4a1c0bf7b6998d6c8..f181fa90a2285c2368c603a4bf93cf201130a8f1 100644 (file)
@@ -106,11 +106,13 @@ stop() {
 # Reload Icinga 2
 reload() {
        printf "Reloading Icinga 2: "
-       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
-       else
+
+       pid=`cat $ICINGA2_PID_FILE`
+       if kill -HUP $pid >/dev/null 2>&1; then
                echo "Done"
+       else
+               echo "Error: Icinga not running"
+               exit 3
        fi
 }
 
index d2f9834f05a70a87918884ecea7777c025969b77..4eb7779fbbf7cc76033a201d635ec4551bd6f945 100644 (file)
@@ -203,7 +203,7 @@ static void TerminateAndWaitForEnd(pid_t target)
        while(Utility::GetTime() < timeout && (ret==0 || errno!=ESRCH))
        {
                Utility::Sleep(0.1);
-               ret = kill(target, 0);
+               ret = kill(target, SIGTERM);
        }
 
        // timeout and the process still seems to live: kill it
@@ -280,7 +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")
+               ("reload-internal", "used internally to implement config reload: do not call manually, send SIGHUP instead")
 #ifndef _WIN32
                ("daemonize,d", "detach from the controlling terminal")
                ("user,u", po::value<std::string>(), "user to run Icinga as")
@@ -434,15 +434,12 @@ 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.");
+       if (!g_AppParams.count("validate") && !g_AppParams.count("reload-internal")) {
+               pid_t runningpid = Application::ReadPidFile(Application::GetPidPath());
+               if (runningpid >= 0) {
+                       Log(LogCritical, "icinga-app", "Another instance of Icinga already running with PID " + Convert::ToString(runningpid));
                        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))
@@ -453,9 +450,9 @@ 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);
+       if(g_AppParams.count("reload-internal")) {
+               Log(LogInformation, "icinga-app", "Terminating previous instance of Icinga (PID " + Convert::ToString(Utility::GetParentPid()) + ")");
+               TerminateAndWaitForEnd(Utility::GetParentPid());
                Log(LogInformation, "icinga-app", "Previous instance has ended, taking over now.");
        }
 
index fc19b93b3db05b53b0008bdaf090f092fcafbdae..a3a6029051cb6b211872ba5503d72372eeedb7f7 100644 (file)
@@ -46,6 +46,7 @@ REGISTER_TYPE(Application);
 
 Application *Application::m_Instance = NULL;
 bool Application::m_ShuttingDown = false;
+bool Application::m_RequestRestart = false;
 bool Application::m_Restarting = false;
 bool Application::m_Debugging = false;
 int Application::m_ArgC;
@@ -219,7 +220,8 @@ void Application::RunEventLoop(void) const
 
        double lastLoop = Utility::GetTime();
 
-       while (!m_ShuttingDown && !m_Restarting) {
+mainloop:
+       while (!m_ShuttingDown && !m_RequestRestart) {
                /* Watches for changes to the system time. Adjusts timers if necessary. */
                Utility::Sleep(2.5);
 
@@ -238,8 +240,21 @@ void Application::RunEventLoop(void) const
                }
 
                lastLoop = now;
-       }
 
+               if (m_RequestRestart) {
+                       m_RequestRestart = false;         // we are now handling the request, once is enough
+               
+                       // are we already restarting? ignore request if we already are
+                       if (m_Restarting)
+                               goto mainloop;
+
+                       m_Restarting = true;
+                       StartReloadProcess();
+
+                       goto mainloop;
+               }
+       }
+       
        Log(LogInformation, "base", "Shutting down Icinga...");
        DynamicObject::StopObjects();
        Application::GetInstance()->OnShutdown();
@@ -259,6 +274,33 @@ void Application::OnShutdown(void)
        /* Nothing to do here. */
 }
 
+void Application::StartReloadProcess(void) const
+{
+       Log(LogInformation, "base", "Got reload command: Starting new instance.");
+
+       // prepare arguments
+       std::vector<String> args;
+       args.push_back(GetExePath(m_ArgV[0]));
+
+       for (int i=1; i < Application::GetArgC(); i++)
+               if (std::string(Application::GetArgV()[i]) != "--reload-internal")
+                       args.push_back(Application::GetArgV()[i]);
+       args.push_back("--reload-internal");
+
+       Process::Ptr process = make_shared<Process>(args);
+
+       process->SetTimeout(15);
+
+       process->Run(boost::bind(&Application::ReloadProcessCallback, _1));
+}
+
+void Application::ReloadProcessCallback(const ProcessResult& pr)
+{
+       if (pr.ExitStatus != 0)
+               Log(LogCritical, "base", "Found error in config: reloading aborted");
+       m_Restarting=false;
+}
+
 /**
  * Signals the application to shut down during the next
  * execution of the event loop.
@@ -274,7 +316,7 @@ void Application::RequestShutdown(void)
  */
 void Application::RequestRestart(void)
 {
-       m_Restarting = true;
+       m_RequestRestart = true;
 }
 
 /**
@@ -563,29 +605,6 @@ int Application::Run(void)
 
        result = Main();
 
-       if (m_Restarting) {
-               Log(LogInformation, "base", "Restarting application.");
-
-#ifndef _WIN32
-               String exePath = GetExePath(m_ArgV[0]);
-
-               int fdcount = getdtablesize();
-
-               for (int i = 3; i < fdcount; i++)
-                       (void) close(i);
-
-               (void) execv(exePath.CStr(), m_ArgV);
-#else /* _WIN32 */
-               STARTUPINFO si;
-               PROCESS_INFORMATION pi;
-               memset(&si, 0, sizeof(si));
-               si.cb = sizeof(si);
-               CreateProcess(NULL, GetCommandLine(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
-#endif /* _WIN32 */
-
-               _exit(0);
-       }
-
        return result;
 }
 
index 9597409e55f0a4f423bf113eb6ad366e5de87e0d..9f5e5ebe1b5c0b3bd091b8b5e1a56906a31c1453 100644 (file)
@@ -24,6 +24,7 @@
 #include "base/application.th"
 #include "base/threadpool.h"
 #include "base/dynamicobject.h"
+#include "base/process.h"
 
 namespace icinga {
 
@@ -109,6 +110,8 @@ protected:
 
        void RunEventLoop(void) const;
 
+       void StartReloadProcess(void) const;
+
        virtual void OnShutdown(void);
 
 private:
@@ -116,6 +119,7 @@ private:
 
        static bool m_ShuttingDown; /**< Whether the application is in the process of
                                  shutting down. */
+       static bool m_RequestRestart;
        static bool m_Restarting;
        static int m_ArgC; /**< The number of command-line arguments. */
        static char **m_ArgV; /**< Command-line arguments. */
@@ -135,6 +139,8 @@ private:
 
        static void SigAbrtHandler(int signum);
        static void ExceptionHandler(void);
+
+       static void ReloadProcessCallback(const ProcessResult& pr);
 };
 
 }
index 56559fea22eb2ff9259652753cbb1464688dd255..dc3c8232ba4827978dbe13a58d3788167275587d 100644 (file)
@@ -331,6 +331,21 @@ pid_t Utility::GetPid(void)
 #endif /* _WIN32 */
 }
 
+/**
+ * Returns the ID of the parent process.
+ *
+ * @returns The PID.
+ */
+pid_t Utility::GetParentPid(void)
+{
+#ifndef _WIN32
+       return getppid();
+#else /* _WIN32 */
+       // TODO
+       return 0;
+#endif /* _WIN32 */
+}
+
 /**
  * Sleeps for the specified amount of time.
  *
index f8c05a5fe930af6b28eb33235feefb7c960b47b2..ada33d43aa13e42f3faae7c3367702c924e65a6e 100644 (file)
@@ -74,6 +74,7 @@ public:
        static double GetTime(void);
 
        static pid_t GetPid(void);
+       static pid_t GetParentPid(void);
 
        static void Sleep(double timeout);