From 504033868672580b3af2b9d1e5d771a8233add9d Mon Sep 17 00:00:00 2001 From: Emilien Macchi Date: Mon, 11 May 2020 14:54:15 -0400 Subject: [PATCH] container_manage: catch more containers with wrong return code - helpers/haskey: add excluded_keys argument. It allows to return the config that has an attribute but also where some attributed are excluded. The use case here is that we have some container configs which have both "command" and "action". We want to use that filter to build a list of containers where the return code has to be checked; which is the not the case for the containers with "action" in their configs; since they are used for "podman exec" configs (and there is nothing to check in return from podman inspect). - check_exit_code: change the list of containers to check the exit code to include all the containers with a "command" but not "action". It should cover all the containers which are used to run some non-services things like db_sync etc. - molecule: change the fedora_bis and fedora_three containers to run short sleep so we can actually test that change against these containers and also on the first deployment of fedora_bis and fedora_three, we'll check their return code. Change-Id: I466a57bd788e02c32b1efb0ac0223684f0d39393 Closes-Bug: #1878074 --- .../ansible_plugins/filter/helpers.py | 14 +++- .../molecule/default/converge.yml | 1 + .../molecule/default/prepare.yml | 4 +- .../tasks/podman/check_exit_code.yml | 2 +- .../tasks/podman/create.yml | 8 +- .../tests/plugins/filter/test_helpers.py | 84 +++++++++++++++++++ 6 files changed, 107 insertions(+), 6 deletions(-) diff --git a/tripleo_ansible/ansible_plugins/filter/helpers.py b/tripleo_ansible/ansible_plugins/filter/helpers.py index 6eac7250b..bd0d86ba9 100644 --- a/tripleo_ansible/ansible_plugins/filter/helpers.py +++ b/tripleo_ansible/ansible_plugins/filter/helpers.py @@ -197,7 +197,8 @@ class FilterModule(object): return to_delete - def haskey(self, data, attribute, value=None, reverse=False, any=False): + def haskey(self, data, attribute, value=None, reverse=False, any=False, + excluded_keys=[]): """Return dict data with a specific key. This filter will take a list of dictionaries (data) @@ -207,10 +208,21 @@ class FilterModule(object): which have the attribute. If any is set to True, the returned list will match any value in the list of values for "value" parameter which has to be a list. + If we want to exclude items which have certain key(s); these keys + should be added to the excluded_keys list. If excluded_keys is used + with reverse, we'll just exclude the items which had a key from + excluded_keys in the reversed list. """ return_list = [] for i in data: + to_skip = False for k, v in json.loads(json.dumps(i)).items(): + for e in excluded_keys: + if e in v: + to_skip = True + break + if to_skip: + break if attribute in v and not reverse: if value is None: return_list.append(i) diff --git a/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml b/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml index 8b2e7e4a0..646b7fd10 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml @@ -64,6 +64,7 @@ tripleo_container_manage_debug: true tripleo_container_manage_config_patterns: '*.json' tripleo_container_manage_systemd_order: true + tripleo_container_manage_valid_exit_code: [0] tasks: - include_role: name: tripleo_container_manage diff --git a/tripleo_ansible/roles/tripleo_container_manage/molecule/default/prepare.yml b/tripleo_ansible/roles/tripleo_container_manage/molecule/default/prepare.yml index 531eed45d..6948494ee 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/molecule/default/prepare.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/molecule/default/prepare.yml @@ -45,7 +45,7 @@ { "image": "fedora:latest", "net": "host", - "command": "sleep 3600" + "command": "sleep 5" } dest: '/tmp/container-configs/fedora_bis.json' - name: Create a third configuration file for a fedora container @@ -54,7 +54,7 @@ { "image": "fedora:latest", "net": "host", - "command": "sleep 3600" + "command": "sleep 5" } dest: '/tmp/container-configs/fedora_three.json' - name: Create old healthcheck service for fedora container diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/check_exit_code.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/check_exit_code.yml index becd98302..f9e8d67b2 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/check_exit_code.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/check_exit_code.yml @@ -16,7 +16,7 @@ - name: "Wait for containers to be exited" podman_container_info: - name: "{{ batched_container_data | haskey(attribute='action', reverse=True) | list_of_keys }}" + name: "{{ containers_with_exit_code }}" register: podman_containers_infos until: ( podman_containers_infos.containers | selectattr('State.Running', 'equalto', True) |list|length ) == 0 # Retry 30 times every 10 seconds so we wait 5 min in total diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/create.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/create.yml index 4e0f0abb1..eac971d3b 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/create.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/tasks/podman/create.yml @@ -97,10 +97,11 @@ when: - not ansible_check_mode|bool -- name: "Create facts for containers which changed or failed" +- name: "Create facts for containers which changed or failed or which require rc check" set_fact: containers_changed: "{{ create_async_poll_results.results | get_changed_containers }}" containers_failed: "{{ create_async_poll_results.results | get_failed_containers }}" + containers_to_check: "{{ batched_container_data | haskey(attribute='command', excluded_keys=['action', 'restart']) | list_of_keys | default([]) }}" - name: Print the containers that failed to start fail: @@ -120,6 +121,9 @@ - name: "Block for container exit codes" when: - - tripleo_container_manage_valid_exit_code|length != 0 - not ansible_check_mode|bool + - tripleo_container_manage_valid_exit_code|length != 0 + - containers_to_check|length != 0 include_tasks: podman/check_exit_code.yml + vars: + containers_with_exit_code: "{{ containers_to_check }}" diff --git a/tripleo_ansible/tests/plugins/filter/test_helpers.py b/tripleo_ansible/tests/plugins/filter/test_helpers.py index a144f6497..507357794 100644 --- a/tripleo_ansible/tests/plugins/filter/test_helpers.py +++ b/tripleo_ansible/tests/plugins/filter/test_helpers.py @@ -200,6 +200,90 @@ class TestHelperFilters(tests_base.TestCase): attribute='restart', value='always') self.assertEqual(result, expected_list) + def test_haskey_exclude(self): + data = [ + { + 'keystone': { + 'start_order': 1, + 'image': 'quay.io/tripleo/keystone', + 'command': 'sleep 10', + 'restart': 'always' + }, + }, + { + 'nova': { + 'start_order': 1, + 'image': 'quay.io/tripleo/nova', + 'command': 'sleep 10', + 'action': 'exec' + }, + }, + { + 'mysql': { + 'start_order': 0, + 'command': 'sleep 10', + 'image': 'quay.io/tripleo/mysql' + } + }, + { + 'haproxy': { + 'start_order': 0, + 'image': 'quay.io/tripleo/haproxy' + } + } + ] + expected_list = [ + { + 'mysql': { + 'start_order': 0, + 'command': 'sleep 10', + 'image': 'quay.io/tripleo/mysql' + }, + } + ] + result = self.filters.haskey(data=data, + attribute='command', + excluded_keys=['action', 'restart']) + self.assertEqual(result, expected_list) + + def test_haskey_reverse_exclude(self): + data = [ + { + 'keystone': { + 'start_order': 1, + 'image': 'quay.io/tripleo/keystone', + 'restart': 'always' + }, + }, + { + 'nova': { + 'start_order': 1, + 'image': 'quay.io/tripleo/nova', + 'action': 'exec' + }, + }, + { + 'mysql': { + 'start_order': 0, + 'image': 'quay.io/tripleo/mysql' + } + } + ] + expected_list = [ + { + 'mysql': { + 'start_order': 0, + 'image': 'quay.io/tripleo/mysql' + }, + } + ] + result = self.filters.haskey(data=data, + attribute='restart', + value='always', + reverse=True, + excluded_keys=['action']) + self.assertEqual(result, expected_list) + def test_haskey_reverse(self): data = [ {