Module: check_mk
Branch: master
Commit: 2ff93a5c27a5071b64f03316bae5ccfeabd7a18f
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=2ff93a5c27a507…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Mon Jul 2 10:35:46 2018 +0200
6283 New mode "omd cleanup" for removing unused Check_MK versions
---
.werks/6283 | 10 +++
omd/packages/omd/bash_completion | 2 +-
omd/packages/omd/omd | 161 +++++++++++++++++++++++++++++++++++++--
omd/packages/omd/omd.8 | 10 +++
4 files changed, 177 insertions(+), 6 deletions(-)
diff --git a/.werks/6283 b/.werks/6283
new file mode 100644
index 0000000..ef6a175
--- /dev/null
+++ b/.werks/6283
@@ -0,0 +1,10 @@
+Title: New mode "omd cleanup" for removing unused Check_MK versions
+Level: 2
+Component: omd
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1530520505
+Class: feature
+
+
diff --git a/omd/packages/omd/bash_completion b/omd/packages/omd/bash_completion
index e880413..71f2e89 100644
--- a/omd/packages/omd/bash_completion
+++ b/omd/packages/omd/bash_completion
@@ -18,7 +18,7 @@ _omd()
{
local GLOBALCMDS="sites|version|versions|help"
local SITECMDS="start|stop|restart|reload|status|update|config|backup|restore|diff"
- local ROOTCMDS="create|setversion"
+ local ROOTCMDS="create|setversion|cleanup"
local ROOTSITECMDS="rm|mv|cp|disable|enable|init|su"
COMPREPLY=()
diff --git a/omd/packages/omd/omd b/omd/packages/omd/omd
index bac0d7f..4862ea9 100644
--- a/omd/packages/omd/omd
+++ b/omd/packages/omd/omd
@@ -51,6 +51,7 @@ if len(sys.argv) > 1 and sys.argv[1] == "update" \
import sys, os, shutil, pwd, grp, re, time, pprint, tty, termios, traceback
+import abc
import fcntl
import string
import random
@@ -404,11 +405,11 @@ def groupdel(groupname):
stdin=open(os.devnull, "r"), stdout=open(os.devnull, "w"),
stderr=subprocess.PIPE, close_fds=True)
except OSError, e:
- bail_out("\n" + tty_error + ": Failed to delete user '%s': %s" % (groupname, e))
+ bail_out("\n" + tty_error + ": Failed to delete group '%s': %s" % (groupname, e))
stderr = p.communicate()[1]
if p.returncode != 0:
- bail_out("\n" + tty_error + ": Failed to delete user '%s': %s" % (groupname, stderr))
+ bail_out("\n" + tty_error + ": Failed to delete group '%s': %s" % (groupname, stderr))
def groupadd(groupname, gid = None):
cmd = "groupadd "
@@ -2582,9 +2583,13 @@ def default_version():
return os.path.basename(os.path.realpath("/omd/versions/default"))
def omd_versions():
- v = [ v for v in os.listdir("/omd/versions") if v != "default" ]
- v.sort()
- return v
+ try:
+ return sorted([ v for v in os.listdir("/omd/versions") if v != "default" ])
+ except OSError, e:
+ if e.errno == 2:
+ return []
+ else:
+ raise
def version_exists(v):
return v in omd_versions()
@@ -3860,6 +3865,146 @@ def postprocess_restore_as_site_user(options, orig_apache_port):
finalize_size_as_user("restore")
+
+def main_cleanup(args, options=None):
+ if options is None:
+ options = {}
+
+ package_manager = PackageManager.factory()
+ if package_manager is None:
+ bail_out("Command is not supported on this platform")
+
+ for version in omd_versions():
+ site_ids = [ s for s in all_sites() if site_version(s) == version ]
+ if site_ids:
+ sys.stdout.write("%s%-20s%s In use (by %s). Keeping this version.\n" %
+ (tty_bold, version, tty_normal, ", ".join(site_ids)))
+ continue
+
+ version_path = os.path.join("/omd/versions", version)
+
+ packages = package_manager.find_packages_of_path(version_path)
+ if len(packages) != 1:
+ sys.stdout.write("%s%-20s%s Could not determine package. Keeping this version.\n" %
+ (tty_bold, version, tty_normal))
+ continue
+
+ sys.stdout.write("%s%-20s%s Uninstalling\n" % (tty_bold, version, tty_normal))
+ package_manager.uninstall(packages[0])
+
+ # In case there were modifications made to the version the uninstall may leave
+ # some files behind. Remove the whole version directory
+ if os.path.exists(version_path):
+ shutil.rmtree(version_path)
+
+
+ # In case the last version has been removed ensure some things created globally
+ # are removed.
+ if not omd_versions():
+ _cleanup_global_files()
+
+
+def _cleanup_global_files():
+ sys.stdout.write("No version left. Cleaning up global files.\n")
+ shutil.rmtree(g_info["OMD_PHYSICAL_BASE"], ignore_errors=True)
+
+ for path in [
+ "/omd",
+ g_info["APACHE_CONF_DIR"] + "/zzz_omd.conf",
+ "/etc/init.d/omd",
+ "/usr/bin/omd",
+ ]:
+ try:
+ os.unlink(path)
+ except OSError, e:
+ if e.errno == 2:
+ pass
+ else:
+ raise
+
+ if group_exists("omd"):
+ groupdel("omd")
+
+
+
+class PackageManager:
+ __metaclass__ = abc.ABCMeta
+
+ @classmethod
+ def factory(self):
+ if os.path.exists("/etc/cma"):
+ return
+
+ distro_code = g_info["DISTRO_CODE"]
+ if distro_code.startswith("el") \
+ or distro_code.startswith("sles"):
+ cls = PackageManagerRPM
+ else:
+ cls = PackageManagerDEB
+
+ return cls()
+
+
+ @abc.abstractmethod
+ def uninstall(self, cmd):
+ p = self._execute(cmd)
+ output = p.communicate()[0]
+ if p.wait() != 0:
+ bail_out("Failed to uninstall package:\n%s" % output)
+
+
+ def _execute(self, cmd):
+ if opt_verbose:
+ sys.stdout.write("Executing: %s\n" % subprocess.list2cmdline(cmd))
+
+ return subprocess.Popen(cmd, shell=False, close_fds=True,
+ stdin=open(os.devnull), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+
+
+class PackageManagerDEB(PackageManager):
+ def uninstall(self, package_name):
+ return super(PackageManagerDEB, self).uninstall(
+ ["apt-get", "-y", "purge", package_name])
+
+
+ def find_packages_of_path(self, path):
+ real_path = os.path.realpath(path)
+
+ p = self._execute(["dpkg", "-S", real_path])
+ output = p.communicate()[0]
+ if p.wait() != 0:
+ bail_out("Failed to find packages:\n%s" % output)
+
+ for line in output.split("\n"):
+ if line.endswith(": %s" % real_path):
+ return line.split(": ", 1)[0].split(", ")
+
+ return []
+
+
+
+class PackageManagerRPM(PackageManager):
+ def uninstall(self, package_name):
+ return super(PackageManagerRPM, self).uninstall(
+ ["rpm", "-e", package_name])
+
+
+ def find_packages_of_path(self, path):
+ real_path = os.path.realpath(path)
+
+ p = self._execute(["rpm", "-qf", real_path])
+ output = p.communicate()[0]
+
+ if p.wait() == 1 and "not owned" in output:
+ return []
+
+ elif p.wait() != 0:
+ bail_out("Failed to find packages:\n%s" % stderr)
+
+ return output.strip().split("\n")
+
+
exclude_options = [
( "no-rrds", None, False, "do not copy RRD files (performance data)"),
( "no-logs", None, False, "do not copy the monitoring history and log files"),
@@ -4071,6 +4216,12 @@ commands = [
],
"Restores the backup of a site to an existing site or creates a new site",
""),
+
+ ( "cleanup", True, False, 0, 0, False, "", main_cleanup,
+ [ ],
+ "Uninstall all Check_MK versions that are not used by any site.",
+ ""),
+
]
def handle_global_option(opt, orig):
diff --git a/omd/packages/omd/omd.8 b/omd/packages/omd/omd.8
index 8aa60d4..b3b155a 100644
--- a/omd/packages/omd/omd.8
+++ b/omd/packages/omd/omd.8
@@ -452,6 +452,16 @@ section about \fBomd update\fP for details.
the available RAM at max. When providing the \fB-t\fP option together with the SIZE
given as absolute value of e.g. \fB500M\fP or percentage value like \fB10%\fP the
maximum size of the tmpfs can be changed.
+.TP
+.B omd cleanup
+This removes all Check_MK versions that are currently not used by any site. All
+installed versions are checked for the number of sites that use this version. The
+versions without sites will be removed by deinstalling the RPM/DEB package of this
+version.
+
+Note: The whole version directory \fB/omd/version/[version]\fP will be removed. Even
+when there are files left after deinstallation of the RPM/DEB package. OMD will cleanup
+the whole directory tree.
.SH SEE ALSO
.BR http://www.omdistro.org