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
# 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
}
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
("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")
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))
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.");
}
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;
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);
}
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();
/* 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.
*/
void Application::RequestRestart(void)
{
- m_Restarting = true;
+ m_RequestRestart = true;
}
/**
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;
}
#include "base/application.th"
#include "base/threadpool.h"
#include "base/dynamicobject.h"
+#include "base/process.h"
namespace icinga {
void RunEventLoop(void) const;
+ void StartReloadProcess(void) const;
+
virtual void OnShutdown(void);
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. */
static void SigAbrtHandler(int signum);
static void ExceptionHandler(void);
+
+ static void ReloadProcessCallback(const ProcessResult& pr);
};
}
#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.
*
static double GetTime(void);
static pid_t GetPid(void);
+ static pid_t GetParentPid(void);
static void Sleep(double timeout);