mirror of https://github.com/Icinga/icinga2.git
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:
parent
33bd909b71
commit
3a294bbd5d
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue