aboutsummaryrefslogtreecommitdiff
path: root/whatmaps
diff options
context:
space:
mode:
Diffstat (limited to 'whatmaps')
-rwxr-xr-xwhatmaps/command.py42
-rw-r--r--whatmaps/debiandistro.py59
-rw-r--r--whatmaps/debianpkg.py6
-rw-r--r--whatmaps/distro.py32
-rw-r--r--whatmaps/pkg.py5
-rw-r--r--whatmaps/process.py1
-rw-r--r--whatmaps/redhatdistro.py8
-rw-r--r--whatmaps/rpmpkg.py5
-rw-r--r--whatmaps/systemd.py3
9 files changed, 106 insertions, 55 deletions
diff --git a/whatmaps/command.py b/whatmaps/command.py
index 0f8e433..e28a8b9 100755
--- a/whatmaps/command.py
+++ b/whatmaps/command.py
@@ -17,7 +17,6 @@
#
-
import errno
import glob
import os
@@ -30,15 +29,16 @@ from . distro import Distro
from . pkg import PkgError
from . systemd import Systemd
+
def check_maps(procs, shared_objects):
restart_procs = {}
for proc in procs:
for so in shared_objects:
if proc.maps(so):
if proc.exe in restart_procs:
- restart_procs[proc.exe] += [ proc ]
+ restart_procs[proc.exe] += [proc]
else:
- restart_procs[proc.exe] = [ proc ]
+ restart_procs[proc.exe] = [proc]
break
return restart_procs
@@ -78,7 +78,7 @@ def find_pkgs(procs, distro):
if pkg.name in pkgs:
pkgs[pkg.name].procs.append(proc)
else:
- pkg.procs = [ proc ]
+ pkg.procs = [proc]
pkgs[pkg.name] = pkg
if pkgs:
@@ -117,21 +117,32 @@ def find_systemd_units(procmap, distro):
try:
unit = Systemd.process_to_unit(proc)
except ValueError as e:
- logging.warning("No systemd unit found for '%s': %s"
+ logging.warning("No systemd unit found for '%s': %s "
"- restart manually" % (proc.exe, e))
continue
if not unit:
- logging.warning("No systemd unit found for '%s'"
+ 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 ])
+ units -= set([service + '.service' for service in distro.service_blacklist])
return units
+def filter_services(distro, services):
+ filtered = distro.filter_services(services)
+ diff = services - filtered
+ if len(diff):
+ logging.warning("Filtered out blacklisted service%s %s - restart manually",
+ 's' if len(diff) > 1 else '',
+ ', '.join(diff))
+ return filtered
+
+
def main(argv):
shared_objects = []
services = None
+ ret = 0
parser = OptionParser(usage='%prog [options] pkg1 [pkg2 pkg3 pkg4]')
parser.add_option("--debug", action="store_true", dest="debug",
@@ -157,7 +168,7 @@ def main(argv):
logging.basicConfig(level=level,
format='%(levelname)s: %(message)s')
- distro = Distro.detect()
+ distro = Distro.detect()()
if not distro:
logging.error("Unsupported Distribution")
return 1
@@ -165,7 +176,7 @@ def main(argv):
logging.debug("Detected distribution: '%s'", distro.id)
if args:
- pkgs = [ distro.pkg(arg) for arg in args ]
+ pkgs = [distro.pkg(arg) for arg in args]
elif options.apt and distro.has_apt():
try:
pkgs = distro.read_apt_pipeline()
@@ -174,7 +185,9 @@ def main(argv):
return 1
if not pkgs:
return 0
- pkgs = distro.filter_security_updates(pkgs)
+ pkgs, notfound = distro.filter_security_updates(pkgs)
+ if notfound:
+ logging.warning("Pkgs %s not found in apt cache" % ", ".join(notfound))
logging.debug("Security Upgrades: %s" % pkgs)
else:
parser.print_help()
@@ -185,8 +198,8 @@ def main(argv):
try:
shared_objects += pkg.shared_objects
except PkgError:
- logging.error("Cannot parse contents of %s" % pkg.name)
- return 1
+ logging.error("Cannot parse contents of %s - skipping it" % pkg.name)
+ ret = 1
logging.debug("Found shared objects:")
for so in shared_objects:
logging.debug(" %s", so)
@@ -226,6 +239,8 @@ def main(argv):
else:
return 0
+ services = filter_services(distro, services)
+
if options.restart:
if options.print_cmds and services:
write_cmd_file(services, options.print_cmds, distro)
@@ -238,7 +253,8 @@ def main(argv):
for s in services:
print(s)
- return 0
+ return ret
+
def run():
return(main(sys.argv))
diff --git a/whatmaps/debiandistro.py b/whatmaps/debiandistro.py
index 32f3774..4fcce54 100644
--- a/whatmaps/debiandistro.py
+++ b/whatmaps/debiandistro.py
@@ -36,30 +36,37 @@ from . debianpkg import DebianPkg
from . pkg import PkgError
from . systemd import Systemd
+
class DebianDistro(Distro):
"Debian (dpkg) based distribution"
id = 'Debian'
- _pkg_services = { 'apache2-mpm-worker': [ 'apache2' ],
- 'apache2-mpm-prefork': [ 'apache2' ],
- 'apache2.2-bin': [ 'apache2' ],
- 'apache2-bin': [ 'apache2' ],
- 'dovecot-imapd': [ 'dovecot' ],
- 'dovecot-pop3d': [ 'dovecot' ],
- 'exim4-daemon-light': [ 'exim4' ],
- 'exim4-daemon-heavy': [ 'exim4' ],
- 'libvirt-daemon': [ 'libvirtd' ],
- 'openjdk-6-jre-headless': ['jenkins', 'tomcat7'],
- 'openjdk-7-jre-headless': ['jenkins', 'tomcat7'],
- 'qemu-system-x86_64': [ 'libvirt-guests' ],
- }
+ _pkg_services = {
+ 'apache2-mpm-worker': ['apache2'],
+ 'apache2-mpm-prefork': ['apache2'],
+ 'apache2.2-bin': ['apache2'],
+ 'apache2-bin': ['apache2'],
+ 'dovecot-imapd': ['dovecot'],
+ 'dovecot-pop3d': ['dovecot'],
+ 'exim4-daemon-light': ['exim4'],
+ 'exim4-daemon-heavy': ['exim4'],
+ 'libvirt-daemon': ['libvirtd'],
+ 'openjdk-6-jre-headless': ['jenkins', 'tomcat7'],
+ 'openjdk-7-jre-headless': ['jenkins', 'tomcat7'],
+ 'qemu-system-x86_64': ['libvirt-guests'],
+ }
# Per package blacklist
- _pkg_service_blacklist = { 'libvirt-bin': [ 'libvirt-guests' ] }
+ _pkg_service_blacklist = {'libvirt-bin': ['libvirt-guests']}
# Per distro blacklist
service_blacklist = set(['kvm', 'qemu-kvm', 'qemu-system-x86'])
+ # Per distro regex filter
+ service_blacklist_re = set([
+ '^user@[0-9]+.service$', # Restarting systemd user service aborts the session
+ ])
+
@classmethod
def pkg(klass, name):
return DebianPkg(name)
@@ -67,8 +74,8 @@ class DebianDistro(Distro):
@classmethod
def pkg_by_file(klass, path):
find_file = subprocess.Popen(['dpkg-query', '-S', path],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
output = find_file.communicate()[0]
if find_file.returncode:
return None
@@ -124,12 +131,11 @@ class DebianDistro(Distro):
(pkgname, oldversion, compare, newversion, filename) = line.split()
if filename == '**CONFIGURE**':
- if oldversion != '-': # Updates only
+ if oldversion != '-': # Updates only
pkgs[pkgname] = DebianPkg(pkgname)
pkgs[pkgname].version = newversion
return pkgs
-
@classmethod
def _security_update_origins(klass):
"Determine security update origins from apt configuration"
@@ -138,9 +144,10 @@ class DebianDistro(Distro):
raise PkgError("lsb_release not found, can't determine security updates")
codename = lsb_release.get_distro_information()['CODENAME']
+
def _subst(line):
- mapping = {'distro_codename' : codename,
- 'distro_id' : klass.id, }
+ mapping = {'distro_codename': codename,
+ 'distro_id': klass.id, }
return string.Template(line).substitute(mapping)
origins = []
@@ -151,7 +158,6 @@ class DebianDistro(Distro):
logging.debug("Security Update Origins: %s", origins)
return origins
-
@classmethod
def filter_security_updates(klass, pkgs):
"""Filter on security updates"""
@@ -160,14 +166,19 @@ class DebianDistro(Distro):
raise PkgError("apt_pkg not installed, can't determine security updates")
apt_pkg.init()
- acquire = apt_pkg.Acquire()
+ apt_pkg.Acquire()
cache = apt_pkg.Cache()
security_update_origins = klass._security_update_origins()
security_updates = {}
+ notfound = []
for pkg in list(pkgs.values()):
- cache_pkg = cache[pkg.name]
+ try:
+ cache_pkg = cache[pkg.name]
+ except KeyError:
+ notfound.append(pkg)
+ continue
for cache_version in cache_pkg.version_list:
if pkg.version == cache_version.ver_str:
for pfile, _ in cache_version.file_list:
@@ -176,4 +187,4 @@ class DebianDistro(Distro):
pfile.archive == origin[1]:
security_updates[pkg] = pkg
break
- return security_updates
+ return (security_updates, notfound)
diff --git a/whatmaps/debianpkg.py b/whatmaps/debianpkg.py
index 8a3349d..0192513 100644
--- a/whatmaps/debianpkg.py
+++ b/whatmaps/debianpkg.py
@@ -19,17 +19,18 @@ import re
from . pkg import Pkg
+
class DebianPkg(Pkg):
type = 'Debian'
_init_script_re = re.compile('/etc/init.d/[\w\-\.]')
- _list_contents = ['dpkg-query', '-L', '${pkg_name}' ]
+ _list_contents = ['dpkg-query', '-L', '${pkg_name}']
def __init__(self, name):
Pkg.__init__(self, name)
@property
def services(self):
- if self._services != None:
+ if self._services is not None:
return self._services
self._services = []
@@ -39,4 +40,3 @@ class DebianPkg(Pkg):
if self._init_script_re.match(line):
self._services.append(os.path.basename(line.strip()))
return self._services
-
diff --git a/whatmaps/distro.py b/whatmaps/distro.py
index f0f08eb..29d2dc2 100644
--- a/whatmaps/distro.py
+++ b/whatmaps/distro.py
@@ -17,6 +17,7 @@
import logging
import os
+import re
import subprocess
@@ -25,6 +26,7 @@ try:
except ImportError:
lsb_release = None
+
class Distro(object):
"""
A distribution
@@ -32,6 +34,8 @@ class Distro(object):
@cvar id: distro id as returned by lsb-release
@cvar service_blacklist: services that should never be restarted
+ @cvar service_blacklist_re: regex list of services that should
+ never be restartet
@cvar _pkg_services: A C{dict} that maps packages to services. In
case we find binaries that match a key in this hash restart
the services listed in values.
@@ -40,6 +44,8 @@ class Distro(object):
"""
id = None
service_blacklist = set()
+ service_blacklist_re = set()
+
_pkg_services = {}
_pkg_blacklist = {}
_pkg_service_blacklist = {}
@@ -75,8 +81,8 @@ class Distro(object):
List of services that package pkg needs restarted that aren't part
of pkg itself
"""
- return [ s for s in klass._pkg_services.get(pkg.name, [])
- if klass.is_service_installed(s) ]
+ return [s for s in klass._pkg_services.get(pkg.name, [])
+ if klass.is_service_installed(s)]
@classmethod
def pkg_service_blacklist(klass, pkg):
@@ -86,6 +92,17 @@ class Distro(object):
"""
return klass._pkg_service_blacklist.get(pkg.name, [])
+ def filter_services(self, services):
+ """
+ Filter out servies that match service_blacklist_re
+ """
+ ret = []
+ matchers = [re.compile(b) for b in self.service_blacklist_re]
+ for s in services:
+ if not any([m.match(s) for m in matchers]):
+ ret.append(s)
+ return set(ret)
+
@classmethod
def has_apt(klass):
"""Does the distribution use apt"""
@@ -95,8 +112,9 @@ class Distro(object):
def detect():
return detect()
-import whatmaps.debiandistro
-import whatmaps.redhatdistro
+import whatmaps.debiandistro # noqa: E402
+import whatmaps.redhatdistro # noqa: E402
+
def detect():
"""
@@ -110,11 +128,11 @@ def detect():
else:
try:
lsb_cmd = subprocess.Popen(['lsb_release', '--id', '-s'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
output = lsb_cmd.communicate()[0]
if not lsb_cmd.returncode:
- id = output.strip()
+ id = output.strip()
except OSError:
# id is None in this case
pass
diff --git a/whatmaps/pkg.py b/whatmaps/pkg.py
index 4290d0b..7aafd5a 100644
--- a/whatmaps/pkg.py
+++ b/whatmaps/pkg.py
@@ -19,6 +19,7 @@ import re
import string
import subprocess
+
class PkgError(Exception):
pass
@@ -55,8 +56,8 @@ class Pkg(object):
if self._contents:
return self._contents
else:
- cmd = [ string.Template(arg).substitute(arg, pkg_name=self.name)
- for arg in self._list_contents ]
+ cmd = [string.Template(arg).substitute(arg, pkg_name=self.name)
+ for arg in self._list_contents]
list_contents = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
diff --git a/whatmaps/process.py b/whatmaps/process.py
index a39da89..78165a7 100644
--- a/whatmaps/process.py
+++ b/whatmaps/process.py
@@ -20,6 +20,7 @@ import logging
import os
import re
+
class Process(object):
"""A process - Linux only so far, needs /proc mounted"""
deleted_re = re.compile(r"(?P<exe>.*) \(deleted\)$")
diff --git a/whatmaps/redhatdistro.py b/whatmaps/redhatdistro.py
index 0427c30..4b17f3c 100644
--- a/whatmaps/redhatdistro.py
+++ b/whatmaps/redhatdistro.py
@@ -21,10 +21,11 @@ import subprocess
from . distro import Distro
from . rpmpkg import RpmPkg
+
class RedHatDistro(Distro):
"RPM based distribution"""
_pkg_re = re.compile(r'(?P<pkg>[\w\-\+]+)-(?P<ver>[\w\.]+)'
- '-(?P<rel>[\w\.]+)\.(?P<arch>.+)')
+ '-(?P<rel>[\w\.]+)\.(?P<arch>.+)')
@classmethod
def pkg(klass, name):
@@ -33,8 +34,8 @@ class RedHatDistro(Distro):
@classmethod
def pkg_by_file(klass, path):
find_file = subprocess.Popen(['rpm', '-qf', path],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
output = find_file.communicate()[0]
if find_file.returncode:
return None
@@ -52,4 +53,3 @@ class RedHatDistro(Distro):
class FedoraDistro(RedHatDistro):
id = 'Fedora'
-
diff --git a/whatmaps/rpmpkg.py b/whatmaps/rpmpkg.py
index 595edd2..493dd5a 100644
--- a/whatmaps/rpmpkg.py
+++ b/whatmaps/rpmpkg.py
@@ -19,17 +19,18 @@ import re
from . pkg import Pkg
+
class RpmPkg(Pkg):
type = 'RPM'
_init_script_re = re.compile('/etc/rc.d/init.d/[\w\-\.]')
- _list_contents = [ 'rpm', '-ql', '$pkg_name' ]
+ _list_contents = ['rpm', '-ql', '$pkg_name']
def __init__(self, name):
Pkg.__init__(self, name)
@property
def services(self):
- if self._services != None:
+ if self._services is not None:
return self._services
self._services = []
diff --git a/whatmaps/systemd.py b/whatmaps/systemd.py
index 9bc03b1..d4f45fe 100644
--- a/whatmaps/systemd.py
+++ b/whatmaps/systemd.py
@@ -43,5 +43,8 @@ class Systemd(object):
return parts[0]
elif parts[1].endswith('.service'):
return parts[1]
+ elif parts[1].startswith('session-') and parts[1].endswith('.scope'):
+ msg = output.decode('utf-8').split('\n')[0][2:]
+ raise ValueError("Can't parse service name from %s" % msg)
else:
raise ValueError("Can't parse service name from: (%s %s)" % (parts[0], parts[1]))