From 5cd6d894d5de22308a689ccc2fc44ebe6e181697 Mon Sep 17 00:00:00 2001 From: Jake Hunsaker Date: Thu, 21 Nov 2019 15:17:02 -0500 Subject: [Plugin] Integrate ContainerRuntime in Plugin API Integrates the ContainerRuntime checks to the Plugin API - `Plugin.exec_cmd()` now accepts a `container` argument that, if set, will first check to see if the container exists and if it does, format the requested command to be executed by the runtime in the selected container. If the runtime is not available, or the container does not exist, the command is not run. Additionally adds a `container_exists()` call to check to see if a container is present/running, and a `fmt_container_cmd()` call that wraps the `ContainerRuntime` method to allow for easy formatting of commands for `add_cmd_output()` calls. Closes: #1866 Signed-off-by: Jake Hunsaker --- sos/plugins/__init__.py | 102 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py index 779e4be2..89ef915a 100644 --- a/sos/plugins/__init__.py +++ b/sos/plugins/__init__.py @@ -1379,28 +1379,120 @@ class Plugin(object): def exec_cmd(self, cmd, timeout=cmd_timeout, stderr=True, chroot=True, runat=None, env=None, binary=False, pred=None, - foreground=False): + foreground=False, container=False): """Execute a command right now and return the output and status, but do not save the output within the archive. Use this method in a plugin's setup() if command output is needed to build subsequent commands added to a report via add_cmd_output(). """ + _default = {'status': None, 'output': ''} if not self.test_predicate(cmd=True, pred=pred): - return { - 'status': None, - 'output': '' - } + return _default if chroot or self.commons['cmdlineopts'].chroot == 'always': root = self.sysroot else: root = None + if container: + if self._get_container_runtime() is None: + self._log_info("Cannot run cmd '%s' in container %s: no " + "runtime detected on host." % (cmd, container)) + return _default + if self.container_exists(container): + cmd = self.fmt_container_cmd(container, cmd) + else: + self._log_info("Cannot run cmd '%s' in container %s: no such " + "container is running." % (cmd, container)) + return sos_get_command_output(cmd, timeout=timeout, chroot=root, chdir=runat, binary=binary, env=env, foreground=foreground) + def _get_container_runtime(self, runtime=None): + """Based on policy and request by the plugin, return a usable + ContainerRuntime if one exists + """ + if runtime is None: + if 'default' in self.policy.runtimes.keys(): + return self.policy.runtimes['default'] + else: + for pol_runtime in list(self.policy.runtimes.keys()): + if runtime == pol_runtime: + return self.policy.runtimes[pol_runtime] + return None + + def container_exists(self, name): + """If a container runtime is present, check to see if a container with + a given name is currently running + """ + _runtime = self._get_container_runtime() + if _runtime is not None: + con = _runtime.get_container_by_name(name) + return con is not None + return False + + def get_container_by_name(self, name): + _runtime = self._get_container_runtime() + if _runtime is not None: + return _runtime.get_container_by_name(name) + return None + + def get_containers(self, runtime=None, get_all=False): + """Return a list of all container IDs from the Policy's + ContainerRuntime. + + If `runtime` is not provided, use the Policy default. If the specified + `runtime is not loaded, return empty. + """ + _runtime = self._get_container_runtime(runtime=runtime) + if _runtime is not None: + if get_all: + return _runtime.get_containers(get_all=True) + else: + return _runtime.containers + return [] + + def get_container_images(self, runtime=None): + """Return a list of all image names from the Policy's + ContainerRuntime + + If `runtime` is not provided, use the Policy default. If the specified + `runtime is not loaded, return empty. + """ + _runtime = self._get_container_runtime(runtime=runtime) + if _runtime is not None: + return _runtime.images + return [] + + def get_container_volumes(self, runtime=None): + """Return a list of all volume names from the Policy's + ContainerRuntime + + If `runtime` is not provided, use the Policy default. If the specified + `runtime is not loaded, return empty. + """ + _runtime = self._get_container_runtime(runtime=runtime) + if _runtime is not None: + return _runtime.volumes + return [] + + def get_container_logs(self, container, **kwargs): + """Helper to get the `logs` output for a given container + + Supports passthru of add_cmd_output() options + """ + _runtime = self._get_container_runtime() + if _runtime is not None: + self.add_cmd_output(_runtime.get_logs_command(container), **kwargs) + + def fmt_container_cmd(self, container, cmd): + if self.container_exists(container): + _runtime = self._get_container_runtime() + return _runtime.fmt_container_cmd(container, cmd) + return cmd + def is_module_loaded(self, module_name): """Return whether specified module as module_name is loaded or not""" return module_name in self.policy.kernel_mods -- cgit