File ansiblegate-take-care-of-failed-skipped-and-unreacha.patch of Package salt
From 1f2a03a90f6673cace7f0946979d548669016d73 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Thu, 13 Aug 2020 13:49:16 +0100
Subject: [PATCH] ansiblegate: take care of failed, skipped and
unreachable tasks (bsc#1173911)
Add 'retcode' from ansible-playbook execution to the returned data (bsc#1173909)
Always add retcode to ansible.playbooks output
Adjust ansible.playbooks output comment properly
Add new unit test for ansible.playbooks
Add unit tests for ansible.playbooks state
---
salt/modules/ansiblegate.py | 10 +-
salt/states/ansiblegate.py | 51 +-
.../unit/files/playbooks/failed_example.json | 748 ++++++++++++++++
.../unit/files/playbooks/success_example.json | 803 ++++++++++++++++++
tests/unit/modules/test_ansiblegate.py | 15 +
tests/unit/states/test_ansiblegate.py | 113 +++
6 files changed, 1717 insertions(+), 23 deletions(-)
create mode 100644 tests/unit/files/playbooks/failed_example.json
create mode 100644 tests/unit/files/playbooks/success_example.json
create mode 100644 tests/unit/states/test_ansiblegate.py
diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py
index 8e28fcafa3..e76809d4ba 100644
--- a/salt/modules/ansiblegate.py
+++ b/salt/modules/ansiblegate.py
@@ -381,9 +381,9 @@ def playbooks(playbook, rundir=None, check=False, diff=False, extra_vars=None,
'cwd': rundir,
'cmd': ' '.join(command)
}
- ret = __salt__['cmd.run_all'](**cmd_kwargs)
- log.debug('Ansible Playbook Return: %s', ret)
- retdata = json.loads(ret['stdout'])
- if ret['retcode']:
- __context__['retcode'] = ret['retcode']
+ ret = __salt__["cmd.run_all"](**cmd_kwargs)
+ log.debug("Ansible Playbook Return: %s", ret)
+ retdata = json.loads(ret["stdout"])
+ if 'retcode' in ret:
+ __context__["retcode"] = retdata["retcode"] = ret["retcode"]
return retdata
diff --git a/salt/states/ansiblegate.py b/salt/states/ansiblegate.py
index b42dc02938..d268e492e2 100644
--- a/salt/states/ansiblegate.py
+++ b/salt/states/ansiblegate.py
@@ -120,9 +120,11 @@ def _changes(plays):
task_changes = {}
for task in play['tasks']:
host_changes = {}
- for host, data in six.iteritems(task['hosts']):
- if data['changed'] is True:
- host_changes[host] = data.get('diff', data.get('changes', {}))
+ for host, data in six.iteritems(task["hosts"]):
+ if data["changed"] is True:
+ host_changes[host] = data.get("diff", data.get("changes", {}))
+ elif any(x in data for x in ["failed", "skipped", "unreachable"]):
+ host_changes[host] = data.get("results", data.get("msg", {}))
if host_changes:
task_changes[task['task']['name']] = host_changes
if task_changes:
@@ -177,20 +179,33 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs=
if not isinstance(ansible_kwargs, dict):
log.debug('Setting ansible_kwargs to empty dict: %s', ansible_kwargs)
ansible_kwargs = {}
- checks = __salt__['ansible.playbooks'](name, rundir=rundir, check=True, diff=True, **ansible_kwargs)
- if all(not check['changed'] for check in six.itervalues(checks['stats'])):
- ret['comment'] = 'No changes to be made from playbook {0}'.format(name)
- ret['result'] = True
- elif __opts__['test']:
- ret['comment'] = 'Changes will be made from playbook {0}'.format(name)
- ret['result'] = None
- ret['changes'] = _changes(checks)
+ if __opts__["test"]:
+ checks = __salt__["ansible.playbooks"](name, rundir=rundir, check=True, diff=True, **ansible_kwargs)
+ if all(not check["changed"] and not check["failures"] and not check["unreachable"] and not check["skipped"] for check in six.itervalues(checks["stats"])):
+ ret["comment"] = "No changes to be made from playbook {0}".format(name)
+ ret["result"] = True
+ elif any(check["changed"] and not check["failures"] and not check["unreachable"] and not check["skipped"] for check in six.itervalues(checks["stats"])):
+ ret["comment"] = "Changes will be made from playbook {0}".format(name)
+ ret["result"] = None
+ ret["changes"] = _changes(checks)
+ else:
+ ret["comment"] = "There were some issues running the playbook {0}".format(name)
+ ret["result"] = False
+ ret["changes"] = _changes(checks)
else:
- results = __salt__['ansible.playbooks'](name, rundir=rundir, diff=True, **ansible_kwargs)
- ret['comment'] = 'Changes were made by playbook {0}'.format(name)
- ret['changes'] = _changes(results)
- ret['result'] = all(
- not check['failures'] and not check['unreachable']
- for check in six.itervalues(checks['stats'])
- )
+ results = __salt__["ansible.playbooks"](name, rundir=rundir, diff=True, **ansible_kwargs)
+ if all(not check["changed"] and not check["failures"] and not check["unreachable"] and not check["skipped"] for check in six.itervalues(results["stats"])):
+ ret["comment"] = "No changes to be made from playbook {0}".format(name)
+ ret["result"] = True
+ ret["changes"] = _changes(results)
+ else:
+ ret["changes"] = _changes(results)
+ ret["result"] = all(
+ not check["failures"] and not check["unreachable"] and not check["skipped"]
+ for check in six.itervalues(results["stats"])
+ )
+ if ret["result"]:
+ ret["comment"] = "Changes were made by playbook {0}".format(name)
+ else:
+ ret["comment"] = "There were some issues running the playbook {0}".format(name)
return ret
diff --git a/tests/unit/files/playbooks/failed_example.json b/tests/unit/files/playbooks/failed_example.json
new file mode 100644
index 0000000000..9ee8ba25b7
--- /dev/null
+++ b/tests/unit/files/playbooks/failed_example.json
@@ -0,0 +1,748 @@
+{
+ "custom_stats": {},
+ "global_custom_stats": {},
+ "plays": [
+ {
+ "play": {
+ "duration": {
+ "end": "2020-08-14T11:55:33.889442Z",
+ "start": "2020-08-14T11:55:30.460145Z"
+ },
+ "id": "5254001e-9fce-297d-21cd-000000000007",
+ "name": "py2hosts"
+ },
+ "tasks": [
+ {
+ "hosts": {
+ "centos7-host1.tf.local": {
+ "_ansible_no_log": false,
+ "_ansible_verbose_override": true,
+ "action": "gather_facts",
+ "ansible_facts": {
+ "ansible_all_ipv4_addresses": [
+ "192.168.122.29"
+ ],
+ "ansible_all_ipv6_addresses": [
+ "fe80::5054:ff:fe3e:4ce"
+ ],
+ "ansible_apparmor": {
+ "status": "disabled"
+ },
+ "ansible_architecture": "x86_64",
+ "ansible_bios_date": "04/01/2014",
+ "ansible_bios_version": "rel-1.13.0-0-gf21b5a4-rebuilt.opensuse.org",
+ "ansible_cmdline": {
+ "BOOT_IMAGE": "/vmlinuz-3.10.0-862.el7.x86_64",
+ "LANG": "en_US.UTF-8",
+ "console": "ttyS0,115200",
+ "crashkernel": "auto",
+ "quiet": true,
+ "rhgb": true,
+ "ro": true,
+ "root": "UUID=2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ "ansible_date_time": {
+ "date": "2020-08-14",
+ "day": "14",
+ "epoch": "1597406131",
+ "hour": "13",
+ "iso8601": "2020-08-14T11:55:31Z",
+ "iso8601_basic": "20200814T135531991936",
+ "iso8601_basic_short": "20200814T135531",
+ "iso8601_micro": "2020-08-14T11:55:31.992035Z",
+ "minute": "55",
+ "month": "08",
+ "second": "31",
+ "time": "13:55:31",
+ "tz": "CEST",
+ "tz_offset": "+0200",
+ "weekday": "Friday",
+ "weekday_number": "5",
+ "weeknumber": "32",
+ "year": "2020"
+ },
+ "ansible_default_ipv4": {
+ "address": "192.168.122.29",
+ "alias": "eth0",
+ "broadcast": "192.168.122.255",
+ "gateway": "192.168.122.1",
+ "interface": "eth0",
+ "macaddress": "52:54:00:3e:04:ce",
+ "mtu": 1500,
+ "netmask": "255.255.255.0",
+ "network": "192.168.122.0",
+ "type": "ether"
+ },
+ "ansible_default_ipv6": {},
+ "ansible_device_links": {
+ "ids": {},
+ "labels": {},
+ "masters": {},
+ "uuids": {
+ "vda1": [
+ "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ ],
+ "vda2": [
+ "5ec08dbf-55e4-4fb1-a866-7b0fedcb4a24"
+ ],
+ "vda3": [
+ "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ ],
+ "vda5": [
+ "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ ]
+ }
+ },
+ "ansible_devices": {
+ "vda": {
+ "holders": [],
+ "host": "",
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": []
+ },
+ "model": null,
+ "partitions": {
+ "vda1": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ ]
+ },
+ "sectors": "2097152",
+ "sectorsize": 512,
+ "size": "1.00 GB",
+ "start": "2048",
+ "uuid": "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ },
+ "vda2": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "5ec08dbf-55e4-4fb1-a866-7b0fedcb4a24"
+ ]
+ },
+ "sectors": "4196352",
+ "sectorsize": 512,
+ "size": "2.00 GB",
+ "start": "2099200",
+ "uuid": "5ec08dbf-55e4-4fb1-a866-7b0fedcb4a24"
+ },
+ "vda3": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ ]
+ },
+ "sectors": "104857600",
+ "sectorsize": 512,
+ "size": "50.00 GB",
+ "start": "6295552",
+ "uuid": "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ "vda4": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": []
+ },
+ "sectors": "2",
+ "sectorsize": 512,
+ "size": "1.00 KB",
+ "start": "111153152",
+ "uuid": null
+ },
+ "vda5": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ ]
+ },
+ "sectors": "308275200",
+ "sectorsize": 512,
+ "size": "147.00 GB",
+ "start": "111155200",
+ "uuid": "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ }
+ },
+ "removable": "0",
+ "rotational": "1",
+ "sas_address": null,
+ "sas_device_handle": null,
+ "scheduler_mode": "mq-deadline",
+ "sectors": "419430400",
+ "sectorsize": "512",
+ "size": "200.00 GB",
+ "support_discard": "0",
+ "vendor": "0x1af4",
+ "virtual": 1
+ }
+ },
+ "ansible_distribution": "CentOS",
+ "ansible_distribution_file_parsed": true,
+ "ansible_distribution_file_path": "/etc/redhat-release",
+ "ansible_distribution_file_variety": "RedHat",
+ "ansible_distribution_major_version": "7",
+ "ansible_distribution_release": "Core",
+ "ansible_distribution_version": "7.5",
+ "ansible_dns": {
+ "nameservers": [
+ "192.168.122.1"
+ ]
+ },
+ "ansible_domain": "tf.local",
+ "ansible_effective_group_id": 0,
+ "ansible_effective_user_id": 0,
+ "ansible_env": {
+ "HOME": "/root",
+ "LANG": "es_ES.utf8",
+ "LC_ADDRESS": "C",
+ "LC_COLLATE": "C",
+ "LC_CTYPE": "C",
+ "LC_IDENTIFICATION": "C",
+ "LC_MEASUREMENT": "C",
+ "LC_MESSAGES": "C",
+ "LC_MONETARY": "C",
+ "LC_NAME": "C",
+ "LC_NUMERIC": "C",
+ "LC_PAPER": "C",
+ "LC_TELEPHONE": "C",
+ "LC_TIME": "C",
+ "LESSOPEN": "||/usr/bin/lesspipe.sh %s",
+ "LOGNAME": "root",
+ "LS_COLORS": "rs=0:di=38;5;27:ln=38;5;51:mh=44;38;5;15:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=05;48;5;232;38;5;15:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;34:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.Z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.axv=38;5;13:*.anx=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.axa=38;5;45:*.oga=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:",
+ "MAIL": "/var/mail/root",
+ "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
+ "PWD": "/root",
+ "SHELL": "/bin/bash",
+ "SHLVL": "2",
+ "SSH_CLIENT": "192.168.122.179 55766 22",
+ "SSH_CONNECTION": "192.168.122.179 55766 192.168.122.29 22",
+ "SSH_TTY": "/dev/pts/0",
+ "TERM": "xterm-256color",
+ "USER": "root",
+ "XDG_RUNTIME_DIR": "/run/user/0",
+ "XDG_SESSION_ID": "110",
+ "_": "/usr/bin/python"
+ },
+ "ansible_eth0": {
+ "active": true,
+ "device": "eth0",
+ "features": {
+ "busy_poll": "off [fixed]",
+ "fcoe_mtu": "off [fixed]",
+ "generic_receive_offload": "on",
+ "generic_segmentation_offload": "on",
+ "highdma": "on [fixed]",
+ "hw_tc_offload": "off [fixed]",
+ "l2_fwd_offload": "off [fixed]",
+ "large_receive_offload": "off [fixed]",
+ "loopback": "off [fixed]",
+ "netns_local": "off [fixed]",
+ "ntuple_filters": "off [fixed]",
+ "receive_hashing": "off [fixed]",
+ "rx_all": "off [fixed]",
+ "rx_checksumming": "on [fixed]",
+ "rx_fcs": "off [fixed]",
+ "rx_udp_tunnel_port_offload": "off [fixed]",
+ "rx_vlan_filter": "on [fixed]",
+ "rx_vlan_offload": "off [fixed]",
+ "rx_vlan_stag_filter": "off [fixed]",
+ "rx_vlan_stag_hw_parse": "off [fixed]",
+ "scatter_gather": "on",
+ "tcp_segmentation_offload": "on",
+ "tx_checksum_fcoe_crc": "off [fixed]",
+ "tx_checksum_ip_generic": "on",
+ "tx_checksum_ipv4": "off [fixed]",
+ "tx_checksum_ipv6": "off [fixed]",
+ "tx_checksum_sctp": "off [fixed]",
+ "tx_checksumming": "on",
+ "tx_fcoe_segmentation": "off [fixed]",
+ "tx_gre_csum_segmentation": "off [fixed]",
+ "tx_gre_segmentation": "off [fixed]",
+ "tx_gso_partial": "off [fixed]",
+ "tx_gso_robust": "off [fixed]",
+ "tx_ipip_segmentation": "off [fixed]",
+ "tx_lockless": "off [fixed]",
+ "tx_nocache_copy": "off",
+ "tx_scatter_gather": "on",
+ "tx_scatter_gather_fraglist": "off [fixed]",
+ "tx_sctp_segmentation": "off [fixed]",
+ "tx_sit_segmentation": "off [fixed]",
+ "tx_tcp6_segmentation": "on",
+ "tx_tcp_ecn_segmentation": "on",
+ "tx_tcp_mangleid_segmentation": "off",
+ "tx_tcp_segmentation": "on",
+ "tx_udp_tnl_csum_segmentation": "off [fixed]",
+ "tx_udp_tnl_segmentation": "off [fixed]",
+ "tx_vlan_offload": "off [fixed]",
+ "tx_vlan_stag_hw_insert": "off [fixed]",
+ "udp_fragmentation_offload": "on",
+ "vlan_challenged": "off [fixed]"
+ },
+ "hw_timestamp_filters": [],
+ "ipv4": {
+ "address": "192.168.122.29",
+ "broadcast": "192.168.122.255",
+ "netmask": "255.255.255.0",
+ "network": "192.168.122.0"
+ },
+ "ipv6": [
+ {
+ "address": "fe80::5054:ff:fe3e:4ce",
+ "prefix": "64",
+ "scope": "link"
+ }
+ ],
+ "macaddress": "52:54:00:3e:04:ce",
+ "module": "virtio_net",
+ "mtu": 1500,
+ "pciid": "virtio0",
+ "promisc": false,
+ "timestamping": [
+ "rx_software",
+ "software"
+ ],
+ "type": "ether"
+ },
+ "ansible_fibre_channel_wwn": [],
+ "ansible_fips": false,
+ "ansible_form_factor": "Other",
+ "ansible_fqdn": "centos7-host1.tf.local",
+ "ansible_hostname": "centos7-host1",
+ "ansible_hostnqn": "",
+ "ansible_interfaces": [
+ "lo",
+ "eth0"
+ ],
+ "ansible_is_chroot": false,
+ "ansible_iscsi_iqn": "",
+ "ansible_kernel": "3.10.0-862.el7.x86_64",
+ "ansible_kernel_version": "#1 SMP Fri Apr 20 16:44:24 UTC 2018",
+ "ansible_lo": {
+ "active": true,
+ "device": "lo",
+ "features": {
+ "busy_poll": "off [fixed]",
+ "fcoe_mtu": "off [fixed]",
+ "generic_receive_offload": "on",
+ "generic_segmentation_offload": "on",
+ "highdma": "on [fixed]",
+ "hw_tc_offload": "off [fixed]",
+ "l2_fwd_offload": "off [fixed]",
+ "large_receive_offload": "off [fixed]",
+ "loopback": "on [fixed]",
+ "netns_local": "on [fixed]",
+ "ntuple_filters": "off [fixed]",
+ "receive_hashing": "off [fixed]",
+ "rx_all": "off [fixed]",
+ "rx_checksumming": "on [fixed]",
+ "rx_fcs": "off [fixed]",
+ "rx_udp_tunnel_port_offload": "off [fixed]",
+ "rx_vlan_filter": "off [fixed]",
+ "rx_vlan_offload": "off [fixed]",
+ "rx_vlan_stag_filter": "off [fixed]",
+ "rx_vlan_stag_hw_parse": "off [fixed]",
+ "scatter_gather": "on",
+ "tcp_segmentation_offload": "on",
+ "tx_checksum_fcoe_crc": "off [fixed]",
+ "tx_checksum_ip_generic": "on [fixed]",
+ "tx_checksum_ipv4": "off [fixed]",
+ "tx_checksum_ipv6": "off [fixed]",
+ "tx_checksum_sctp": "on [fixed]",
+ "tx_checksumming": "on",
+ "tx_fcoe_segmentation": "off [fixed]",
+ "tx_gre_csum_segmentation": "off [fixed]",
+ "tx_gre_segmentation": "off [fixed]",
+ "tx_gso_partial": "off [fixed]",
+ "tx_gso_robust": "off [fixed]",
+ "tx_ipip_segmentation": "off [fixed]",
+ "tx_lockless": "on [fixed]",
+ "tx_nocache_copy": "off [fixed]",
+ "tx_scatter_gather": "on [fixed]",
+ "tx_scatter_gather_fraglist": "on [fixed]",
+ "tx_sctp_segmentation": "on",
+ "tx_sit_segmentation": "off [fixed]",
+ "tx_tcp6_segmentation": "on",
+ "tx_tcp_ecn_segmentation": "on",
+ "tx_tcp_mangleid_segmentation": "on",
+ "tx_tcp_segmentation": "on",
+ "tx_udp_tnl_csum_segmentation": "off [fixed]",
+ "tx_udp_tnl_segmentation": "off [fixed]",
+ "tx_vlan_offload": "off [fixed]",
+ "tx_vlan_stag_hw_insert": "off [fixed]",
+ "udp_fragmentation_offload": "on",
+ "vlan_challenged": "on [fixed]"
+ },
+ "hw_timestamp_filters": [],
+ "ipv4": {
+ "address": "127.0.0.1",
+ "broadcast": "host",
+ "netmask": "255.0.0.0",
+ "network": "127.0.0.0"
+ },
+ "ipv6": [
+ {
+ "address": "::1",
+ "prefix": "128",
+ "scope": "host"
+ }
+ ],
+ "mtu": 65536,
+ "promisc": false,
+ "timestamping": [
+ "rx_software",
+ "software"
+ ],
+ "type": "loopback"
+ },
+ "ansible_local": {},
+ "ansible_lsb": {},
+ "ansible_machine": "x86_64",
+ "ansible_machine_id": "d5f025e24919a00e864180785ebaa8c9",
+ "ansible_memfree_mb": 717,
+ "ansible_memory_mb": {
+ "nocache": {
+ "free": 893,
+ "used": 98
+ },
+ "real": {
+ "free": 717,
+ "total": 991,
+ "used": 274
+ },
+ "swap": {
+ "cached": 0,
+ "free": 2048,
+ "total": 2048,
+ "used": 0
+ }
+ },
+ "ansible_memtotal_mb": 991,
+ "ansible_mounts": [
+ {
+ "block_available": 243103,
+ "block_size": 4096,
+ "block_total": 259584,
+ "block_used": 16481,
+ "device": "/dev/vda1",
+ "fstype": "xfs",
+ "inode_available": 523998,
+ "inode_total": 524288,
+ "inode_used": 290,
+ "mount": "/boot",
+ "options": "rw,relatime,attr2,inode64,noquota",
+ "size_available": 995749888,
+ "size_total": 1063256064,
+ "uuid": "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ },
+ {
+ "block_available": 12902656,
+ "block_size": 4096,
+ "block_total": 13100800,
+ "block_used": 198144,
+ "device": "/dev/vda3",
+ "fstype": "xfs",
+ "inode_available": 26189994,
+ "inode_total": 26214400,
+ "inode_used": 24406,
+ "mount": "/",
+ "options": "rw,relatime,attr2,inode64,noquota",
+ "size_available": 52849278976,
+ "size_total": 53660876800,
+ "uuid": "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ {
+ "block_available": 38507349,
+ "block_size": 4096,
+ "block_total": 38515585,
+ "block_used": 8236,
+ "device": "/dev/vda5",
+ "fstype": "xfs",
+ "inode_available": 77068797,
+ "inode_total": 77068800,
+ "inode_used": 3,
+ "mount": "/home",
+ "options": "rw,relatime,attr2,inode64,noquota",
+ "size_available": 157726101504,
+ "size_total": 157759836160,
+ "uuid": "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ }
+ ],
+ "ansible_nodename": "centos7-host1",
+ "ansible_os_family": "RedHat",
+ "ansible_pkg_mgr": "yum",
+ "ansible_proc_cmdline": {
+ "BOOT_IMAGE": "/vmlinuz-3.10.0-862.el7.x86_64",
+ "LANG": "en_US.UTF-8",
+ "console": "ttyS0,115200",
+ "crashkernel": "auto",
+ "quiet": true,
+ "rhgb": true,
+ "ro": true,
+ "root": "UUID=2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ "ansible_processor": [
+ "0",
+ "GenuineIntel",
+ "QEMU Virtual CPU version 2.5+"
+ ],
+ "ansible_processor_cores": 1,
+ "ansible_processor_count": 1,
+ "ansible_processor_threads_per_core": 1,
+ "ansible_processor_vcpus": 1,
+ "ansible_product_name": "Standard PC (i440FX + PIIX, 1996)",
+ "ansible_product_serial": "NA",
+ "ansible_product_uuid": "18FEBA4D-2060-45E8-87AF-AD6574F522CC",
+ "ansible_product_version": "pc-i440fx-4.2",
+ "ansible_python": {
+ "executable": "/usr/bin/python",
+ "has_sslcontext": true,
+ "type": "CPython",
+ "version": {
+ "major": 2,
+ "micro": 5,
+ "minor": 7,
+ "releaselevel": "final",
+ "serial": 0
+ },
+ "version_info": [
+ 2,
+ 7,
+ 5,
+ "final",
+ 0
+ ]
+ },
+ "ansible_python_version": "2.7.5",
+ "ansible_real_group_id": 0,
+ "ansible_real_user_id": 0,
+ "ansible_selinux": {
+ "status": "disabled"
+ },
+ "ansible_selinux_python_present": true,
+ "ansible_service_mgr": "systemd",
+ "ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBE3bXHUHyjmlbxE6LCP2ohRTr0pTX7sq89g0yKvovFK1qhP1rsBvy2jW8wjo2P8mlBWhL7obRGl8B+i3cMxZdrc=",
+ "ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIHv4wovK7u1Est8e1rMvQifupxLPpxtNEJIvKHq/iIVF",
+ "ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDPW4spvldGYXFraJCWJAqkuyQQRogSL+aECRU0hAG+IwESq3ceVkUZrvMVnhxmVImcRGWLCP24wmiMC2G/sDMHfBIhQIc4ySvLLyVd20VIsQHWiODQsSZTKCWkIwNmWuUD/8FcIpHm4YKlzZdHRVPwx9oIkdzoxgGyGZ3em7QwhryPZ+GiK8P9dEE2xy2lfAMXCFEL6Eyw/WF1AS0KLZiKl5ct9aYedUZN1rWkWW1Kb9S+OsZ+qzjdZbU2EfQI8SnP8kkvKt1E/B1UnsfZ5R0nlsyIX6Bh8oCluqJrxXrsTBf/s4Pe76/Q7JH/QHp2Yw+sQb+l7wXhlNmDRTpqXDdR",
+ "ansible_swapfree_mb": 2048,
+ "ansible_swaptotal_mb": 2048,
+ "ansible_system": "Linux",
+ "ansible_system_capabilities": [
+ "cap_chown",
+ "cap_dac_override",
+ "cap_dac_read_search",
+ "cap_fowner",
+ "cap_fsetid",
+ "cap_kill",
+ "cap_setgid",
+ "cap_setuid",
+ "cap_setpcap",
+ "cap_linux_immutable",
+ "cap_net_bind_service",
+ "cap_net_broadcast",
+ "cap_net_admin",
+ "cap_net_raw",
+ "cap_ipc_lock",
+ "cap_ipc_owner",
+ "cap_sys_module",
+ "cap_sys_rawio",
+ "cap_sys_chroot",
+ "cap_sys_ptrace",
+ "cap_sys_pacct",
+ "cap_sys_admin",
+ "cap_sys_boot",
+ "cap_sys_nice",
+ "cap_sys_resource",
+ "cap_sys_time",
+ "cap_sys_tty_config",
+ "cap_mknod",
+ "cap_lease",
+ "cap_audit_write",
+ "cap_audit_control",
+ "cap_setfcap",
+ "cap_mac_override",
+ "cap_mac_admin",
+ "cap_syslog",
+ "35",
+ "36+ep"
+ ],
+ "ansible_system_capabilities_enforced": "True",
+ "ansible_system_vendor": "QEMU",
+ "ansible_uptime_seconds": 178555,
+ "ansible_user_dir": "/root",
+ "ansible_user_gecos": "root",
+ "ansible_user_gid": 0,
+ "ansible_user_id": "root",
+ "ansible_user_shell": "/bin/bash",
+ "ansible_user_uid": 0,
+ "ansible_userspace_architecture": "x86_64",
+ "ansible_userspace_bits": "64",
+ "ansible_virtualization_role": "guest",
+ "ansible_virtualization_type": "kvm",
+ "discovered_interpreter_python": "/usr/bin/python",
+ "gather_subset": [
+ "all"
+ ],
+ "module_setup": true
+ },
+ "changed": false,
+ "deprecations": [],
+ "warnings": []
+ }
+ },
+ "task": {
+ "duration": {
+ "end": "2020-08-14T11:55:31.760375Z",
+ "start": "2020-08-14T11:55:30.470536Z"
+ },
+ "id": "5254001e-9fce-297d-21cd-00000000000f",
+ "name": "Gathering Facts"
+ }
+ },
+ {
+ "hosts": {
+ "centos7-host1.tf.local": {
+ "_ansible_no_log": false,
+ "action": "yum",
+ "changed": false,
+ "invocation": {
+ "module_args": {
+ "allow_downgrade": false,
+ "autoremove": false,
+ "bugfix": false,
+ "conf_file": null,
+ "disable_excludes": null,
+ "disable_gpg_check": false,
+ "disable_plugin": [],
+ "disablerepo": [],
+ "download_dir": null,
+ "download_only": false,
+ "enable_plugin": [],
+ "enablerepo": [],
+ "exclude": [],
+ "install_repoquery": true,
+ "install_weak_deps": true,
+ "installroot": "/",
+ "list": null,
+ "lock_timeout": 30,
+ "name": [
+ "httpd"
+ ],
+ "releasever": null,
+ "security": false,
+ "skip_broken": false,
+ "state": "present",
+ "update_cache": false,
+ "update_only": false,
+ "use_backend": "auto",
+ "validate_certs": true
+ }
+ },
+ "msg": "",
+ "rc": 0,
+ "results": [
+ "httpd-2.4.6-93.el7.centos.x86_64 providing httpd is already installed"
+ ]
+ }
+ },
+ "task": {
+ "duration": {
+ "end": "2020-08-14T11:55:32.952644Z",
+ "start": "2020-08-14T11:55:31.776073Z"
+ },
+ "id": "5254001e-9fce-297d-21cd-000000000009",
+ "name": "yum"
+ }
+ },
+ {
+ "hosts": {
+ "centos7-host1.tf.local": {
+ "_ansible_no_log": false,
+ "action": "yum",
+ "changed": false,
+ "failed": true,
+ "invocation": {
+ "module_args": {
+ "allow_downgrade": false,
+ "autoremove": false,
+ "bugfix": false,
+ "conf_file": null,
+ "disable_excludes": null,
+ "disable_gpg_check": false,
+ "disable_plugin": [],
+ "disablerepo": [],
+ "download_dir": null,
+ "download_only": false,
+ "enable_plugin": [],
+ "enablerepo": [],
+ "exclude": [],
+ "install_repoquery": true,
+ "install_weak_deps": true,
+ "installroot": "/",
+ "list": null,
+ "lock_timeout": 30,
+ "name": [
+ "rsyndc"
+ ],
+ "releasever": null,
+ "security": false,
+ "skip_broken": false,
+ "state": "present",
+ "update_cache": false,
+ "update_only": false,
+ "use_backend": "auto",
+ "validate_certs": true
+ }
+ },
+ "msg": "No package matching 'rsyndc' found available, installed or updated",
+ "rc": 126,
+ "results": [
+ "No package matching 'rsyndc' found available, installed or updated"
+ ]
+ }
+ },
+ "task": {
+ "duration": {
+ "end": "2020-08-14T11:55:33.889442Z",
+ "start": "2020-08-14T11:55:32.969762Z"
+ },
+ "id": "5254001e-9fce-297d-21cd-00000000000a",
+ "name": "yum"
+ }
+ }
+ ]
+ }
+ ],
+ "stats": {
+ "centos7-host1.tf.local": {
+ "changed": 0,
+ "failures": 1,
+ "ignored": 0,
+ "ok": 2,
+ "rescued": 0,
+ "skipped": 0,
+ "unreachable": 0
+ }
+ },
+ "retcode": 2
+}
diff --git a/tests/unit/files/playbooks/success_example.json b/tests/unit/files/playbooks/success_example.json
new file mode 100644
index 0000000000..8a9f3ad868
--- /dev/null
+++ b/tests/unit/files/playbooks/success_example.json
@@ -0,0 +1,803 @@
+{
+ "custom_stats": {},
+ "global_custom_stats": {},
+ "plays": [
+ {
+ "play": {
+ "duration": {
+ "end": "2020-08-14T11:55:58.334076Z",
+ "start": "2020-08-14T11:55:54.295001Z"
+ },
+ "id": "5254001e-9fce-f8b5-c66a-000000000007",
+ "name": "py2hosts"
+ },
+ "tasks": [
+ {
+ "hosts": {
+ "centos7-host1.tf.local": {
+ "_ansible_no_log": false,
+ "_ansible_verbose_override": true,
+ "action": "gather_facts",
+ "ansible_facts": {
+ "ansible_all_ipv4_addresses": [
+ "192.168.122.29"
+ ],
+ "ansible_all_ipv6_addresses": [
+ "fe80::5054:ff:fe3e:4ce"
+ ],
+ "ansible_apparmor": {
+ "status": "disabled"
+ },
+ "ansible_architecture": "x86_64",
+ "ansible_bios_date": "04/01/2014",
+ "ansible_bios_version": "rel-1.13.0-0-gf21b5a4-rebuilt.opensuse.org",
+ "ansible_cmdline": {
+ "BOOT_IMAGE": "/vmlinuz-3.10.0-862.el7.x86_64",
+ "LANG": "en_US.UTF-8",
+ "console": "ttyS0,115200",
+ "crashkernel": "auto",
+ "quiet": true,
+ "rhgb": true,
+ "ro": true,
+ "root": "UUID=2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ "ansible_date_time": {
+ "date": "2020-08-14",
+ "day": "14",
+ "epoch": "1597406155",
+ "hour": "13",
+ "iso8601": "2020-08-14T11:55:55Z",
+ "iso8601_basic": "20200814T135555808955",
+ "iso8601_basic_short": "20200814T135555",
+ "iso8601_micro": "2020-08-14T11:55:55.809048Z",
+ "minute": "55",
+ "month": "08",
+ "second": "55",
+ "time": "13:55:55",
+ "tz": "CEST",
+ "tz_offset": "+0200",
+ "weekday": "Friday",
+ "weekday_number": "5",
+ "weeknumber": "32",
+ "year": "2020"
+ },
+ "ansible_default_ipv4": {
+ "address": "192.168.122.29",
+ "alias": "eth0",
+ "broadcast": "192.168.122.255",
+ "gateway": "192.168.122.1",
+ "interface": "eth0",
+ "macaddress": "52:54:00:3e:04:ce",
+ "mtu": 1500,
+ "netmask": "255.255.255.0",
+ "network": "192.168.122.0",
+ "type": "ether"
+ },
+ "ansible_default_ipv6": {},
+ "ansible_device_links": {
+ "ids": {},
+ "labels": {},
+ "masters": {},
+ "uuids": {
+ "vda1": [
+ "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ ],
+ "vda2": [
+ "5ec08dbf-55e4-4fb1-a866-7b0fedcb4a24"
+ ],
+ "vda3": [
+ "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ ],
+ "vda5": [
+ "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ ]
+ }
+ },
+ "ansible_devices": {
+ "vda": {
+ "holders": [],
+ "host": "",
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": []
+ },
+ "model": null,
+ "partitions": {
+ "vda1": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ ]
+ },
+ "sectors": "2097152",
+ "sectorsize": 512,
+ "size": "1.00 GB",
+ "start": "2048",
+ "uuid": "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ },
+ "vda2": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "5ec08dbf-55e4-4fb1-a866-7b0fedcb4a24"
+ ]
+ },
+ "sectors": "4196352",
+ "sectorsize": 512,
+ "size": "2.00 GB",
+ "start": "2099200",
+ "uuid": "5ec08dbf-55e4-4fb1-a866-7b0fedcb4a24"
+ },
+ "vda3": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ ]
+ },
+ "sectors": "104857600",
+ "sectorsize": 512,
+ "size": "50.00 GB",
+ "start": "6295552",
+ "uuid": "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ "vda4": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": []
+ },
+ "sectors": "2",
+ "sectorsize": 512,
+ "size": "1.00 KB",
+ "start": "111153152",
+ "uuid": null
+ },
+ "vda5": {
+ "holders": [],
+ "links": {
+ "ids": [],
+ "labels": [],
+ "masters": [],
+ "uuids": [
+ "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ ]
+ },
+ "sectors": "308275200",
+ "sectorsize": 512,
+ "size": "147.00 GB",
+ "start": "111155200",
+ "uuid": "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ }
+ },
+ "removable": "0",
+ "rotational": "1",
+ "sas_address": null,
+ "sas_device_handle": null,
+ "scheduler_mode": "mq-deadline",
+ "sectors": "419430400",
+ "sectorsize": "512",
+ "size": "200.00 GB",
+ "support_discard": "0",
+ "vendor": "0x1af4",
+ "virtual": 1
+ }
+ },
+ "ansible_distribution": "CentOS",
+ "ansible_distribution_file_parsed": true,
+ "ansible_distribution_file_path": "/etc/redhat-release",
+ "ansible_distribution_file_variety": "RedHat",
+ "ansible_distribution_major_version": "7",
+ "ansible_distribution_release": "Core",
+ "ansible_distribution_version": "7.5",
+ "ansible_dns": {
+ "nameservers": [
+ "192.168.122.1"
+ ]
+ },
+ "ansible_domain": "tf.local",
+ "ansible_effective_group_id": 0,
+ "ansible_effective_user_id": 0,
+ "ansible_env": {
+ "HOME": "/root",
+ "LANG": "es_ES.utf8",
+ "LC_ADDRESS": "C",
+ "LC_COLLATE": "C",
+ "LC_CTYPE": "C",
+ "LC_IDENTIFICATION": "C",
+ "LC_MEASUREMENT": "C",
+ "LC_MESSAGES": "C",
+ "LC_MONETARY": "C",
+ "LC_NAME": "C",
+ "LC_NUMERIC": "C",
+ "LC_PAPER": "C",
+ "LC_TELEPHONE": "C",
+ "LC_TIME": "C",
+ "LESSOPEN": "||/usr/bin/lesspipe.sh %s",
+ "LOGNAME": "root",
+ "LS_COLORS": "rs=0:di=38;5;27:ln=38;5;51:mh=44;38;5;15:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=05;48;5;232;38;5;15:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;34:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.Z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.axv=38;5;13:*.anx=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.axa=38;5;45:*.oga=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:",
+ "MAIL": "/var/mail/root",
+ "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
+ "PWD": "/root",
+ "SHELL": "/bin/bash",
+ "SHLVL": "2",
+ "SSH_CLIENT": "192.168.122.179 55766 22",
+ "SSH_CONNECTION": "192.168.122.179 55766 192.168.122.29 22",
+ "SSH_TTY": "/dev/pts/0",
+ "TERM": "xterm-256color",
+ "USER": "root",
+ "XDG_RUNTIME_DIR": "/run/user/0",
+ "XDG_SESSION_ID": "110",
+ "_": "/usr/bin/python"
+ },
+ "ansible_eth0": {
+ "active": true,
+ "device": "eth0",
+ "features": {
+ "busy_poll": "off [fixed]",
+ "fcoe_mtu": "off [fixed]",
+ "generic_receive_offload": "on",
+ "generic_segmentation_offload": "on",
+ "highdma": "on [fixed]",
+ "hw_tc_offload": "off [fixed]",
+ "l2_fwd_offload": "off [fixed]",
+ "large_receive_offload": "off [fixed]",
+ "loopback": "off [fixed]",
+ "netns_local": "off [fixed]",
+ "ntuple_filters": "off [fixed]",
+ "receive_hashing": "off [fixed]",
+ "rx_all": "off [fixed]",
+ "rx_checksumming": "on [fixed]",
+ "rx_fcs": "off [fixed]",
+ "rx_udp_tunnel_port_offload": "off [fixed]",
+ "rx_vlan_filter": "on [fixed]",
+ "rx_vlan_offload": "off [fixed]",
+ "rx_vlan_stag_filter": "off [fixed]",
+ "rx_vlan_stag_hw_parse": "off [fixed]",
+ "scatter_gather": "on",
+ "tcp_segmentation_offload": "on",
+ "tx_checksum_fcoe_crc": "off [fixed]",
+ "tx_checksum_ip_generic": "on",
+ "tx_checksum_ipv4": "off [fixed]",
+ "tx_checksum_ipv6": "off [fixed]",
+ "tx_checksum_sctp": "off [fixed]",
+ "tx_checksumming": "on",
+ "tx_fcoe_segmentation": "off [fixed]",
+ "tx_gre_csum_segmentation": "off [fixed]",
+ "tx_gre_segmentation": "off [fixed]",
+ "tx_gso_partial": "off [fixed]",
+ "tx_gso_robust": "off [fixed]",
+ "tx_ipip_segmentation": "off [fixed]",
+ "tx_lockless": "off [fixed]",
+ "tx_nocache_copy": "off",
+ "tx_scatter_gather": "on",
+ "tx_scatter_gather_fraglist": "off [fixed]",
+ "tx_sctp_segmentation": "off [fixed]",
+ "tx_sit_segmentation": "off [fixed]",
+ "tx_tcp6_segmentation": "on",
+ "tx_tcp_ecn_segmentation": "on",
+ "tx_tcp_mangleid_segmentation": "off",
+ "tx_tcp_segmentation": "on",
+ "tx_udp_tnl_csum_segmentation": "off [fixed]",
+ "tx_udp_tnl_segmentation": "off [fixed]",
+ "tx_vlan_offload": "off [fixed]",
+ "tx_vlan_stag_hw_insert": "off [fixed]",
+ "udp_fragmentation_offload": "on",
+ "vlan_challenged": "off [fixed]"
+ },
+ "hw_timestamp_filters": [],
+ "ipv4": {
+ "address": "192.168.122.29",
+ "broadcast": "192.168.122.255",
+ "netmask": "255.255.255.0",
+ "network": "192.168.122.0"
+ },
+ "ipv6": [
+ {
+ "address": "fe80::5054:ff:fe3e:4ce",
+ "prefix": "64",
+ "scope": "link"
+ }
+ ],
+ "macaddress": "52:54:00:3e:04:ce",
+ "module": "virtio_net",
+ "mtu": 1500,
+ "pciid": "virtio0",
+ "promisc": false,
+ "timestamping": [
+ "rx_software",
+ "software"
+ ],
+ "type": "ether"
+ },
+ "ansible_fibre_channel_wwn": [],
+ "ansible_fips": false,
+ "ansible_form_factor": "Other",
+ "ansible_fqdn": "centos7-host1.tf.local",
+ "ansible_hostname": "centos7-host1",
+ "ansible_hostnqn": "",
+ "ansible_interfaces": [
+ "lo",
+ "eth0"
+ ],
+ "ansible_is_chroot": false,
+ "ansible_iscsi_iqn": "",
+ "ansible_kernel": "3.10.0-862.el7.x86_64",
+ "ansible_kernel_version": "#1 SMP Fri Apr 20 16:44:24 UTC 2018",
+ "ansible_lo": {
+ "active": true,
+ "device": "lo",
+ "features": {
+ "busy_poll": "off [fixed]",
+ "fcoe_mtu": "off [fixed]",
+ "generic_receive_offload": "on",
+ "generic_segmentation_offload": "on",
+ "highdma": "on [fixed]",
+ "hw_tc_offload": "off [fixed]",
+ "l2_fwd_offload": "off [fixed]",
+ "large_receive_offload": "off [fixed]",
+ "loopback": "on [fixed]",
+ "netns_local": "on [fixed]",
+ "ntuple_filters": "off [fixed]",
+ "receive_hashing": "off [fixed]",
+ "rx_all": "off [fixed]",
+ "rx_checksumming": "on [fixed]",
+ "rx_fcs": "off [fixed]",
+ "rx_udp_tunnel_port_offload": "off [fixed]",
+ "rx_vlan_filter": "off [fixed]",
+ "rx_vlan_offload": "off [fixed]",
+ "rx_vlan_stag_filter": "off [fixed]",
+ "rx_vlan_stag_hw_parse": "off [fixed]",
+ "scatter_gather": "on",
+ "tcp_segmentation_offload": "on",
+ "tx_checksum_fcoe_crc": "off [fixed]",
+ "tx_checksum_ip_generic": "on [fixed]",
+ "tx_checksum_ipv4": "off [fixed]",
+ "tx_checksum_ipv6": "off [fixed]",
+ "tx_checksum_sctp": "on [fixed]",
+ "tx_checksumming": "on",
+ "tx_fcoe_segmentation": "off [fixed]",
+ "tx_gre_csum_segmentation": "off [fixed]",
+ "tx_gre_segmentation": "off [fixed]",
+ "tx_gso_partial": "off [fixed]",
+ "tx_gso_robust": "off [fixed]",
+ "tx_ipip_segmentation": "off [fixed]",
+ "tx_lockless": "on [fixed]",
+ "tx_nocache_copy": "off [fixed]",
+ "tx_scatter_gather": "on [fixed]",
+ "tx_scatter_gather_fraglist": "on [fixed]",
+ "tx_sctp_segmentation": "on",
+ "tx_sit_segmentation": "off [fixed]",
+ "tx_tcp6_segmentation": "on",
+ "tx_tcp_ecn_segmentation": "on",
+ "tx_tcp_mangleid_segmentation": "on",
+ "tx_tcp_segmentation": "on",
+ "tx_udp_tnl_csum_segmentation": "off [fixed]",
+ "tx_udp_tnl_segmentation": "off [fixed]",
+ "tx_vlan_offload": "off [fixed]",
+ "tx_vlan_stag_hw_insert": "off [fixed]",
+ "udp_fragmentation_offload": "on",
+ "vlan_challenged": "on [fixed]"
+ },
+ "hw_timestamp_filters": [],
+ "ipv4": {
+ "address": "127.0.0.1",
+ "broadcast": "host",
+ "netmask": "255.0.0.0",
+ "network": "127.0.0.0"
+ },
+ "ipv6": [
+ {
+ "address": "::1",
+ "prefix": "128",
+ "scope": "host"
+ }
+ ],
+ "mtu": 65536,
+ "promisc": false,
+ "timestamping": [
+ "rx_software",
+ "software"
+ ],
+ "type": "loopback"
+ },
+ "ansible_local": {},
+ "ansible_lsb": {},
+ "ansible_machine": "x86_64",
+ "ansible_machine_id": "d5f025e24919a00e864180785ebaa8c9",
+ "ansible_memfree_mb": 717,
+ "ansible_memory_mb": {
+ "nocache": {
+ "free": 893,
+ "used": 98
+ },
+ "real": {
+ "free": 717,
+ "total": 991,
+ "used": 274
+ },
+ "swap": {
+ "cached": 0,
+ "free": 2048,
+ "total": 2048,
+ "used": 0
+ }
+ },
+ "ansible_memtotal_mb": 991,
+ "ansible_mounts": [
+ {
+ "block_available": 243103,
+ "block_size": 4096,
+ "block_total": 259584,
+ "block_used": 16481,
+ "device": "/dev/vda1",
+ "fstype": "xfs",
+ "inode_available": 523998,
+ "inode_total": 524288,
+ "inode_used": 290,
+ "mount": "/boot",
+ "options": "rw,relatime,attr2,inode64,noquota",
+ "size_available": 995749888,
+ "size_total": 1063256064,
+ "uuid": "81b5a934-1fbb-4d6f-a972-bc7c9eb48345"
+ },
+ {
+ "block_available": 12902661,
+ "block_size": 4096,
+ "block_total": 13100800,
+ "block_used": 198139,
+ "device": "/dev/vda3",
+ "fstype": "xfs",
+ "inode_available": 26189994,
+ "inode_total": 26214400,
+ "inode_used": 24406,
+ "mount": "/",
+ "options": "rw,relatime,attr2,inode64,noquota",
+ "size_available": 52849299456,
+ "size_total": 53660876800,
+ "uuid": "2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ {
+ "block_available": 38507349,
+ "block_size": 4096,
+ "block_total": 38515585,
+ "block_used": 8236,
+ "device": "/dev/vda5",
+ "fstype": "xfs",
+ "inode_available": 77068797,
+ "inode_total": 77068800,
+ "inode_used": 3,
+ "mount": "/home",
+ "options": "rw,relatime,attr2,inode64,noquota",
+ "size_available": 157726101504,
+ "size_total": 157759836160,
+ "uuid": "7f7965bf-54e8-43d4-a2f6-cb7f56a9a249"
+ }
+ ],
+ "ansible_nodename": "centos7-host1",
+ "ansible_os_family": "RedHat",
+ "ansible_pkg_mgr": "yum",
+ "ansible_proc_cmdline": {
+ "BOOT_IMAGE": "/vmlinuz-3.10.0-862.el7.x86_64",
+ "LANG": "en_US.UTF-8",
+ "console": "ttyS0,115200",
+ "crashkernel": "auto",
+ "quiet": true,
+ "rhgb": true,
+ "ro": true,
+ "root": "UUID=2b13ca03-1e1d-4f51-8929-4e7fef390e0c"
+ },
+ "ansible_processor": [
+ "0",
+ "GenuineIntel",
+ "QEMU Virtual CPU version 2.5+"
+ ],
+ "ansible_processor_cores": 1,
+ "ansible_processor_count": 1,
+ "ansible_processor_threads_per_core": 1,
+ "ansible_processor_vcpus": 1,
+ "ansible_product_name": "Standard PC (i440FX + PIIX, 1996)",
+ "ansible_product_serial": "NA",
+ "ansible_product_uuid": "18FEBA4D-2060-45E8-87AF-AD6574F522CC",
+ "ansible_product_version": "pc-i440fx-4.2",
+ "ansible_python": {
+ "executable": "/usr/bin/python",
+ "has_sslcontext": true,
+ "type": "CPython",
+ "version": {
+ "major": 2,
+ "micro": 5,
+ "minor": 7,
+ "releaselevel": "final",
+ "serial": 0
+ },
+ "version_info": [
+ 2,
+ 7,
+ 5,
+ "final",
+ 0
+ ]
+ },
+ "ansible_python_version": "2.7.5",
+ "ansible_real_group_id": 0,
+ "ansible_real_user_id": 0,
+ "ansible_selinux": {
+ "status": "disabled"
+ },
+ "ansible_selinux_python_present": true,
+ "ansible_service_mgr": "systemd",
+ "ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBE3bXHUHyjmlbxE6LCP2ohRTr0pTX7sq89g0yKvovFK1qhP1rsBvy2jW8wjo2P8mlBWhL7obRGl8B+i3cMxZdrc=",
+ "ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIHv4wovK7u1Est8e1rMvQifupxLPpxtNEJIvKHq/iIVF",
+ "ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDPW4spvldGYXFraJCWJAqkuyQQRogSL+aECRU0hAG+IwESq3ceVkUZrvMVnhxmVImcRGWLCP24wmiMC2G/sDMHfBIhQIc4ySvLLyVd20VIsQHWiODQsSZTKCWkIwNmWuUD/8FcIpHm4YKlzZdHRVPwx9oIkdzoxgGyGZ3em7QwhryPZ+GiK8P9dEE2xy2lfAMXCFEL6Eyw/WF1AS0KLZiKl5ct9aYedUZN1rWkWW1Kb9S+OsZ+qzjdZbU2EfQI8SnP8kkvKt1E/B1UnsfZ5R0nlsyIX6Bh8oCluqJrxXrsTBf/s4Pe76/Q7JH/QHp2Yw+sQb+l7wXhlNmDRTpqXDdR",
+ "ansible_swapfree_mb": 2048,
+ "ansible_swaptotal_mb": 2048,
+ "ansible_system": "Linux",
+ "ansible_system_capabilities": [
+ "cap_chown",
+ "cap_dac_override",
+ "cap_dac_read_search",
+ "cap_fowner",
+ "cap_fsetid",
+ "cap_kill",
+ "cap_setgid",
+ "cap_setuid",
+ "cap_setpcap",
+ "cap_linux_immutable",
+ "cap_net_bind_service",
+ "cap_net_broadcast",
+ "cap_net_admin",
+ "cap_net_raw",
+ "cap_ipc_lock",
+ "cap_ipc_owner",
+ "cap_sys_module",
+ "cap_sys_rawio",
+ "cap_sys_chroot",
+ "cap_sys_ptrace",
+ "cap_sys_pacct",
+ "cap_sys_admin",
+ "cap_sys_boot",
+ "cap_sys_nice",
+ "cap_sys_resource",
+ "cap_sys_time",
+ "cap_sys_tty_config",
+ "cap_mknod",
+ "cap_lease",
+ "cap_audit_write",
+ "cap_audit_control",
+ "cap_setfcap",
+ "cap_mac_override",
+ "cap_mac_admin",
+ "cap_syslog",
+ "35",
+ "36+ep"
+ ],
+ "ansible_system_capabilities_enforced": "True",
+ "ansible_system_vendor": "QEMU",
+ "ansible_uptime_seconds": 178578,
+ "ansible_user_dir": "/root",
+ "ansible_user_gecos": "root",
+ "ansible_user_gid": 0,
+ "ansible_user_id": "root",
+ "ansible_user_shell": "/bin/bash",
+ "ansible_user_uid": 0,
+ "ansible_userspace_architecture": "x86_64",
+ "ansible_userspace_bits": "64",
+ "ansible_virtualization_role": "guest",
+ "ansible_virtualization_type": "kvm",
+ "discovered_interpreter_python": "/usr/bin/python",
+ "gather_subset": [
+ "all"
+ ],
+ "module_setup": true
+ },
+ "changed": false,
+ "deprecations": [],
+ "warnings": []
+ }
+ },
+ "task": {
+ "duration": {
+ "end": "2020-08-14T11:55:55.578128Z",
+ "start": "2020-08-14T11:55:54.313122Z"
+ },
+ "id": "5254001e-9fce-f8b5-c66a-00000000000f",
+ "name": "Gathering Facts"
+ }
+ },
+ {
+ "hosts": {
+ "centos7-host1.tf.local": {
+ "_ansible_no_log": false,
+ "action": "yum",
+ "changed": false,
+ "invocation": {
+ "module_args": {
+ "allow_downgrade": false,
+ "autoremove": false,
+ "bugfix": false,
+ "conf_file": null,
+ "disable_excludes": null,
+ "disable_gpg_check": false,
+ "disable_plugin": [],
+ "disablerepo": [],
+ "download_dir": null,
+ "download_only": false,
+ "enable_plugin": [],
+ "enablerepo": [],
+ "exclude": [],
+ "install_repoquery": true,
+ "install_weak_deps": true,
+ "installroot": "/",
+ "list": null,
+ "lock_timeout": 30,
+ "name": [
+ "httpd"
+ ],
+ "releasever": null,
+ "security": false,
+ "skip_broken": false,
+ "state": "present",
+ "update_cache": false,
+ "update_only": false,
+ "use_backend": "auto",
+ "validate_certs": true
+ }
+ },
+ "msg": "",
+ "rc": 0,
+ "results": [
+ "httpd-2.4.6-93.el7.centos.x86_64 providing httpd is already installed"
+ ]
+ }
+ },
+ "task": {
+ "duration": {
+ "end": "2020-08-14T11:55:56.737921Z",
+ "start": "2020-08-14T11:55:55.596293Z"
+ },
+ "id": "5254001e-9fce-f8b5-c66a-000000000009",
+ "name": "yum"
+ }
+ },
+ {
+ "hosts": {
+ "centos7-host1.tf.local": {
+ "_ansible_no_log": false,
+ "action": "yum",
+ "changed": false,
+ "invocation": {
+ "module_args": {
+ "allow_downgrade": false,
+ "autoremove": false,
+ "bugfix": false,
+ "conf_file": null,
+ "disable_excludes": null,
+ "disable_gpg_check": false,
+ "disable_plugin": [],
+ "disablerepo": [],
+ "download_dir": null,
+ "download_only": false,
+ "enable_plugin": [],
+ "enablerepo": [],
+ "exclude": [],
+ "install_repoquery": true,
+ "install_weak_deps": true,
+ "installroot": "/",
+ "list": null,
+ "lock_timeout": 30,
+ "name": [
+ "rsync"
+ ],
+ "releasever": null,
+ "security": false,
+ "skip_broken": false,
+ "state": "present",
+ "update_cache": false,
+ "update_only": false,
+ "use_backend": "auto",
+ "validate_certs": true
+ }
+ },
+ "msg": "",
+ "rc": 0,
+ "results": [
+ "rsync-3.1.2-10.el7.x86_64 providing rsync is already installed"
+ ]
+ }
+ },
+ "task": {
+ "duration": {
+ "end": "2020-08-14T11:55:57.609670Z",
+ "start": "2020-08-14T11:55:56.755620Z"
+ },
+ "id": "5254001e-9fce-f8b5-c66a-00000000000a",
+ "name": "yum"
+ }
+ },
+ {
+ "hosts": {
+ "centos7-host1.tf.local": {
+ "_ansible_no_log": false,
+ "action": "synchronize",
+ "changed": true,
+ "cmd": "/usr/bin/rsync --delay-updates -F --compress --delete-after --archive --rsh=/usr/bin/ssh -S none -i /etc/ansible/keys/mykey.pem -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --out-format=<<CHANGED>>%i %n%L /root/myfiles/ centos7-host1.tf.local:/var/www/html/",
+ "invocation": {
+ "module_args": {
+ "_local_rsync_password": null,
+ "_local_rsync_path": "rsync",
+ "_substitute_controller": false,
+ "archive": true,
+ "checksum": false,
+ "compress": true,
+ "copy_links": false,
+ "delete": true,
+ "dest": "centos7-host1.tf.local:/var/www/html/",
+ "dest_port": null,
+ "dirs": false,
+ "existing_only": false,
+ "group": null,
+ "link_dest": null,
+ "links": null,
+ "mode": "push",
+ "owner": null,
+ "partial": false,
+ "perms": null,
+ "private_key": "/etc/ansible/keys/mykey.pem",
+ "recursive": null,
+ "rsync_opts": [],
+ "rsync_path": null,
+ "rsync_timeout": 0,
+ "set_remote_user": true,
+ "src": "/root/myfiles/",
+ "ssh_args": null,
+ "times": null,
+ "verify_host": false
+ }
+ },
+ "msg": "<f.st...... index.html\n",
+ "rc": 0,
+ "stdout_lines": [
+ "<f.st...... index.html"
+ ]
+ }
+ },
+ "task": {
+ "duration": {
+ "end": "2020-08-14T11:55:58.334076Z",
+ "start": "2020-08-14T11:55:57.624999Z"
+ },
+ "id": "5254001e-9fce-f8b5-c66a-00000000000b",
+ "name": "Ansible copy file to remote server"
+ }
+ }
+ ]
+ }
+ ],
+ "stats": {
+ "centos7-host1.tf.local": {
+ "changed": 1,
+ "failures": 0,
+ "ignored": 0,
+ "ok": 4,
+ "rescued": 0,
+ "skipped": 0,
+ "unreachable": 0
+ }
+ },
+ "retcode": 0
+}
diff --git a/tests/unit/modules/test_ansiblegate.py b/tests/unit/modules/test_ansiblegate.py
index 05dff4a4fa..fc562605ff 100644
--- a/tests/unit/modules/test_ansiblegate.py
+++ b/tests/unit/modules/test_ansiblegate.py
@@ -177,3 +177,18 @@ description:
except AssertionError:
proc.assert_any_call(['echo', '{"ANSIBLE_MODULE_ARGS": {"_raw_params": "arg_1", "kwarg1": "foobar"}}'], stdout=-1, timeout=1200)
assert ret == {"completed": True, "timeout": 1200}
+
+ @patch('salt.utils.path.which', MagicMock(return_value=True))
+ def test_ansible_playbooks_return_retcode(self):
+ '''
+ Test ansible.playbooks execution module function include retcode in the return.
+ :return:
+ '''
+ ref_out = {
+ 'retcode': 0,
+ 'stdout': '{"foo": "bar"}'
+ }
+ cmd_run_all = MagicMock(return_value=ref_out)
+ with patch.dict(ansible.__salt__, {'cmd.run_all': cmd_run_all}):
+ ret = ansible.playbooks("fake-playbook.yml")
+ assert 'retcode' in ret
diff --git a/tests/unit/states/test_ansiblegate.py b/tests/unit/states/test_ansiblegate.py
new file mode 100644
index 0000000000..7251c2f6d5
--- /dev/null
+++ b/tests/unit/states/test_ansiblegate.py
@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020 SUSE LLC
+# 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.
+
+# Import Salt Testing Libs
+from __future__ import absolute_import, print_function, unicode_literals
+
+import json
+import os
+
+import salt.states.ansiblegate as ansible
+import salt.utils.files
+import salt.utils.platform
+from tests.support.mixins import LoaderModuleMockMixin
+from tests.support.mock import MagicMock, patch
+from tests.support.runtests import RUNTIME_VARS
+from tests.support.unit import TestCase, skipIf
+
+try:
+ import pytest
+except ImportError as import_error:
+ pytest = None
+NO_PYTEST = not bool(pytest)
+
+
+@skipIf(NO_PYTEST, False)
+@skipIf(salt.utils.platform.is_windows(), "Not supported on Windows")
+class AnsiblegateTestCase(TestCase, LoaderModuleMockMixin):
+ @classmethod
+ def setUpClass(cls):
+ cls.playbooks_examples_dir = os.path.join(
+ RUNTIME_VARS.TESTS_DIR, "unit/files/playbooks/"
+ )
+
+ def setup_loader_modules(self):
+ return {ansible: {}}
+
+ @patch("salt.utils.path.which", MagicMock(return_value=True))
+ def test_ansible_playbooks_states_success(self):
+ """
+ Test ansible.playbooks states executions success.
+ :return:
+ """
+
+ with salt.utils.files.fopen(
+ os.path.join(self.playbooks_examples_dir, "success_example.json")
+ ) as f:
+ success_output = json.loads(f.read())
+
+ with patch.dict(
+ ansible.__salt__,
+ {"ansible.playbooks": MagicMock(return_value=success_output)},
+ ):
+ with patch.dict(ansible.__opts__, {"test": False}):
+ ret = ansible.playbooks("foobar")
+ self.assertTrue(ret["result"])
+ self.assertEqual(ret["comment"], "Changes were made by playbook foobar")
+ self.assertDictEqual(
+ ret["changes"],
+ {
+ "py2hosts": {
+ "Ansible copy file to remote server": {
+ "centos7-host1.tf.local": {}
+ }
+ }
+ },
+ )
+
+ @patch("salt.utils.path.which", MagicMock(return_value=True))
+ def test_ansible_playbooks_states_failed(self):
+ """
+ Test ansible.playbooks failed states executions.
+ :return:
+ """
+
+ with salt.utils.files.fopen(
+ os.path.join(self.playbooks_examples_dir, "failed_example.json")
+ ) as f:
+ failed_output = json.loads(f.read())
+
+ with patch.dict(
+ ansible.__salt__,
+ {"ansible.playbooks": MagicMock(return_value=failed_output)},
+ ):
+ with patch.dict(ansible.__opts__, {"test": False}):
+ ret = ansible.playbooks("foobar")
+ self.assertFalse(ret["result"])
+ self.assertEqual(
+ ret["comment"], "There were some issues running the playbook foobar"
+ )
+ self.assertDictEqual(
+ ret["changes"],
+ {
+ "py2hosts": {
+ "yum": {
+ "centos7-host1.tf.local": [
+ "No package matching 'rsyndc' found available, installed or updated"
+ ]
+ }
+ }
+ },
+ )
--
2.28.0