Implemented correct agent restart for systemd services
authorEriks Jenkevics <eriks@netxms.org>
Fri, 29 Sep 2017 14:31:57 +0000 (17:31 +0300)
committerEriks Jenkevics <eriks@netxms.org>
Fri, 29 Sep 2017 14:32:04 +0000 (17:32 +0300)
configure.ac
src/agent/core/Makefile.am
src/agent/core/nxagentd.cpp
src/agent/core/nxagentd.h
src/agent/core/systemd.cpp [new file with mode: 0644]

index 74c56cb..580fc83 100644 (file)
@@ -123,6 +123,7 @@ WITH_ENCRYPTION="no"
 DISABLE_COMMONCRYPTO="no"
 OPENSSL_LIBSSL="ssl"
 OPENSSL_LIBCRYPTO="crypto"
+SYSTEMD_SUPPORT="yes"
 
 
 #--------------------------------------------------------------------
@@ -714,6 +715,14 @@ AC_ARG_WITH(tests,
        TOP_LEVEL_MODULES="$TOP_LEVEL_MODULES tests"
 ])
 
+AC_ARG_ENABLE(systemd,
+[AS_HELP_STRING(--disable-systemd,disable Systemd support)],
+[
+       if test "x$$enableval" = "xno"; then
+               SYSTEMD_SUPPORT="no"
+       fi
+])
+
 
 #--------------------------------------------------------------------
 # Set LD_LIBRARY_PATH from LD_RUN_PATH because on some systems
@@ -2077,6 +2086,15 @@ if test "x$LDAP_SUPPORT" = "xyes"; then
        LDAP_SUPPORT="$HAVE_LDAP"
 fi
 
+if test "x$SYSTEMD_SUPPORT" = "xyes"; then
+       AC_CHECK_HEADER(systemd/sd-bus.h,HAVE_SYSTEMD=yes,HAVE_SYSTEMD=no)
+       if test "x$HAVE_SYSTEMD" = "xyes"; then
+               AC_DEFINE(WITH_SYSTEMD, 1, Define to 1 if you have Systemd libraries and headers)
+               SUBAGENT_LIBS="-lsystemd $SUBAGENT_LIBS"
+       fi
+       SYSTEMD_SUPPORT="$HAVE_SYSTEMD"
+fi
+
 #--------------------------------------------------------------------
 # Checks for data types
 #--------------------------------------------------------------------
@@ -3853,6 +3871,11 @@ if test "x${BUILD_AGENT}" = "xyes"; then
        echo "Build Agent             : YES"
        echo "Agent extra components  :${AGENT_DIRS}"
        echo "Subagents list          :${SUBAGENT_DIRS}"
+       if test "x${SYSTEMD_SUPPORT}" = "xyes"; then
+               echo "Systemd support           : YES"
+       else
+               echo "Systemd support           : NO"
+       fi
 else
        echo "Build Agent             : NO"
 fi
index 83ee05c..f6c80d1 100644 (file)
@@ -6,7 +6,7 @@ nxagentd_SOURCES = messages.c actions.cpp appagent.cpp comm.cpp config.cpp \
                    nxagentd.cpp policy.cpp push.cpp register.cpp sa.cpp \
                    session.cpp snmpproxy.cpp snmptrapproxy.cpp \
                    static_subagents.cpp subagent.cpp sysinfo.cpp syslog.cpp \
-                  tools.cpp trap.cpp tunnel.cpp upgrade.cpp watchdog.cpp
+                                  systemd.cpp tools.cpp trap.cpp tunnel.cpp upgrade.cpp watchdog.cpp
 if USE_INTERNAL_EXPAT
 nxagentd_LDADD = ../../appagent/libappagent.la ../libnxagent/libnxagent.la @top_srcdir@/src/db/libnxdb/libnxdb.la @top_srcdir@/src/libnetxms/libnetxms.la @top_srcdir@/src/snmp/libnxsnmp/libnxsnmp.la @top_srcdir@/src/libexpat/libexpat/libnxexpat.la @SUBAGENT_LIBS@
 else
index 3a0f701..2929f4d 100644 (file)
@@ -1304,7 +1304,13 @@ static void DoRestartActions(UINT32 dwOldPID)
          CloseHandle(hProcess);
       }
    }
+#elif WITH_SYSTEMD
+   if (RestartService(dwOldPID))
+      dwOldPID = 0; // Success
 #else
