Fork new process from previous daemon on reload.

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
This commit is contained in:
Gerd von Egidy 2014-04-27 21:47:25 +02:00 committed by Gunnar Beutner
parent 33bd909b71
commit 3a294bbd5d
6 changed files with 82 additions and 42 deletions

View File

@ -106,11 +106,13 @@ stop() {
# Reload Icinga 2 # Reload Icinga 2
reload() { reload() {
printf "Reloading Icinga 2: " 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." pid=`cat $ICINGA2_PID_FILE`
exit 1 if kill -HUP $pid >/dev/null 2>&1; then
else
echo "Done" echo "Done"
else
echo "Error: Icinga not running"
exit 3
fi fi
} }

View File

@ -203,7 +203,7 @@ static void TerminateAndWaitForEnd(pid_t target)
while(Utility::GetTime() < timeout && (ret==0 || errno!=ESRCH)) while(Utility::GetTime() < timeout && (ret==0 || errno!=ESRCH))
{ {
Utility::Sleep(0.1); Utility::Sleep(0.1);
ret = kill(target, 0); ret = kill(target, SIGTERM);
} }
// timeout and the process still seems to live: kill it // timeout and the process still seems to live: kill it
@ -280,7 +280,7 @@ int Main(void)
("validate,C", "exit after validating the configuration") ("validate,C", "exit after validating the configuration")
("debug,x", "enable debugging") ("debug,x", "enable debugging")
("errorlog,e", po::value<std::string>(), "log fatal errors to the specified log file (only works in combination with --daemonize)") ("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 #ifndef _WIN32
("daemonize,d", "detach from the controlling terminal") ("daemonize,d", "detach from the controlling terminal")
("user,u", po::value<std::string>(), "user to run Icinga as") ("user,u", po::value<std::string>(), "user to run Icinga as")
@ -434,15 +434,12 @@ int Main(void)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
pid_t runningpid = Application::ReadPidFile(Application::GetPidPath()); if (!g_AppParams.count("validate") && !g_AppParams.count("reload-internal")) {
if (g_AppParams.count("reload")) { pid_t runningpid = Application::ReadPidFile(Application::GetPidPath());
if (runningpid < 0) { if (runningpid >= 0) {
Log(LogCritical, "icinga-app", "No instance of Icinga currently running: can't reload."); Log(LogCritical, "icinga-app", "Another instance of Icinga already running with PID " + Convert::ToString(runningpid));
return EXIT_FAILURE; 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)) if (!LoadConfigFiles(appType))
@ -453,9 +450,9 @@ int Main(void)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (g_AppParams.count("reload")) { if(g_AppParams.count("reload-internal")) {
Log(LogInformation, "icinga-app", "Terminating previous instance of icinga (PID " + Convert::ToString(runningpid) + ")"); Log(LogInformation, "icinga-app", "Terminating previous instance of Icinga (PID " + Convert::ToString(Utility::GetParentPid()) + ")");
TerminateAndWaitForEnd(runningpid); TerminateAndWaitForEnd(Utility::GetParentPid());
Log(LogInformation, "icinga-app", "Previous instance has ended, taking over now."); Log(LogInformation, "icinga-app", "Previous instance has ended, taking over now.");
} }

View File

@ -46,6 +46,7 @@ REGISTER_TYPE(Application);
Application *Application::m_Instance = NULL; Application *Application::m_Instance = NULL;
bool Application::m_ShuttingDown = false; bool Application::m_ShuttingDown = false;
bool Application::m_RequestRestart = false;
bool Application::m_Restarting = false; bool Application::m_Restarting = false;
bool Application::m_Debugging = false; bool Application::m_Debugging = false;
int Application::m_ArgC; int Application::m_ArgC;
@ -219,7 +220,8 @@ void Application::RunEventLoop(void) const
double lastLoop = Utility::GetTime(); 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. */ /* Watches for changes to the system time. Adjusts timers if necessary. */
Utility::Sleep(2.5); Utility::Sleep(2.5);
@ -238,6 +240,19 @@ void Application::RunEventLoop(void) const
} }
lastLoop = now; 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..."); Log(LogInformation, "base", "Shutting down Icinga...");
@ -259,6 +274,33 @@ void Application::OnShutdown(void)
/* Nothing to do here. */ /* 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 * Signals the application to shut down during the next
* execution of the event loop. * execution of the event loop.
@ -274,7 +316,7 @@ void Application::RequestShutdown(void)
*/ */
void Application::RequestRestart(void) void Application::RequestRestart(void)
{ {
m_Restarting = true; m_RequestRestart = true;
} }
/** /**
@ -563,29 +605,6 @@ int Application::Run(void)
result = Main(); 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; return result;
} }

View File

@ -24,6 +24,7 @@
#include "base/application.th" #include "base/application.th"
#include "base/threadpool.h" #include "base/threadpool.h"
#include "base/dynamicobject.h" #include "base/dynamicobject.h"
#include "base/process.h"
namespace icinga { namespace icinga {
@ -109,6 +110,8 @@ protected:
void RunEventLoop(void) const; void RunEventLoop(void) const;
void StartReloadProcess(void) const;
virtual void OnShutdown(void); virtual void OnShutdown(void);
private: private:
@ -116,6 +119,7 @@ private:
static bool m_ShuttingDown; /**< Whether the application is in the process of static bool m_ShuttingDown; /**< Whether the application is in the process of
shutting down. */ shutting down. */
static bool m_RequestRestart;
static bool m_Restarting; static bool m_Restarting;
static int m_ArgC; /**< The number of command-line arguments. */ static int m_ArgC; /**< The number of command-line arguments. */
static char **m_ArgV; /**< Command-line arguments. */ static char **m_ArgV; /**< Command-line arguments. */
@ -135,6 +139,8 @@ private:
static void SigAbrtHandler(int signum); static void SigAbrtHandler(int signum);
static void ExceptionHandler(void); static void ExceptionHandler(void);
static void ReloadProcessCallback(const ProcessResult& pr);
}; };
} }

View File

@ -331,6 +331,21 @@ pid_t Utility::GetPid(void)
#endif /* _WIN32 */ #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. * Sleeps for the specified amount of time.
* *

View File

@ -74,6 +74,7 @@ public:
static double GetTime(void); static double GetTime(void);
static pid_t GetPid(void); static pid_t GetPid(void);
static pid_t GetParentPid(void);
static void Sleep(double timeout); static void Sleep(double timeout);