Catch errors and changes in kolla_toolbox module

The kolla_toolbox Ansible module executes as-hoc ansible commands in the
kolla_toolbox container, and parses the output to make it look as if
ansible-playbook executed the command. Currently however, this module
sometimes fails to catch failures of the underlying command, and also
sometimes shows tasks as 'ok' when the underlying command was changed.
This has been tested both before and after the upgrade to ansible 2.8.

This change fixes this issue by configuring ansible to emit output in
JSON format, to make parsing simpler. We can now pick up errors and
changes, and signal them to the caller.

This change also adds an ansible playbook, tests/test-kolla-toolbox.yml,
that can be executed to test the module. It's not currently integrated
with any CI jobs.

Note that this change cannot be backported as the JSON output callback
plugin was added in Ansible 2.5.

Change-Id: I8236dd4165f760c819ca972b75cbebc62015fada
Closes-Bug: #1844114
This commit is contained in:
Mark Goddard 2019-09-16 11:27:48 +01:00
parent d659c4dd15
commit 70b515bf12
2 changed files with 116 additions and 23 deletions

View File

@ -16,7 +16,6 @@
import docker
import json
import re
from ansible.module_utils.basic import AnsibleModule
@ -90,13 +89,6 @@ EXAMPLES = '''
'''
JSON_REG = re.compile('^(?P<host>\w+) \| (?P<status>\w+)!? =>(?P<stdout>.*)$',
re.MULTILINE | re.DOTALL)
NON_JSON_REG = re.compile(('^(?P<host>\w+) \| (?P<status>\w+)!? \| '
'rc=(?P<exit_code>\d+) >>\n(?P<stdout>.*)\n$'),
re.MULTILINE | re.DOTALL)
def gen_commandline(params):
command = ['ansible', 'localhost']
if params.get('module_name'):
@ -138,23 +130,43 @@ def main():
module.fail_json(msg='kolla_toolbox container is not running.')
kolla_toolbox = kolla_toolbox[0]
job = client.exec_create(kolla_toolbox, command_line)
output = client.exec_start(job)
# Use the JSON output formatter, so that we can parse it.
environment = {"ANSIBLE_STDOUT_CALLBACK": "json",
"ANSIBLE_LOAD_CALLBACK_PLUGINS": "True"}
job = client.exec_create(kolla_toolbox, command_line,
environment=environment)
json_output = client.exec_start(job)
for exp in [JSON_REG, NON_JSON_REG]:
m = exp.match(output)
if m:
inner_output = m.groupdict().get('stdout')
break
else:
module.fail_json(
msg='Can not parse the inner module output: %s' % output)
ret = dict()
try:
ret = json.loads(inner_output)
except ValueError:
ret['stdout'] = inner_output
output = json.loads(json_output)
except Exception as e:
module.fail_json(
msg='Can not parse the inner module output: %s' % json_output)
# Expected format is the following:
# {
# "plays": [
# {
# "tasks": [
# {
# "hosts": {
# "localhost": {
# <module result>
# }
# }
# }
# ]
# {
# ]
# }
try:
ret = output['plays'][0]['tasks'][0]['hosts']['localhost']
except (KeyError, IndexError) as e:
module.fail_json(
msg='Ansible JSON output has unexpected format: %s' % output)
# Remove Ansible's internal variables from returned fields.
ret.pop('_ansible_no_log', None)
module.exit_json(**ret)

View File

@ -0,0 +1,81 @@
---
- name: Test the kolla_toolbox module
hosts: localhost
gather_facts: false
tasks:
- name: Test successful & unchanged
kolla_toolbox:
module_name: debug
module_args:
msg: hi
register: result
- name: Assert result is successful
assert:
that: result is successful
- name: Assert result is not changed
assert:
that: result is not changed
- name: Test successful & changed
kolla_toolbox:
module_name: command
module_args:
echo hi
register: result
- name: Assert result is successful
assert:
that: result is successful
- name: Assert result is changed
assert:
that: result is changed
- name: Test unsuccessful
kolla_toolbox:
module_name: command
module_args:
foo
register: result
ignore_errors: true
- name: Assert result is failed
assert:
that: result is failed
- name: Test invalid module parameters
kolla_toolbox:
module_name: debug
module_args:
foo: bar
register: result
ignore_errors: true
- name: Assert result is failed
assert:
that: result is failed
- name: Setup for Test successful & changed (JSON format)
kolla_toolbox:
module_name: file
module_args:
path: /tmp/foo
state: absent
- name: Test successful & changed (JSON format)
kolla_toolbox:
module_name: file
module_args:
path: /tmp/foo
state: directory
register: result
- name: Assert result is successful
assert:
that: result is successful
- name: Assert result is changed
assert:
that: result is changed