From 2232a27ffbc0da1cab736a4a3cd79037bbad3ec1 Mon Sep 17 00:00:00 2001 From: Alex Schultz Date: Fri, 26 Jun 2020 15:05:11 -0600 Subject: [PATCH] Use filter for containers not running check Rather than using ansible task loops which increase the time to execute, this change creates a filter that is used to assert that the containers used in execs are running before we run the execs Change-Id: I5e15cc71c45160109f5c303c13dd25a052ede3c3 --- .../ansible_plugins/filter/helpers.py | 39 +++++++++++ .../tasks/container_running.yml | 25 ------- .../tasks/podman/exec.yml | 10 +-- .../tests/plugins/filter/test_helpers.py | 68 +++++++++++++++++++ 4 files changed, 113 insertions(+), 29 deletions(-) delete mode 100644 tripleo_ansible/roles/tripleo_container_manage/tasks/container_running.yml diff --git a/tripleo_ansible/ansible_plugins/filter/helpers.py b/tripleo_ansible/ansible_plugins/filter/helpers.py index bd0d86ba9..6d9ec2912 100644 --- a/tripleo_ansible/ansible_plugins/filter/helpers.py +++ b/tripleo_ansible/ansible_plugins/filter/helpers.py @@ -38,6 +38,7 @@ class FilterModule(object): 'haskey': self.haskey, 'list_of_keys': self.list_of_keys, 'container_exec_cmd': self.container_exec_cmd, + 'containers_not_running': self.containers_not_running, 'get_key_from_dict': self.get_key_from_dict, 'recursive_get_key_from_dict': self.recursive_get_key_from_dict, 'get_role_assignments': self.get_role_assignments, @@ -336,6 +337,44 @@ class FilterModule(object): cmd.extend(data['command']) return cmd + def containers_not_running(self, container_info, execs=[]): + """Check if specified services aren't running + + :params: container_info: containers list from podman_container_info + result + :params: execs: list of dicts for container actions + """ + not_running = [] + expected_containers = set() + + # Get the container out of any execs by extracting the container + # out of the command to be executed + # + # NOTE this could be written as: + # [v.get('command')[0] + # for i in self.haskey(execs, attribute='action', value='exec') + # for k, v in i.items()] + # But this won't handle missing command. I'm uncertain if we ever would + # pass in an exec without an action but the code below won't blow up + # if command is missing + for action in self.haskey(execs, attribute='action', value='exec'): + for k, v in action.items(): + command = v.get('command') + if command and len(command) > 0: + expected_containers.add(command[0]) + + # we don't have any containers we're checking so just stop + if len(expected_containers) == 0: + return [] + + # check running containers against exec containers + for container in container_info: + container_name = container.get('Name') + if (container_name in expected_containers + and not container.get('State', {}).get('Running')): + not_running.append(container_name) + return not_running + def get_role_assignments(self, data, default_role='admin', default_project='service'): """Return a dict of all roles and their users. diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/container_running.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/container_running.yml deleted file mode 100644 index 17cee9849..000000000 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/container_running.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -# Copyright 2019 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: "Assert that {{ lookup('dict', container_exists_data).value.command.0 }} is running before exec" - assert: - that: - - podman_containers.containers | selectattr('Name', 'equalto', lookup('dict', container_exists_data).value.command.0) | - map(attribute='State.Running') | first | default(false) - fail_msg: >- - Can't run container exec for {{ lookup('dict', container_exists_data).key }}, - {{ lookup('dict', container_exists_data).value.command.0 }} is not running - success_msg: "{{ lookup('dict', container_exists_data).value.command.0 }} is running" 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 28c4c8ea0..b82e6a299 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/exec.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/exec.yml @@ -15,10 +15,12 @@ # under the License. - name: "Check if containers are running before doing exec" - include_tasks: container_running.yml - loop: "{{ batched_container_data | haskey(attribute='action', value='exec') }}" - loop_control: - loop_var: container_exists_data + assert: + that: + - (podman_containers.containers | containers_not_running(execs=batched_container_data) | length) == 0 + fail_msg: >- + Can't run container exec as the following containers are not running: + {{ podman_containers.containers | containers_not_running(execs=batched_container_data) | join(', ') }} when: not ansible_check_mode|bool - name: "Async container exec" diff --git a/tripleo_ansible/tests/plugins/filter/test_helpers.py b/tripleo_ansible/tests/plugins/filter/test_helpers.py index 507357794..0ba61c40c 100644 --- a/tripleo_ansible/tests/plugins/filter/test_helpers.py +++ b/tripleo_ansible/tests/plugins/filter/test_helpers.py @@ -816,6 +816,74 @@ class TestHelperFilters(tests_base.TestCase): result = self.filters.container_exec_cmd(data=data) self.assertEqual(result, expected_cmd) + def test_containers_not_running(self): + results = [ + { + "Name": "keystone", + "State": {"Running": False} + }, + { + "Name": "neutron", + "State": {"Running": True} + } + ] + commands = [{ + "keystone_bootstrap": { + "action": "exec", + "command": [ + "keystone", + "/usr/bin/bootstrap_host_exec", + "keystone", + "keystone-manage", + "bootstrap" + ] + }, + "neutron_bootstrap": { + "action": "exec", + "command": [ + "neutron", + "/usr/bin/bootstrap_host_exec", + "neutron", + "neutron-manage", + "bootstrap" + ] + } + }] + + expected = ['keystone'] + actual = self.filters.containers_not_running(results, commands) + self.assertEqual(actual, expected) + + def test_containers_not_running_missing_command(self): + results = [ + { + "Name": "keystone", + "State": {"Running": True} + }, + { + "Name": "neutron", + "State": {"Running": True} + } + ] + commands = [{ + "keystone_bootstrap": { + "action": "exec", + "command": [ + "keystone", + "/usr/bin/bootstrap_host_exec", + "keystone", + "keystone-manage", + "bootstrap" + ] + }, + "neutron_bootstrap": { + "action": "exec", + } + }] + expected = [] + actual = self.filters.containers_not_running(results, commands) + self.assertEqual(actual, expected) + def test_get_role_assignments(self): data = [{ 'nova': {