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
(cherry picked from commit 2232a27ffb)
This commit is contained in:
Alex Schultz 2020-06-26 15:05:11 -06:00 committed by Emilien Macchi
parent 2d1a48b505
commit 68784620ef
4 changed files with 113 additions and 29 deletions

View File

@ -38,6 +38,7 @@ class FilterModule(object):
'haskey': self.haskey, 'haskey': self.haskey,
'list_of_keys': self.list_of_keys, 'list_of_keys': self.list_of_keys,
'container_exec_cmd': self.container_exec_cmd, 'container_exec_cmd': self.container_exec_cmd,
'containers_not_running': self.containers_not_running,
'get_key_from_dict': self.get_key_from_dict, 'get_key_from_dict': self.get_key_from_dict,
'get_role_assignments': self.get_role_assignments, 'get_role_assignments': self.get_role_assignments,
'get_domain_id': self.get_domain_id, 'get_domain_id': self.get_domain_id,
@ -330,6 +331,44 @@ class FilterModule(object):
cmd.extend(data['command']) cmd.extend(data['command'])
return cmd 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', def get_role_assignments(self, data, default_role='admin',
default_project='service'): default_project='service'):
"""Return a dict of all roles and their users. """Return a dict of all roles and their users.

View File

@ -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"

View File

@ -15,10 +15,12 @@
# under the License. # under the License.
- name: "Check if containers are running before doing exec" - name: "Check if containers are running before doing exec"
include_tasks: container_running.yml assert:
loop: "{{ batched_container_data | haskey(attribute='action', value='exec') }}" that:
loop_control: - (podman_containers.containers | containers_not_running(execs=batched_container_data) | length) == 0
loop_var: container_exists_data 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 when: not ansible_check_mode|bool
- name: "Async container exec" - name: "Async container exec"

View File

@ -816,6 +816,74 @@ class TestHelperFilters(tests_base.TestCase):
result = self.filters.container_exec_cmd(data=data) result = self.filters.container_exec_cmd(data=data)
self.assertEqual(result, expected_cmd) 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): def test_get_role_assignments(self):
data = [{ data = [{
'nova': { 'nova': {