+   if (dwOldPID == 0) // Already killed
+      return;
+
    int i;
 
    kill(dwOldPID, SIGTERM);
@@ -1986,7 +1992,7 @@ int main(int argc, char *argv[])
                                                s_pid = getpid();
                                                if (Initialize())
                                                {
-                                                       FILE *fp;
+                                                  FILE *fp;
 
                                                        // Write PID file
                                                        fp = _tfopen(g_szPidFile, _T("w"));
index 7daa976..9e03285 100644 (file)
@@ -627,6 +627,12 @@ bool EnumerateSessions(EnumerationCallbackResult (* callback)(AbstractCommSessio
 AbstractCommSession *FindServerSession(UINT64 serverId);
 AbstractCommSession *FindServerSession(bool (*comparator)(AbstractCommSession *, void *), void *userData);
 
+#ifdef WITH_SYSTEMD
+bool RestartService(UINT32 pid);
+#endif
+
+void KillProcess(UINT32 pid);
+
 #ifdef _WIN32
 
 void InitService();
diff --git a/src/agent/core/systemd.cpp b/src/agent/core/systemd.cpp
new file mode 100644 (file)
index 0000000..2340a28
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+** NetXMS multiplatform core agent
+** Copyright (C) 2003-2017 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: systemd.cpp
+**
+**/
+
+#include <nms_util.h>
+
+#if WITH_SYSTEMD
+extern "C"
+{
+#include <systemd/sd-bus.h>
+}
+#endif
+
+/**
+ * Find the name of the systemd service given pid (if run as service)
+ */
+static char *FindServiceName(UINT32 pid)
+{
+   char path[64];
+   snprintf(path, 64, "/proc/%d/cgroup", pid);
+   FILE *cgroup = fopen(path, "r");
+   char *serviceName = NULL;
+   if (cgroup != NULL)
+   {
+     char fileBuffer[255];
+     while(fgets(fileBuffer, 255, cgroup) != NULL)
+     {
+        serviceName = strstr(fileBuffer, ".service");
+        if (serviceName != NULL)
+        {
+           serviceName[8] = 0;
+           while(*serviceName != '/')
+              serviceName--;
+           serviceName++;
+           serviceName = strdup(serviceName);
+           break;
+        }
+     }
+     fclose(cgroup);
+   }
+
+   return serviceName;
+}
+
+/**
+ * Restart service run by systemd
+ */
+bool RestartService(UINT32 pid)
+{
+   sd_bus_error error = SD_BUS_ERROR_NULL;
+   sd_bus_message *m = NULL;
+   sd_bus *bus = NULL;
+   const char *path;
+   int r;
+   char *serviceName = FindServiceName(pid);
+   bool result = false;
+
+   /* Connect to the system bus */
+   r = sd_bus_open_system(&bus);
+   if (r < 0)
+   {
+      _ftprintf(stderr, _T("Failed to connect to system bus: %s\n"), strerror(-r));
+      sd_bus_message_unref(m);
+      sd_bus_unref(bus);
+      goto finish;
+   }
+
+   /* Issue the method call and store the respons message in m */
+   r = sd_bus_call_method(bus,
+                          "org.freedesktop.systemd1",           /* service to contact */
+                          "/org/freedesktop/systemd1",          /* object path */
+                          "org.freedesktop.systemd1.Manager",   /* interface name */
+                          "RestartUnit",                        /* method name */
+                          &error,                               /* object to return error in */
+                          &m,                                   /* return message on success */
+                          "ss",                                 /* input signature */
+                          serviceName,                          /* first argument */
+                          "replace");                           /* second argument */
+   if (r < 0)
+   {
+      _ftprintf(stderr, _T("Failed to issue method call: %s\n"), error.message);
+      goto finish;
+   }
+
+   /* Parse the response message */
+   r = sd_bus_message_read(m, "o", &path);
+   if (r < 0)
+   {
+      _ftprintf(stderr, _T("Failed to parse response message: %s\n"), strerror(-r));
+      goto finish;
+   }
+
+   _tprintf(_T("Queued service job as %s\n"), path);
+   result = true;
+
+   finish:
+           sd_bus_error_free(&error);
+           sd_bus_message_unref(m);
+           sd_bus_unref(bus);
+           free(serviceName);
+
+   return result;
+}