From 3ce9d50a7f3a62a63561c473b6dc764a458eb1e9 Mon Sep 17 00:00:00 2001 From: Emilien Macchi Date: Tue, 7 Jul 2020 15:37:15 -0400 Subject: [PATCH] container_status: "exec" checks status Support the checks of "podman exec" commands, and add the commands to the list of things podman ran. It reduces the number of tasks as it removes get_commands_exec and re-use the container_status action plugin. Change-Id: I4c84b389b595a8fe18ef6d31e896d6b6608b9920 --- .../action/container_status.py | 77 ++++++++++++------- .../tasks/podman/exec.yml | 14 +++- .../tasks/podman/get_commands_exec.yml | 33 -------- .../tasks/podman/manage.yml | 4 + 4 files changed, 67 insertions(+), 61 deletions(-) delete mode 100644 tripleo_ansible/roles/tripleo_container_manage/tasks/podman/get_commands_exec.yml diff --git a/tripleo_ansible/ansible_plugins/action/container_status.py b/tripleo_ansible/ansible_plugins/action/container_status.py index 43e6d9ff6..9f8f14da6 100644 --- a/tripleo_ansible/ansible_plugins/action/container_status.py +++ b/tripleo_ansible/ansible_plugins/action/container_status.py @@ -137,26 +137,33 @@ class ActionModule(ActionBase): :param data: Dictionary of container data. :returns: List of containers that need to be checked. """ - containers = [] + containers_exec = [] + containers_run = [] # loop through container data to get specific container for container in data: # get container name and data for name, values in container.items(): - if 'action' in values or 'restart' in values: + if 'restart' in values: continue + if 'action' in values: + containers_exec.append(name) if 'image' in values: # We assume that container configs that don't have a # restart policy nor action (used for podman exec) but have # an image set, will run something and then exit with a # return code. - containers.append(name) - if self.debug and len(containers) > 0: + containers_run.append(name) + if self.debug and len(containers_run) > 0: DISPLAY.display('These containers are supposed to terminate with ' 'a valid exit code and will be checked: ' - '{}'.format(containers)) - return containers + '{}'.format(containers_run)) + if self.debug and len(containers_exec) > 0: + DISPLAY.display('These containers exec are supposed to terminate ' + 'with a valid exit code and will be checked: ' + '{}'.format(containers_exec)) + return containers_run - def _get_create_commands(self, results): + def _get_commands(self, results): """Return a list of commands that were executed by container tool. :param results: Ansible task results. @@ -164,8 +171,16 @@ class ActionModule(ActionBase): """ commands = [] for item in results: - if item['changed']: - commands.extend(item['podman_actions']) + try: + if item['changed']: + commands.extend(item['podman_actions']) + except KeyError: + if 'cmd' in item: + commands.append(' '.join(item['cmd'])) + else: + raise AnsibleActionFail('Wrong async result data, missing' + ' podman_actions or cmd:' + ' {}'.format(item)) return commands def _is_container_running(self, container): @@ -248,22 +263,29 @@ class ActionModule(ActionBase): :returns: Tuple of containers that changed or failed """ changed = [] - failed = [] + create_failed = [] + exec_failed = [] for item in results: # if Ansible is run in check mode, the async_results items will # not contain failed or finished keys. if self._play_context.check_mode: break - async_result_item = item['create_async_result_item'] - if item['changed']: - for name, c in async_result_item['container_data'].items(): - changed.append(name) - if (item['failed'] or not item['finished'] - or ('stderr' in async_result_item - and async_result_item['stderr'] != '')): - for name, c in async_result_item['container_data'].items(): - failed.append(name) - return (changed, failed) + if 'create_async_result_item' in item: + async_item = item['create_async_result_item'] + if item['changed']: + for name, c in async_item['container_data'].items(): + changed.append(name) + if (item['failed'] or not item['finished'] + or ('stderr' in async_item + and async_item['stderr'] != '')): + for name, c in async_item['container_data'].items(): + create_failed.append(name) + if 'exec_async_result_item' in item: + async_item = item['exec_async_result_item'] + if item['rc'] != 0: + for name, c in async_item['container_exec_data'].items(): + exec_failed.append(name) + return (changed, create_failed, exec_failed) def run(self, tmp=None, task_vars=None): self._supports_check_mode = True @@ -285,13 +307,13 @@ class ActionModule(ActionBase): valid_exit_codes = args['valid_exit_codes'] self.debug = args['debug'] - containers_to_check = self._get_containers_to_check(container_data) + containers_run_to_check = self._get_containers_to_check(container_data) # Check that the containers which are supposed to finish have # actually finished and also terminated with the right exit code. - if len(valid_exit_codes) > 0 and len(containers_to_check) > 0: + if len(valid_exit_codes) > 0 and len(containers_run_to_check) > 0: (running, failed) = self._check_container_state( - containers_to_check, + containers_run_to_check, valid_exit_codes, task_vars) @@ -301,9 +323,12 @@ class ActionModule(ActionBase): # - reported a failed resource (podman_container failed to create # the container and return it as self.failed_containers. # - didn't finish on time and return it as self.failed_containers. - (self.changed_containers, async_failed) = ( + (self.changed_containers, async_failed, exec_failed) = ( self._check_errors_in_ansible_async_results(async_results)) + if len(exec_failed) > 0: + DISPLAY.error('Container(s) exec commands which failed to execute' + ': {}'.format(failed)) if len(failed) > 0: DISPLAY.error('Container(s) which finished with wrong return code' ': {}'.format(failed)) @@ -313,13 +338,13 @@ class ActionModule(ActionBase): if len(running) > 0: DISPLAY.error('Container(s) which did not finish after {} ' 'minutes: {}'.format(TIMEOUT, running)) - total_errors = list(set(failed + async_failed + running)) + total_errors = list(set(failed + exec_failed + async_failed + running)) if len(total_errors) > 0: raise AnsibleActionFail('Failed container(s): {}, check logs in ' '/var/log/containers/' 'stdouts/'.format(total_errors)) - container_commands = self._get_create_commands(async_results) + container_commands = self._get_commands(async_results) if len(container_commands) > 0 and \ (self._play_context.check_mode or self.debug): for cmd in container_commands: diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/exec.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/exec.yml index b82e6a299..fca9c2be0 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/exec.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/exec.yml @@ -45,9 +45,19 @@ register: exec_async_poll_results until: exec_async_poll_results.finished retries: "{{ tripleo_container_manage_exec_retries }}" + # We fail later if a container failed to execute the command + failed_when: false when: not ansible_check_mode|bool -- name: Block for container commands - include_tasks: podman/get_commands_exec.yml +- name: Check container exec status + container_status: + container_async_results: "{{ exec_async_poll_results.results }}" + container_data: "{{ batched_container_data | haskey(attribute='action', value='exec') }}" + debug: "{{ tripleo_container_manage_debug | bool }}" + register: container_exec_status_results + +- name: "Append the list of all podman commands with the containers execs" + set_fact: + all_containers_commands: "{{ container_status_results.commands | default([]) + (all_containers_commands | default([]) | list) }}" when: - ansible_check_mode|bool diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/get_commands_exec.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/get_commands_exec.yml deleted file mode 100644 index dd4137b52..000000000 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/get_commands_exec.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -# Copyright 2020 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -- name: "Create a list of podman exec commands that are run" - no_log: "{{ not (tripleo_container_manage_debug | bool) }}" - set_fact: - containers_commands: >- - {{ (containers_commands | default([])) + ([lookup('dict', container_exec_data).value | - container_exec_cmd(cli=tripleo_container_manage_cli) | join(' ')]) }} - loop: "{{ batched_container_data | haskey(attribute='action', value='exec') }}" - loop_control: - loop_var: container_exec_data - -- name: "Print the list of podman exec commands that are run" - debug: - var: containers_commands - -- name: "Append the list of all podman commands that are run for containers with changes" - set_fact: - all_containers_commands: "{{ containers_commands|default([], true) + (all_containers_commands | default([]) | list) }}" diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/manage.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/manage.yml index 9515642cb..eb82ec59b 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/manage.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/manage.yml @@ -16,6 +16,10 @@ - name: Run containers execs asynchronously include_tasks: podman/exec.yml + when: + - ((batched_container_data | haskey(attribute='action', value='exec') | default([])) | length > 0) - name: Manage containers asynchronously include_tasks: podman/create.yml + when: + - ((batched_container_data | haskey(attribute='action', reverse=True) | default([])) | length > 0)