summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2014-07-11 17:23:10 +0200
committerGuido Günther <agx@sigxcpu.org>2014-07-11 20:02:35 +0200
commitf758314abe0c3c4cc2b06ca5a24c7288a0af41ed (patch)
tree7c1170065179a884031e8cf5d0d5f558edf25c17
parent3ff8c7d8227119474543b0fd4dbee0817676472e (diff)
Add systemd support
-rw-r--r--tests/test_systemd.py62
-rwxr-xr-xwhatmaps/command.py64
-rw-r--r--whatmaps/debiandistro.py7
-rw-r--r--whatmaps/systemd.py41
4 files changed, 152 insertions, 22 deletions
diff --git a/tests/test_systemd.py b/tests/test_systemd.py
new file mode 100644
index 0000000..2fbdfdc
--- /dev/null
+++ b/tests/test_systemd.py
@@ -0,0 +1,62 @@
+# vim: set fileencoding=utf-8 :
+# (C) 2014 Guido Günther <agx@sigxcpu.org>
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+"""Test L{whatmaps.process} config"""
+
+import unittest
+
+from mock import patch
+
+from whatmaps.systemd import Systemd
+from whatmaps.process import Process
+
+class Process(object):
+ def __init__(self, pid):
+ self.pid = pid
+
+class TestSystemd(unittest.TestCase):
+ def test_is_init(self):
+ """Check if we create a systemd object if systemd is the init system in use"""
+ with patch('os.path.exists', return_value=True):
+ self.assertIsNotNone(Systemd())
+
+ def test_is_not_init(self):
+ """Check if we raise an exception if systemd isn't tthe init system in use"""
+ with patch('os.path.exists', return_value=False):
+ self.assertRaises(ValueError, Systemd)
+
+ def test_process_to_unit(self):
+ p = Process(952)
+ output = """libvirt-bin.service - Virtualization daemon
+ Loaded: loaded (/lib/systemd/system/libvirt-bin.service; enabled)
+ Active: active (running) since Fr 2014-07-11 16:10:55 CEST; 50min ago
+ Docs: man:libvirtd(8)
+ http://libvirt.org
+ Main PID: 952 (libvirtd)
+ CGroup: name=systemd:/system/libvirt-bin.service
+ ├─ 952 /usr/sbin/libvirtd
+ └─1355 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf
+ """
+ with patch('os.path.exists', return_value=True):
+ with patch('subprocess.Popen') as mock:
+ PopenMock = mock.return_value
+ PopenMock.communicate.return_value = [output]
+ PopenMock.returncode = 0
+ result = Systemd().process_to_unit(p)
+ self.assertEqual(result, 'libvirt-bin.service')
+
+ PopenMock.returncode = 1
+ result = Systemd().process_to_unit(p)
+ self.assertIsNone(result)
+
diff --git a/whatmaps/command.py b/whatmaps/command.py
index 3c22e20..7690ef8 100755
--- a/whatmaps/command.py
+++ b/whatmaps/command.py
@@ -28,6 +28,7 @@ from optparse import OptionParser
from . process import Process
from . distro import Distro
from . pkg import PkgError
+from . systemd import Systemd
def check_maps(procs, shared_objects):
restart_procs = {}
@@ -106,8 +107,25 @@ def find_services(pkgs, distro):
return all_services
+def find_systemd_units(procmap, distro):
+ """Find systemd units that contain the given processes"""
+ units = set()
+
+ for dummy, procs in procmap.items():
+ for proc in procs:
+ unit = Systemd.process_to_unit(proc)
+ if not unit:
+ logging.warning("No systemd unit found for '%s'"
+ "- restart manually" % proc.exe)
+ else:
+ units.add(unit)
+ units -= set([ service + '.service' for service in distro.service_blacklist ])
+ return units
+
+
def main(argv):
shared_objects = []
+ services = None
parser = OptionParser(usage='%prog [options] pkg1 [pkg2 pkg3 pkg4]')
parser.add_option("--debug", action="store_true", dest="debug",
@@ -180,34 +198,38 @@ def main(argv):
for exe, pids in restart_procs.items():
logging.debug(" Exe: %s Pids: %s", exe, pids),
- # Find the packages that contain the binaries the processes are
- # executing
- pkgs = find_pkgs(restart_procs, distro)
+ if Systemd.is_running():
+ logging.debug("Detected Systemd")
+ services = find_systemd_units(restart_procs, distro)
+ else:
+ # Find the packages that contain the binaries the processes are
+ # executing
+ pkgs = find_pkgs(restart_procs, distro)
- # Find the services in these packages honoring distro specific
- # mappings and blacklists
- try:
- all_services = find_services(pkgs, distro)
- except NotImplementedError:
- if level > logging.INFO:
- logging.error("Getting Service listing not implemented "
- "for distribution %s - rerun with --verbose to see a list"
- "of binaries that map a shared objects from %s",
- distro.id, args)
- return 1
- else:
- return 0
+ # Find the services in these packages honoring distro specific
+ # mappings and blacklists
+ try:
+ services = find_services(pkgs, distro)
+ except NotImplementedError:
+ if level > logging.INFO:
+ logging.error("Getting Service listing not implemented "
+ "for distribution %s - rerun with --verbose to see a list"
+ "of binaries that map a shared objects from %s",
+ distro.id, args)
+ return 1
+ else:
+ return 0
if options.restart:
- if options.print_cmds and all_services:
- write_cmd_file(all_services, options.print_cmds, distro)
+ if options.print_cmds and services:
+ write_cmd_file(services, options.print_cmds, distro)
else:
- for service in all_services:
+ for service in services:
logging.info("Restarting %s" % service)
distro.restart_service(service)
- elif all_services:
+ elif services:
print("Services that possibly need to be restarted:")
- for s in all_services:
+ for s in services:
print(s)
return 0
diff --git a/whatmaps/debiandistro.py b/whatmaps/debiandistro.py
index d608d8f..5333a35 100644
--- a/whatmaps/debiandistro.py
+++ b/whatmaps/debiandistro.py
@@ -34,6 +34,7 @@ import string
import distro
from . debianpkg import DebianPkg
from . pkg import PkgError
+from . systemd import Systemd
class DebianDistro(distro.Distro):
"Debian (dpkg) based distribution"
@@ -73,8 +74,12 @@ class DebianDistro(distro.Distro):
return DebianPkg(pkg)
@classmethod
- def restart_service_cmd(klass, name):
+ def restart_service_cmd(klass, service):
"""The command that should be used to start a service"""
+ if Systemd.is_running() and service.endswith('.service'):
+ name = service[:-len('.service')]
+ else:
+ name = service
return ['invoke-rc.d', name, 'restart']
@classmethod
diff --git a/whatmaps/systemd.py b/whatmaps/systemd.py
new file mode 100644
index 0000000..add6d0e
--- /dev/null
+++ b/whatmaps/systemd.py
@@ -0,0 +1,41 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2014 Guido Günther <agx@sigxcpu.org>
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import subprocess
+
+
+class Systemd(object):
+ """Systemd init system"""
+
+ def __init__(self):
+ if not self.is_running():
+ raise ValueError("Systemd not running")
+
+ @staticmethod
+ def is_running():
+ return os.path.exists("/run/systemd/system")
+
+ @staticmethod
+ def process_to_unit(process):
+ cmd = ['systemctl', 'status', "%d" % process.pid]
+ systemctl_status = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ output = systemctl_status.communicate()[0]
+ if systemctl_status.returncode:
+ return None
+ else:
+ return output.split()[0]