diff options
author | Jake Hunsaker <jhunsake@redhat.com> | 2020-12-17 16:08:54 -0500 |
---|---|---|
committer | Jake Hunsaker <jhunsake@redhat.com> | 2021-01-04 11:55:11 -0500 |
commit | d48660eef94d906831a38fd16e7a0f3791228242 (patch) | |
tree | 982734d18d13d05efcc6d2f3c458df7703c0ed99 | |
parent | db398cc11daa7d3d06f245162787a3982323f573 (diff) | |
download | sos-d48660eef94d906831a38fd16e7a0f3791228242.tar.gz |
[ContainerRuntime] Separate runtimes from policies
Moves `ContainerRuntime` and the related subclasses out from
`sos/policies/__init__.py` into a new `sos/policies/runtimes` subdir.
Related: #2349
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r-- | sos/policies/__init__.py | 182 | ||||
-rw-r--r-- | sos/policies/runtimes/__init__.py | 173 | ||||
-rw-r--r-- | sos/policies/runtimes/docker.py | 30 | ||||
-rw-r--r-- | sos/policies/runtimes/podman.py | 21 |
4 files changed, 226 insertions, 180 deletions
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py index 7f140613..ee466c95 100644 --- a/sos/policies/__init__.py +++ b/sos/policies/__init__.py @@ -12,12 +12,13 @@ from getpass import getpass from pwd import getpwuid from sos.utilities import (ImporterHelper, import_module, - is_executable, shell_out, sos_get_command_output, get_human_readable) from sos.report.plugins import IndependentPlugin, ExperimentalPlugin from sos.options import SoSOptions +from sos.policies.runtimes.docker import DockerContainerRuntime +from sos.policies.runtimes.podman import PodmanContainerRuntime from sos import _sos as _ from textwrap import fill from pipes import quote @@ -59,185 +60,6 @@ def load(cache={}, sysroot=None, init=None, probe_runtime=True, return cache['policy'] -class ContainerRuntime(object): - """Encapsulates a container runtime that provides the ability to plugins to - check runtime status, check for the presence of specific containers, and - to format commands to run in those containers - - :param policy: The loaded policy for the system - :type policy: ``Policy()`` - - :cvar name: The name of the container runtime, e.g. 'podman' - :vartype name: ``str`` - - :cvar containers: A list of containers known to the runtime - :vartype containers: ``list`` - - :cvar images: A list of images known to the runtime - :vartype images: ``list`` - - :cvar binary: The binary command to run for the runtime, must exit within - $PATH - :vartype binary: ``str`` - """ - - name = 'Undefined' - containers = [] - images = [] - volumes = [] - binary = '' - active = False - - def __init__(self, policy=None): - self.policy = policy - self.run_cmd = "%s exec " % self.binary - - def load_container_info(self): - """If this runtime is found to be active, attempt to load information - on the objects existing in the runtime. - """ - self.containers = self.get_containers() - self.images = self.get_images() - self.volumes = self.get_volumes() - - def check_is_active(self): - """Check to see if the container runtime is both present AND active. - - Active in this sense means that the runtime can be used to glean - information about the runtime itself and containers that are running. - - :returns: ``True`` if the runtime is active, else ``False`` - :rtype: ``bool`` - """ - if is_executable(self.binary): - self.active = True - return True - return False - - def get_containers(self, get_all=False): - """Get a list of containers present on the system. - - :param get_all: If set, include stopped containers as well - :type get_all: ``bool`` - """ - containers = [] - _cmd = "%s ps %s" % (self.binary, '-a' if get_all else '') - if self.active: - out = sos_get_command_output(_cmd) - if out['status'] == 0: - for ent in out['output'].splitlines()[1:]: - ent = ent.split() - # takes the form (container_id, container_name) - containers.append((ent[0], ent[-1])) - return containers - - def get_container_by_name(self, name): - """Get the container ID for the container matching the provided - name - - :param name: The name of the container, note this can be a regex - :type name: ``str`` - - :returns: The id of the first container to match `name`, else ``None`` - :rtype: ``str`` - """ - if not self.active or name is None: - return None - for c in self.containers: - if re.match(name, c[1]): - return c[1] - return None - - def get_images(self): - """Get a list of images present on the system - - :returns: A list of 2-tuples containing (image_name, image_id) - :rtype: ``list`` - """ - images = [] - fmt = '{{lower .Repository}}:{{lower .Tag}} {{lower .ID}}' - if self.active: - out = sos_get_command_output("%s images --format '%s'" - % (self.binary, fmt)) - if out['status'] == 0: - for ent in out['output'].splitlines(): - ent = ent.split() - # takes the form (image_name, image_id) - images.append((ent[0], ent[1])) - return images - - def get_volumes(self): - """Get a list of container volumes present on the system - - :returns: A list of volume IDs on the system - :rtype: ``list`` - """ - vols = [] - if self.active: - out = sos_get_command_output("%s volume ls" % self.binary) - if out['status'] == 0: - for ent in out['output'].splitlines()[1:]: - ent = ent.split() - vols.append(ent[-1]) - return vols - - def fmt_container_cmd(self, container, cmd, quotecmd): - """Format a command to run inside a container using the runtime - - :param container: The name or ID of the container in which to run - :type container: ``str`` - - :param cmd: The command to run inside `container` - :type cmd: ``str`` - - :param quotecmd: Whether the cmd should be quoted. - :type quotecmd: ``bool`` - - :returns: Formatted string to run `cmd` inside `container` - :rtype: ``str`` - """ - if quotecmd: - quoted_cmd = quote(cmd) - else: - quoted_cmd = cmd - return "%s %s %s" % (self.run_cmd, container, quoted_cmd) - - def get_logs_command(self, container): - """Get the command string used to dump container logs from the - runtime - - :param container: The name or ID of the container to get logs for - :type container: ``str`` - - :returns: Formatted runtime command to get logs from `container` - :type: ``str`` - """ - return "%s logs -t %s" % (self.binary, container) - - -class DockerContainerRuntime(ContainerRuntime): - """Runtime class to use for systems running Docker""" - - name = 'docker' - binary = 'docker' - - def check_is_active(self): - # the daemon must be running - if (is_executable('docker') and - (self.policy.init_system.is_running('docker') or - self.policy.init_system.is_running('snap.docker.dockerd'))): - self.active = True - return True - return False - - -class PodmanContainerRuntime(ContainerRuntime): - """Runtime class to use for systems running Podman""" - - name = 'podman' - binary = 'podman' - - class InitSystem(object): """Encapsulates an init system to provide service-oriented functions to sos. diff --git a/sos/policies/runtimes/__init__.py b/sos/policies/runtimes/__init__.py new file mode 100644 index 00000000..1a61b644 --- /dev/null +++ b/sos/policies/runtimes/__init__.py @@ -0,0 +1,173 @@ +# Copyright (C) 2020 Red Hat, Inc., Jake Hunsaker <jhunsake@redhat.com> + +# This file is part of the sos project: https://github.com/sosreport/sos +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# version 2 of the GNU General Public License. +# +# See the LICENSE file in the source distribution for further information. + +import re + +from pipes import quote +from sos.utilities import sos_get_command_output, is_executable + + +class ContainerRuntime(): + """Encapsulates a container runtime that provides the ability to plugins to + check runtime status, check for the presence of specific containers, and + to format commands to run in those containers + + :param policy: The loaded policy for the system + :type policy: ``Policy()`` + + :cvar name: The name of the container runtime, e.g. 'podman' + :vartype name: ``str`` + + :cvar containers: A list of containers known to the runtime + :vartype containers: ``list`` + + :cvar images: A list of images known to the runtime + :vartype images: ``list`` + + :cvar binary: The binary command to run for the runtime, must exit within + $PATH + :vartype binary: ``str`` + """ + + name = 'Undefined' + containers = [] + images = [] + volumes = [] + binary = '' + active = False + + def __init__(self, policy=None): + self.policy = policy + self.run_cmd = "%s exec " % self.binary + + def load_container_info(self): + """If this runtime is found to be active, attempt to load information + on the objects existing in the runtime. + """ + self.containers = self.get_containers() + self.images = self.get_images() + self.volumes = self.get_volumes() + + def check_is_active(self): + """Check to see if the container runtime is both present AND active. + + Active in this sense means that the runtime can be used to glean + information about the runtime itself and containers that are running. + + :returns: ``True`` if the runtime is active, else ``False`` + :rtype: ``bool`` + """ + if is_executable(self.binary): + self.active = True + return True + return False + + def get_containers(self, get_all=False): + """Get a list of containers present on the system. + + :param get_all: If set, include stopped containers as well + :type get_all: ``bool`` + """ + containers = [] + _cmd = "%s ps %s" % (self.binary, '-a' if get_all else '') + if self.active: + out = sos_get_command_output(_cmd) + if out['status'] == 0: + for ent in out['output'].splitlines()[1:]: + ent = ent.split() + # takes the form (container_id, container_name) + containers.append((ent[0], ent[-1])) + return containers + + def get_container_by_name(self, name): + """Get the container ID for the container matching the provided + name + + :param name: The name of the container, note this can be a regex + :type name: ``str`` + + :returns: The id of the first container to match `name`, else ``None`` + :rtype: ``str`` + """ + if not self.active or name is None: + return None + for c in self.containers: + if re.match(name, c[1]): + return c[1] + return None + + def get_images(self): + """Get a list of images present on the system + + :returns: A list of 2-tuples containing (image_name, image_id) + :rtype: ``list`` + """ + images = [] + fmt = '{{lower .Repository}}:{{lower .Tag}} {{lower .ID}}' + if self.active: + out = sos_get_command_output("%s images --format '%s'" + % (self.binary, fmt)) + if out['status'] == 0: + for ent in out['output'].splitlines(): + ent = ent.split() + # takes the form (image_name, image_id) + images.append((ent[0], ent[1])) + return images + + def get_volumes(self): + """Get a list of container volumes present on the system + + :returns: A list of volume IDs on the system + :rtype: ``list`` + """ + vols = [] + if self.active: + out = sos_get_command_output("%s volume ls" % self.binary) + if out['status'] == 0: + for ent in out['output'].splitlines()[1:]: + ent = ent.split() + vols.append(ent[-1]) + return vols + + def fmt_container_cmd(self, container, cmd, quotecmd): + """Format a command to run inside a container using the runtime + + :param container: The name or ID of the container in which to run + :type container: ``str`` + + :param cmd: The command to run inside `container` + :type cmd: ``str`` + + :param quotecmd: Whether the cmd should be quoted. + :type quotecmd: ``bool`` + + :returns: Formatted string to run `cmd` inside `container` + :rtype: ``str`` + """ + if quotecmd: + quoted_cmd = quote(cmd) + else: + quoted_cmd = cmd + return "%s %s %s" % (self.run_cmd, container, quoted_cmd) + + def get_logs_command(self, container): + """Get the command string used to dump container logs from the + runtime + + :param container: The name or ID of the container to get logs for + :type container: ``str`` + + :returns: Formatted runtime command to get logs from `container` + :type: ``str`` + """ + return "%s logs -t %s" % (self.binary, container) + + +# vim: set et ts=4 sw=4 : diff --git a/sos/policies/runtimes/docker.py b/sos/policies/runtimes/docker.py new file mode 100644 index 00000000..759dfaf6 --- /dev/null +++ b/sos/policies/runtimes/docker.py @@ -0,0 +1,30 @@ +# Copyright (C) 2020 Red Hat, Inc., Jake Hunsaker <jhunsake@redhat.com> + +# This file is part of the sos project: https://github.com/sosreport/sos +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# version 2 of the GNU General Public License. +# +# See the LICENSE file in the source distribution for further information. + +from sos.policies.runtimes import ContainerRuntime +from sos.utilities import is_executable + + +class DockerContainerRuntime(ContainerRuntime): + """Runtime class to use for systems running Docker""" + + name = 'docker' + binary = 'docker' + + def check_is_active(self): + # the daemon must be running + if (is_executable('docker') and + (self.policy.init_system.is_running('docker') or + self.policy.init_system.is_running('snap.docker.dockerd'))): + self.active = True + return True + return False + +# vim: set et ts=4 sw=4 : diff --git a/sos/policies/runtimes/podman.py b/sos/policies/runtimes/podman.py new file mode 100644 index 00000000..ef53ce2e --- /dev/null +++ b/sos/policies/runtimes/podman.py @@ -0,0 +1,21 @@ +# Copyright (C) 2020 Red Hat, Inc., Jake Hunsaker <jhunsake@redhat.com> + +# This file is part of the sos project: https://github.com/sosreport/sos +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# version 2 of the GNU General Public License. +# +# See the LICENSE file in the source distribution for further information. + +from sos.policies.runtimes import ContainerRuntime + + +class PodmanContainerRuntime(ContainerRuntime): + """Runtime class to use for systems running Podman""" + + name = 'podman' + binary = 'podman' + + +# vim: set et ts=4 sw=4 : |