alternatives: handle absent link, add integration tests (#27967)
* alternatives: add integration tests * alternatives: handle absent link (fix AttributeError) Error occurred at least on Debian Stretch and OpenSuse 42.2: Traceback (most recent call last): File "/tmp/ansible_RY6X41/ansible_module_alternatives.py", line 161, in <module> main() File "/tmp/ansible_RY6X41/ansible_module_alternatives.py", line 113, in main current_path = current_path_regex.search(display_output).group(1) AttributeError: 'NoneType' object has no attribute 'group' update-alternatives stdout sample: dummy - manual mode link best version is /usr/bin/dummy1 link currently absent link dummy is /usr/bin/dummy * alternatives: PEP 8 fixes * alternatives: fix copyright in integration tests * alternatives: nested loops handle more than 2 items Thanks to Michael Scherer (@mscherer) for pointing that. * alternatives: enable integration tests
This commit is contained in:
parent
6886153b54
commit
016cd0691c
15 changed files with 231 additions and 9 deletions
|
@ -77,11 +77,11 @@ from ansible.module_utils.basic import AnsibleModule
|
|||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required=True),
|
||||
path = dict(required=True, type='path'),
|
||||
link = dict(required=False, type='path'),
|
||||
priority = dict(required=False, type='int',
|
||||
argument_spec=dict(
|
||||
name=dict(required=True),
|
||||
path=dict(required=True, type='path'),
|
||||
link=dict(required=False, type='path'),
|
||||
priority=dict(required=False, type='int',
|
||||
default=50),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
|
@ -93,7 +93,7 @@ def main():
|
|||
link = params['link']
|
||||
priority = params['priority']
|
||||
|
||||
UPDATE_ALTERNATIVES = module.get_bin_path('update-alternatives',True)
|
||||
UPDATE_ALTERNATIVES = module.get_bin_path('update-alternatives', True)
|
||||
|
||||
current_path = None
|
||||
all_alternatives = []
|
||||
|
@ -111,7 +111,9 @@ def main():
|
|||
re.MULTILINE)
|
||||
alternative_regex = re.compile(r'^(\/.*)\s-\spriority', re.MULTILINE)
|
||||
|
||||
current_path = current_path_regex.search(display_output).group(1)
|
||||
match = current_path_regex.search(display_output)
|
||||
if match:
|
||||
current_path = match.group(1)
|
||||
all_alternatives = alternative_regex.findall(display_output)
|
||||
|
||||
if not link:
|
||||
|
|
5
test/integration/targets/alternatives/aliases
Normal file
5
test/integration/targets/alternatives/aliases
Normal file
|
@ -0,0 +1,5 @@
|
|||
posix/ci/group3
|
||||
destructive
|
||||
needs/root
|
||||
skip/freebsd
|
||||
skip/osx
|
62
test/integration/targets/alternatives/tasks/main.yml
Normal file
62
test/integration/targets/alternatives/tasks/main.yml
Normal file
|
@ -0,0 +1,62 @@
|
|||
# Copyright (c) 2017 Pierre-Louis Bonicoli <pierre-louis.bonicoli@libregerbil.fr>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: 'setup: create a dummy alternative'
|
||||
block:
|
||||
- import_tasks: setup.yml
|
||||
|
||||
##############
|
||||
# Test parameters:
|
||||
# link parameter present / absent ('with_link' variable)
|
||||
# with / without alternatives defined in alternatives file ('with_alternatives' variable)
|
||||
# auto / manual ('mode' variable)
|
||||
|
||||
- include_tasks: tests.yml
|
||||
with_nested:
|
||||
- [ True, False ] # with_link
|
||||
- [ True, False ] # with_alternatives
|
||||
- [ 'auto', 'manual' ] # mode
|
||||
loop_control:
|
||||
loop_var: test_conf
|
||||
|
||||
##########
|
||||
# Priority
|
||||
- block:
|
||||
- include_tasks: remove_links.yml
|
||||
- include_tasks: setup_test.yml
|
||||
# at least two iterations again
|
||||
- include_tasks: tests_set_priority.yml
|
||||
with_sequence: start=3 end=4
|
||||
vars:
|
||||
with_alternatives: True
|
||||
mode: auto
|
||||
|
||||
- block:
|
||||
- include_tasks: remove_links.yml
|
||||
- include_tasks: setup_test.yml
|
||||
# at least two iterations again
|
||||
- include_tasks: tests_set_priority.yml
|
||||
with_sequence: start=3 end=4
|
||||
vars:
|
||||
with_alternatives: False
|
||||
mode: auto
|
||||
always:
|
||||
- include_tasks: remove_links.yml
|
||||
|
||||
- file:
|
||||
path: '{{ item }}'
|
||||
state: absent
|
||||
with_items:
|
||||
- '{{ alternatives_dir }}/dummy'
|
||||
|
||||
- file:
|
||||
path: '/usr/bin/dummy{{ item }}'
|
||||
state: absent
|
||||
with_sequence: start=1 end=4
|
||||
# *Disable tests on Fedora 24*
|
||||
# Shippable Fedora 24 image provides chkconfig-1.7-2.fc24.x86_64 but not the
|
||||
# latest available version (chkconfig-1.8-1.fc24.x86_64). update-alternatives
|
||||
# in chkconfig-1.7-2 fails when /etc/alternatives/dummy link is missing,
|
||||
# error is: 'failed to read link /usr/bin/dummy: No such file or directory'.
|
||||
# Moreover Fedora 24 is no longer maintained.
|
||||
when: ansible_distribution != 'Fedora' or ansible_distribution_major_version|int > 24
|
|
@ -0,0 +1,7 @@
|
|||
- name: remove links
|
||||
file:
|
||||
path: '{{ item }}'
|
||||
state: absent
|
||||
with_items:
|
||||
- /etc/alternatives/dummy
|
||||
- /usr/bin/dummy
|
14
test/integration/targets/alternatives/tasks/setup.yml
Normal file
14
test/integration/targets/alternatives/tasks/setup.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
- include_vars: '{{ item }}'
|
||||
with_first_found:
|
||||
- files:
|
||||
- '{{ ansible_os_family }}.yml'
|
||||
- 'default.yml'
|
||||
paths: '../vars'
|
||||
|
||||
- template:
|
||||
src: dummy_command
|
||||
dest: '/usr/bin/dummy{{ item }}'
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0755
|
||||
with_sequence: start=1 end=4
|
22
test/integration/targets/alternatives/tasks/setup_test.yml
Normal file
22
test/integration/targets/alternatives/tasks/setup_test.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
- template:
|
||||
src: dummy_alternative
|
||||
dest: '{{ alternatives_dir }}/dummy'
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
when: with_alternatives or ansible_os_family != 'RedHat'
|
||||
|
||||
# update-alternatives included in Fedora 26 (1.10) & Red Hat 7.4 (1.8) segfaults
|
||||
# when <admindir>/dummy file contains only mode and link. Hence the file is
|
||||
# deleted instead of containing only mode and link. The file below works fine with
|
||||
# newer version of update-alternatives:
|
||||
# """
|
||||
# auto
|
||||
# /usr/bin/dummy
|
||||
#
|
||||
#
|
||||
# """
|
||||
- file:
|
||||
path: '{{ alternatives_dir }}/dummy'
|
||||
state: absent
|
||||
when: not with_alternatives and ansible_os_family == 'RedHat'
|
53
test/integration/targets/alternatives/tasks/test.yml
Normal file
53
test/integration/targets/alternatives/tasks/test.yml
Normal file
|
@ -0,0 +1,53 @@
|
|||
- debug:
|
||||
msg: ' with_alternatives: {{ with_alternatives }}, mode: {{ mode }}'
|
||||
|
||||
- block:
|
||||
- name: set alternative (using link parameter)
|
||||
alternatives:
|
||||
name: dummy
|
||||
path: '/usr/bin/dummy{{ item }}'
|
||||
link: '/usr/bin/dummy'
|
||||
register: alternative
|
||||
|
||||
- name: check expected command was executed
|
||||
assert:
|
||||
that:
|
||||
- 'alternative|success'
|
||||
- 'alternative|changed'
|
||||
when: with_link
|
||||
|
||||
- block:
|
||||
- name: set alternative (without link parameter)
|
||||
alternatives:
|
||||
name: dummy
|
||||
path: '/usr/bin/dummy{{ item }}'
|
||||
register: alternative
|
||||
|
||||
- name: check expected command was executed
|
||||
assert:
|
||||
that:
|
||||
- 'alternative|success'
|
||||
- 'alternative|changed'
|
||||
when: not with_link
|
||||
|
||||
- name: execute dummy command
|
||||
shell: dummy
|
||||
register: cmd
|
||||
|
||||
- name: check expected command was executed
|
||||
assert:
|
||||
that:
|
||||
- 'cmd.stdout == "dummy" ~ item'
|
||||
|
||||
- name: 'check mode (manual: alternatives file existed, it has been updated)'
|
||||
shell: 'head -n1 {{ alternatives_dir }}/dummy | grep "^manual$"'
|
||||
when: ansible_os_family != 'RedHat' or with_alternatives or item != 1
|
||||
|
||||
- name: 'check mode (auto: alternatives file didn''t exist, it has been created)'
|
||||
shell: 'head -n1 {{ alternatives_dir }}/dummy | grep "^auto$"'
|
||||
when: ansible_os_family == 'RedHat' and not with_alternatives and item == 1
|
||||
|
||||
- name: check that alternative has been updated
|
||||
command: "grep -Pzq '/bin/dummy{{ item }}\\n' '{{ alternatives_dir }}/dummy'"
|
||||
# priority doesn't seem updated
|
||||
#command: "grep -Pzq '/bin/dummy{{ item }}\\n50' '{{ alternatives_dir }}/dummy'"
|
15
test/integration/targets/alternatives/tasks/tests.yml
Normal file
15
test/integration/targets/alternatives/tasks/tests.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
- block:
|
||||
- include_tasks: remove_links.yml
|
||||
- include_tasks: setup_test.yml
|
||||
# at least two iterations:
|
||||
# - first will use 'link currently absent',
|
||||
# - second will receive 'link currently points to'
|
||||
- include_tasks: test.yml
|
||||
with_sequence: start=1 end=2
|
||||
vars:
|
||||
with_link: '{{ test_conf[0] }}'
|
||||
with_alternatives: '{{ test_conf[1] }}'
|
||||
mode: '{{ test_conf[2] }}'
|
||||
# update-alternatives included in Fedora 26 (1.10) & Red Hat 7.4 (1.8) doesn't provide
|
||||
# '--query' switch, 'link' is mandatory for these distributions.
|
||||
when: ansible_os_family != 'RedHat' or test_conf[0]
|
|
@ -0,0 +1,23 @@
|
|||
- name: update dummy alternative
|
||||
alternatives:
|
||||
name: dummy
|
||||
path: '/usr/bin/dummy{{ item }}'
|
||||
link: /usr/bin/dummy
|
||||
priority: '{{ 60 + item|int }}'
|
||||
register: alternative
|
||||
|
||||
- name: execute dummy command
|
||||
shell: dummy
|
||||
register: cmd
|
||||
|
||||
- name: check if link group is in manual mode
|
||||
shell: 'head -n1 {{ alternatives_dir }}/dummy | grep "^manual$"'
|
||||
|
||||
- name: check expected command was executed
|
||||
assert:
|
||||
that:
|
||||
- 'alternative|changed'
|
||||
- 'cmd.stdout == "dummy{{ item }}"'
|
||||
|
||||
- name: check that alternative has been updated
|
||||
command: "grep -Pzq '/bin/dummy{{ item }}\\n{{ 60 + item|int }}' '{{ alternatives_dir }}/dummy'"
|
|
@ -0,0 +1,12 @@
|
|||
{{ mode }}
|
||||
/usr/bin/dummy
|
||||
|
||||
{% if with_alternatives %}
|
||||
/usr/bin/dummy1
|
||||
40
|
||||
/usr/bin/dummy2
|
||||
30
|
||||
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
echo dummy{{ item }}
|
2
test/integration/targets/alternatives/vars/Debian.yml
Normal file
2
test/integration/targets/alternatives/vars/Debian.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
alternatives_dir: /var/lib/dpkg/alternatives/
|
2
test/integration/targets/alternatives/vars/Suse.yml
Normal file
2
test/integration/targets/alternatives/vars/Suse.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
alternatives_dir: /var/lib/rpm/alternatives/
|
2
test/integration/targets/alternatives/vars/default.yml
Normal file
2
test/integration/targets/alternatives/vars/default.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
alternatives_dir: /var/lib/alternatives/
|
|
@ -431,7 +431,6 @@ lib/ansible/modules/storage/netapp/sf_volume_access_group_manager.py
|
|||
lib/ansible/modules/storage/netapp/sf_volume_manager.py
|
||||
lib/ansible/modules/storage/zfs/zfs.py
|
||||
lib/ansible/modules/system/aix_inittab.py
|
||||
lib/ansible/modules/system/alternatives.py
|
||||
lib/ansible/modules/system/at.py
|
||||
lib/ansible/modules/system/capabilities.py
|
||||
lib/ansible/modules/system/cron.py
|
||||
|
|
Loading…
Reference in a new issue