mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
snap: aware of channel in installed snaps (#6435)
* [WIP] snap: aware of channel in installed snaps * parse snap list output and assert whether channel matches * undo test * fail rightfully when install with different channel does not work * transparetent refresh * rollback comment in integration test * rollback comment in integration test * add changelog frag * Update plugins/modules/snap.py Co-authored-by: Felix Fontein <felix@fontein.de> --------- Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
91b692634e
commit
b78d1999e1
6 changed files with 357 additions and 257 deletions
2
changelogs/fragments/6435-snap-channel-aware.yml
Normal file
2
changelogs/fragments/6435-snap-channel-aware.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- snap - module is now aware of channel when deciding whether to install or refresh the snap (https://github.com/ansible-collections/community.general/pull/6435, https://github.com/ansible-collections/community.general/issues/1606).
|
|
@ -20,6 +20,7 @@ _state_map = dict(
|
||||||
absent='remove',
|
absent='remove',
|
||||||
enabled='enable',
|
enabled='enable',
|
||||||
disabled='disable',
|
disabled='disable',
|
||||||
|
refresh='refresh',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,9 @@ options:
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- Desired state of the package.
|
- Desired state of the package.
|
||||||
required: false
|
- >
|
||||||
|
When I(state=present) the module will use C(snap install) if the snap is not installed,
|
||||||
|
and C(snap refresh) if it is installed but from a different channel.
|
||||||
default: present
|
default: present
|
||||||
choices: [ absent, present, enabled, disabled ]
|
choices: [ absent, present, enabled, disabled ]
|
||||||
type: str
|
type: str
|
||||||
|
@ -52,9 +54,9 @@ options:
|
||||||
description:
|
description:
|
||||||
- Define which release of a snap is installed and tracked for updates.
|
- Define which release of a snap is installed and tracked for updates.
|
||||||
This option can only be specified if there is a single snap in the task.
|
This option can only be specified if there is a single snap in the task.
|
||||||
|
- If not passed, the C(snap) command will default to V(stable).
|
||||||
type: str
|
type: str
|
||||||
required: false
|
required: false
|
||||||
default: stable
|
|
||||||
options:
|
options:
|
||||||
description:
|
description:
|
||||||
- Set options with pattern C(key=value) or C(snap:key=value). If a snap name is given, the option will be applied
|
- Set options with pattern C(key=value) or C(snap:key=value). If a snap name is given, the option will be applied
|
||||||
|
@ -159,15 +161,20 @@ from ansible_collections.community.general.plugins.module_utils.snap import snap
|
||||||
|
|
||||||
|
|
||||||
class Snap(StateModuleHelper):
|
class Snap(StateModuleHelper):
|
||||||
|
NOT_INSTALLED = 0
|
||||||
|
CHANNEL_MISMATCH = 1
|
||||||
|
INSTALLED = 2
|
||||||
|
|
||||||
__disable_re = re.compile(r'(?:\S+\s+){5}(?P<notes>\S+)')
|
__disable_re = re.compile(r'(?:\S+\s+){5}(?P<notes>\S+)')
|
||||||
__set_param_re = re.compile(r'(?P<snap_prefix>\S+:)?(?P<key>\S+)\s*=\s*(?P<value>.+)')
|
__set_param_re = re.compile(r'(?P<snap_prefix>\S+:)?(?P<key>\S+)\s*=\s*(?P<value>.+)')
|
||||||
|
__list_re = re.compile(r'^(?P<name>\S+)\s+\S+\s+\S+\s+(?P<channel>\S+)')
|
||||||
|
__install_re = re.compile(r'(?P<name>\S+)\s.+\s(installed|refreshed)')
|
||||||
module = dict(
|
module = dict(
|
||||||
argument_spec={
|
argument_spec={
|
||||||
'name': dict(type='list', elements='str', required=True),
|
'name': dict(type='list', elements='str', required=True),
|
||||||
'state': dict(type='str', default='present',
|
'state': dict(type='str', default='present', choices=['absent', 'present', 'enabled', 'disabled']),
|
||||||
choices=['absent', 'present', 'enabled', 'disabled']),
|
|
||||||
'classic': dict(type='bool', default=False),
|
'classic': dict(type='bool', default=False),
|
||||||
'channel': dict(type='str', default='stable'),
|
'channel': dict(type='str'),
|
||||||
'options': dict(type='list', elements='str'),
|
'options': dict(type='list', elements='str'),
|
||||||
},
|
},
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
|
@ -183,35 +190,47 @@ class Snap(StateModuleHelper):
|
||||||
|
|
||||||
def __init_module__(self):
|
def __init_module__(self):
|
||||||
self.runner = snap_runner(self.module)
|
self.runner = snap_runner(self.module)
|
||||||
|
self.vars.set("snap_status", self.snap_status(self.vars.name, self.vars.channel), output=False)
|
||||||
|
self.vars.set("snap_status_map", dict(zip(self.vars.name, self.vars.snap_status)), output=False)
|
||||||
|
|
||||||
def _run_multiple_commands(self, commands, actionable_names, bundle=True):
|
def _run_multiple_commands(self, commands, actionable_names, bundle=True, refresh=False):
|
||||||
results_cmd = []
|
results_cmd = []
|
||||||
results_rc = []
|
results_rc = []
|
||||||
results_out = []
|
results_out = []
|
||||||
results_err = []
|
results_err = []
|
||||||
|
results_run_info = []
|
||||||
|
|
||||||
|
state = "refresh" if refresh else self.vars.state
|
||||||
|
|
||||||
with self.runner(commands + ["name"]) as ctx:
|
with self.runner(commands + ["name"]) as ctx:
|
||||||
if bundle:
|
if bundle:
|
||||||
rc, out, err = ctx.run(name=actionable_names)
|
rc, out, err = ctx.run(state=state, name=actionable_names)
|
||||||
results_cmd.append(commands + actionable_names)
|
results_cmd.append(commands + actionable_names)
|
||||||
results_rc.append(rc)
|
results_rc.append(rc)
|
||||||
results_out.append(out)
|
results_out.append(out)
|
||||||
results_err.append(err)
|
results_err.append(err)
|
||||||
|
results_run_info.append(ctx.run_info)
|
||||||
else:
|
else:
|
||||||
for name in actionable_names:
|
for name in actionable_names:
|
||||||
rc, out, err = ctx.run(name=name)
|
rc, out, err = ctx.run(state=state, name=name)
|
||||||
results_cmd.append(commands + [name])
|
results_cmd.append(commands + [name])
|
||||||
results_rc.append(rc)
|
results_rc.append(rc)
|
||||||
results_out.append(out)
|
results_out.append(out)
|
||||||
results_err.append(err)
|
results_err.append(err)
|
||||||
|
results_run_info.append(ctx.run_info)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'; '.join([to_native(x) for x in results_cmd]),
|
'; '.join([to_native(x) for x in results_cmd]),
|
||||||
self._first_non_zero(results_rc),
|
self._first_non_zero(results_rc),
|
||||||
'\n'.join(results_out),
|
'\n'.join(results_out),
|
||||||
'\n'.join(results_err),
|
'\n'.join(results_err),
|
||||||
|
results_run_info,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def __quit_module__(self):
|
||||||
|
if self.vars.channel is None:
|
||||||
|
self.vars.channel = "stable"
|
||||||
|
|
||||||
def convert_json_subtree_to_map(self, json_subtree, prefix=None):
|
def convert_json_subtree_to_map(self, json_subtree, prefix=None):
|
||||||
option_map = {}
|
option_map = {}
|
||||||
|
|
||||||
|
@ -224,7 +243,6 @@ class Snap(StateModuleHelper):
|
||||||
|
|
||||||
if isinstance(value, (str, float, bool, numbers.Integral)):
|
if isinstance(value, (str, float, bool, numbers.Integral)):
|
||||||
option_map[full_key] = str(value)
|
option_map[full_key] = str(value)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
option_map.update(self.convert_json_subtree_to_map(json_subtree=value, prefix=full_key))
|
option_map.update(self.convert_json_subtree_to_map(json_subtree=value, prefix=full_key))
|
||||||
|
|
||||||
|
@ -248,16 +266,32 @@ class Snap(StateModuleHelper):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
option_map = self.convert_json_to_map(out)
|
option_map = self.convert_json_to_map(out)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.do_raise(
|
self.do_raise(
|
||||||
msg="Parsing option map returned by 'snap get {0}' triggers exception '{1}', output:\n'{2}'".format(snap_name, str(e), out))
|
msg="Parsing option map returned by 'snap get {0}' triggers exception '{1}', output:\n'{2}'".format(snap_name, str(e), out))
|
||||||
|
|
||||||
return option_map
|
return option_map
|
||||||
|
|
||||||
def is_snap_installed(self, snap_name):
|
def snap_status(self, snap_name, channel):
|
||||||
rc, dummy, dummy = self.runner("_list name").run(name=snap_name)
|
def _status_check(name, channel, installed):
|
||||||
return rc == 0
|
match = [c for n, c in installed if n == name]
|
||||||
|
if not match:
|
||||||
|
return Snap.NOT_INSTALLED
|
||||||
|
if channel and channel != match[0]:
|
||||||
|
return Snap.CHANNEL_MISMATCH
|
||||||
|
else:
|
||||||
|
return Snap.INSTALLED
|
||||||
|
|
||||||
|
with self.runner("_list") as ctx:
|
||||||
|
rc, out, err = ctx.run(check_rc=True)
|
||||||
|
out = out.split('\n')[1:]
|
||||||
|
out = [self.__list_re.match(x) for x in out]
|
||||||
|
out = [(m.group('name'), m.group('channel')) for m in out if m]
|
||||||
|
if self.verbosity >= 4:
|
||||||
|
self.vars.status_out = out
|
||||||
|
self.vars.status_run_info = ctx.run_info
|
||||||
|
|
||||||
|
return [_status_check(n, channel, out) for n in snap_name]
|
||||||
|
|
||||||
def is_snap_enabled(self, snap_name):
|
def is_snap_enabled(self, snap_name):
|
||||||
with self.runner("_list name") as ctx:
|
with self.runner("_list name") as ctx:
|
||||||
|
@ -271,7 +305,7 @@ class Snap(StateModuleHelper):
|
||||||
notes = match.group('notes')
|
notes = match.group('notes')
|
||||||
return "disabled" not in notes.split(',')
|
return "disabled" not in notes.split(',')
|
||||||
|
|
||||||
def process_actionable_snaps(self, actionable_snaps):
|
def _present(self, actionable_snaps, refresh=False):
|
||||||
self.changed = True
|
self.changed = True
|
||||||
self.vars.snaps_installed = actionable_snaps
|
self.vars.snaps_installed = actionable_snaps
|
||||||
|
|
||||||
|
@ -283,12 +317,17 @@ class Snap(StateModuleHelper):
|
||||||
has_multiple_snaps = len(actionable_snaps) > 1
|
has_multiple_snaps = len(actionable_snaps) > 1
|
||||||
|
|
||||||
if has_one_pkg_params and has_multiple_snaps:
|
if has_one_pkg_params and has_multiple_snaps:
|
||||||
self.vars.cmd, rc, out, err = self._run_multiple_commands(params, actionable_snaps, bundle=False)
|
self.vars.cmd, rc, out, err, run_info = self._run_multiple_commands(params, actionable_snaps, bundle=False, refresh=refresh)
|
||||||
else:
|
else:
|
||||||
self.vars.cmd, rc, out, err = self._run_multiple_commands(params, actionable_snaps)
|
self.vars.cmd, rc, out, err, run_info = self._run_multiple_commands(params, actionable_snaps, refresh=refresh)
|
||||||
|
if self.verbosity >= 4:
|
||||||
|
self.vars.run_info = run_info
|
||||||
|
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
return
|
match_install = [self.__install_re.match(line) for line in out.split('\n')]
|
||||||
|
match_install = [m.group('name') in actionable_snaps for m in match_install if m]
|
||||||
|
if len(match_install) == len(actionable_snaps):
|
||||||
|
return
|
||||||
|
|
||||||
classic_snap_pattern = re.compile(r'^error: This revision of snap "(?P<package_name>\w+)"'
|
classic_snap_pattern = re.compile(r'^error: This revision of snap "(?P<package_name>\w+)"'
|
||||||
r' was published using classic confinement')
|
r' was published using classic confinement')
|
||||||
|
@ -305,10 +344,13 @@ class Snap(StateModuleHelper):
|
||||||
|
|
||||||
self.vars.meta('classic').set(output=True)
|
self.vars.meta('classic').set(output=True)
|
||||||
self.vars.meta('channel').set(output=True)
|
self.vars.meta('channel').set(output=True)
|
||||||
actionable_snaps = [s for s in self.vars.name if not self.is_snap_installed(s)]
|
|
||||||
|
|
||||||
if actionable_snaps:
|
actionable_refresh = [snap for snap in self.vars.name if self.vars.snap_status_map[snap] == Snap.CHANNEL_MISMATCH]
|
||||||
self.process_actionable_snaps(actionable_snaps)
|
if actionable_refresh:
|
||||||
|
self._present(actionable_refresh, refresh=True)
|
||||||
|
actionable_install = [snap for snap in self.vars.name if self.vars.snap_status_map[snap] == Snap.NOT_INSTALLED]
|
||||||
|
if actionable_install:
|
||||||
|
self._present(actionable_install)
|
||||||
|
|
||||||
self.set_options()
|
self.set_options()
|
||||||
|
|
||||||
|
@ -316,7 +358,7 @@ class Snap(StateModuleHelper):
|
||||||
if self.vars.options is None:
|
if self.vars.options is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
actionable_snaps = [s for s in self.vars.name if self.is_snap_installed(s)]
|
actionable_snaps = [s for s in self.vars.name if self.vars.snap_status_map[s] != Snap.NOT_INSTALLED]
|
||||||
overall_options_changed = []
|
overall_options_changed = []
|
||||||
|
|
||||||
for snap_name in actionable_snaps:
|
for snap_name in actionable_snaps:
|
||||||
|
@ -366,7 +408,7 @@ class Snap(StateModuleHelper):
|
||||||
if overall_options_changed:
|
if overall_options_changed:
|
||||||
self.vars.options_changed = overall_options_changed
|
self.vars.options_changed = overall_options_changed
|
||||||
|
|
||||||
def _generic_state_action(self, actionable_func, actionable_var, params=None):
|
def _generic_state_action(self, actionable_func, actionable_var, params):
|
||||||
actionable_snaps = [s for s in self.vars.name if actionable_func(s)]
|
actionable_snaps = [s for s in self.vars.name if actionable_func(s)]
|
||||||
if not actionable_snaps:
|
if not actionable_snaps:
|
||||||
return
|
return
|
||||||
|
@ -374,9 +416,9 @@ class Snap(StateModuleHelper):
|
||||||
self.vars[actionable_var] = actionable_snaps
|
self.vars[actionable_var] = actionable_snaps
|
||||||
if self.check_mode:
|
if self.check_mode:
|
||||||
return
|
return
|
||||||
if params is None:
|
self.vars.cmd, rc, out, err, run_info = self._run_multiple_commands(params, actionable_snaps)
|
||||||
params = ['state']
|
if self.verbosity >= 4:
|
||||||
self.vars.cmd, rc, out, err = self._run_multiple_commands(params, actionable_snaps)
|
self.vars.run_info = run_info
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
return
|
return
|
||||||
msg = "Ooops! Snap operation failed while executing '{cmd}', please examine logs and " \
|
msg = "Ooops! Snap operation failed while executing '{cmd}', please examine logs and " \
|
||||||
|
@ -384,7 +426,7 @@ class Snap(StateModuleHelper):
|
||||||
self.do_raise(msg=msg)
|
self.do_raise(msg=msg)
|
||||||
|
|
||||||
def state_absent(self):
|
def state_absent(self):
|
||||||
self._generic_state_action(self.is_snap_installed, "snaps_removed", ['classic', 'channel', 'state'])
|
self._generic_state_action(lambda s: self.vars.snap_status_map[s] != Snap.NOT_INSTALLED, "snaps_removed", ['classic', 'channel', 'state'])
|
||||||
|
|
||||||
def state_enabled(self):
|
def state_enabled(self):
|
||||||
self._generic_state_action(lambda s: not self.is_snap_enabled(s), "snaps_enabled", ['classic', 'channel', 'state'])
|
self._generic_state_action(lambda s: not self.is_snap_enabled(s), "snaps_enabled", ['classic', 'channel', 'state'])
|
||||||
|
|
|
@ -8,236 +8,10 @@
|
||||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
- name: Has-snap block
|
- name: Has-snap include
|
||||||
when: has_snap
|
when: has_snap
|
||||||
block:
|
block:
|
||||||
- name: Make sure package is not installed (hello-world)
|
- name: Include test
|
||||||
community.general.snap:
|
ansible.builtin.include_tasks: test.yml
|
||||||
name: hello-world
|
- name: Include test_channel
|
||||||
state: absent
|
ansible.builtin.include_tasks: test_channel.yml
|
||||||
|
|
||||||
- name: Install package (hello-world) (check mode)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: present
|
|
||||||
register: install_check
|
|
||||||
check_mode: true
|
|
||||||
|
|
||||||
- name: Install package (hello-world)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: present
|
|
||||||
register: install
|
|
||||||
|
|
||||||
- name: Install package again (hello-world) (check mode)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: present
|
|
||||||
register: install_again_check
|
|
||||||
check_mode: true
|
|
||||||
|
|
||||||
- name: Install package again (hello-world)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: present
|
|
||||||
register: install_again
|
|
||||||
|
|
||||||
- name: Assert package has been installed just once (hello-world)
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- install is changed
|
|
||||||
- install_check is changed
|
|
||||||
- install_again is not changed
|
|
||||||
- install_again_check is not changed
|
|
||||||
|
|
||||||
- name: Check package has been installed correctly (hello-world)
|
|
||||||
command: hello-world
|
|
||||||
environment:
|
|
||||||
PATH: /snap/bin/
|
|
||||||
|
|
||||||
- name: Remove package (hello-world) (check mode)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: absent
|
|
||||||
register: remove_check
|
|
||||||
check_mode: true
|
|
||||||
|
|
||||||
- name: Remove package (hello-world)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: absent
|
|
||||||
register: remove
|
|
||||||
|
|
||||||
- name: Remove package again (hello-world) (check mode)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: absent
|
|
||||||
register: remove_again_check
|
|
||||||
check_mode: true
|
|
||||||
|
|
||||||
- name: Remove package again (hello-world)
|
|
||||||
community.general.snap:
|
|
||||||
name: hello-world
|
|
||||||
state: absent
|
|
||||||
register: remove_again
|
|
||||||
|
|
||||||
- name: Assert package has been removed just once (hello-world)
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- remove is changed
|
|
||||||
- remove_check is changed
|
|
||||||
- remove_again is not changed
|
|
||||||
- remove_again_check is not changed
|
|
||||||
|
|
||||||
- name: Make sure package from classic snap is not installed (nvim)
|
|
||||||
community.general.snap:
|
|
||||||
name: nvim
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Install package from classic snap (nvim)
|
|
||||||
community.general.snap:
|
|
||||||
name: nvim
|
|
||||||
state: present
|
|
||||||
classic: true
|
|
||||||
register: classic_install
|
|
||||||
|
|
||||||
# testing classic idempotency
|
|
||||||
- name: Install package from classic snap again (nvim)
|
|
||||||
community.general.snap:
|
|
||||||
name: nvim
|
|
||||||
state: present
|
|
||||||
classic: true
|
|
||||||
register: classic_install_again
|
|
||||||
|
|
||||||
- name: Assert package has been installed just once (nvim)
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- classic_install is changed
|
|
||||||
- classic_install_again is not changed
|
|
||||||
|
|
||||||
# this is just testing if a package which has been installed
|
|
||||||
# with true classic can be removed without setting classic to true
|
|
||||||
- name: Remove package from classic snap without setting classic to true (nvim)
|
|
||||||
community.general.snap:
|
|
||||||
name: nvim
|
|
||||||
state: absent
|
|
||||||
register: classic_remove_without_true_classic
|
|
||||||
|
|
||||||
- name: Remove package from classic snap with setting classic to true (nvim)
|
|
||||||
community.general.snap:
|
|
||||||
name: nvim
|
|
||||||
state: absent
|
|
||||||
classic: true
|
|
||||||
register: classic_remove_with_true_classic
|
|
||||||
|
|
||||||
- name: Assert package has been removed without setting classic to true (nvim)
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- classic_remove_without_true_classic is changed
|
|
||||||
- classic_remove_with_true_classic is not changed
|
|
||||||
|
|
||||||
|
|
||||||
- name: Make sure package is not installed (uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name: uhttpd
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Install package (uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name: uhttpd
|
|
||||||
state: present
|
|
||||||
register: install
|
|
||||||
|
|
||||||
- name: Install package (uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name: uhttpd
|
|
||||||
state: present
|
|
||||||
options:
|
|
||||||
- "listening-port=8080"
|
|
||||||
register: install_with_option
|
|
||||||
|
|
||||||
- name: Install package again with option (uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name: uhttpd
|
|
||||||
state: present
|
|
||||||
options:
|
|
||||||
- "listening-port=8080"
|
|
||||||
register: install_with_option_again
|
|
||||||
|
|
||||||
- name: Install package again with different options (uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name: uhttpd
|
|
||||||
state: present
|
|
||||||
options:
|
|
||||||
- "listening-port=8088"
|
|
||||||
- "document-root-dir=/tmp"
|
|
||||||
register: install_with_option_changed
|
|
||||||
|
|
||||||
- name: Remove package (uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name: uhttpd
|
|
||||||
state: absent
|
|
||||||
register: remove
|
|
||||||
|
|
||||||
- name: Assert package has been installed with options just once and only changed options trigger a change (uhttpd)
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- install is changed
|
|
||||||
- install_with_option is changed
|
|
||||||
- "install_with_option.options_changed[0] == 'uhttpd:listening-port=8080'"
|
|
||||||
- install_with_option_again is not changed
|
|
||||||
- install_with_option_changed is changed
|
|
||||||
- "'uhttpd:listening-port=8088' in install_with_option_changed.options_changed"
|
|
||||||
- "'uhttpd:document-root-dir=/tmp' in install_with_option_changed.options_changed"
|
|
||||||
- "'uhttpd:listening-port=8080' not in install_with_option_changed.options_changed"
|
|
||||||
- remove is changed
|
|
||||||
|
|
||||||
- name: Install two packages at the same time
|
|
||||||
community.general.snap:
|
|
||||||
name:
|
|
||||||
- hello-world
|
|
||||||
- uhttpd
|
|
||||||
state: present
|
|
||||||
register: install_two
|
|
||||||
|
|
||||||
- name: Install two packages at the same time (again)
|
|
||||||
community.general.snap:
|
|
||||||
name:
|
|
||||||
- hello-world
|
|
||||||
- uhttpd
|
|
||||||
state: present
|
|
||||||
register: install_two_again
|
|
||||||
|
|
||||||
- name: Remove packages (hello-world & uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name:
|
|
||||||
- hello-world
|
|
||||||
- uhttpd
|
|
||||||
state: absent
|
|
||||||
register: install_two_remove
|
|
||||||
|
|
||||||
- name: Remove packages again (hello-world & uhttpd)
|
|
||||||
community.general.snap:
|
|
||||||
name:
|
|
||||||
- hello-world
|
|
||||||
- uhttpd
|
|
||||||
state: absent
|
|
||||||
register: install_two_remove_again
|
|
||||||
|
|
||||||
- name: Assert installation of two packages
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- install_two is changed
|
|
||||||
- "'hello-world' in install_two.snaps_installed"
|
|
||||||
- "'uhttpd' in install_two.snaps_installed"
|
|
||||||
- install_two.snaps_removed is not defined
|
|
||||||
- install_two_again is not changed
|
|
||||||
- install_two_again.snaps_installed is not defined
|
|
||||||
- install_two_again.snaps_removed is not defined
|
|
||||||
- install_two_remove is changed
|
|
||||||
- install_two_again.snaps_installed is not defined
|
|
||||||
- "'hello-world' in install_two_remove.snaps_removed"
|
|
||||||
- "'uhttpd' in install_two_remove.snaps_removed"
|
|
||||||
- install_two_remove_again is not changed
|
|
||||||
- install_two_remove_again.snaps_installed is not defined
|
|
||||||
- install_two_remove_again.snaps_removed is not defined
|
|
||||||
|
|
235
tests/integration/targets/snap/tasks/test.yml
Normal file
235
tests/integration/targets/snap/tasks/test.yml
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
- name: Make sure package is not installed (hello-world)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Install package (hello-world) (check mode)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: present
|
||||||
|
register: install_check
|
||||||
|
check_mode: true
|
||||||
|
|
||||||
|
- name: Install package (hello-world)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: present
|
||||||
|
register: install
|
||||||
|
|
||||||
|
- name: Install package again (hello-world) (check mode)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: present
|
||||||
|
register: install_again_check
|
||||||
|
check_mode: true
|
||||||
|
|
||||||
|
- name: Install package again (hello-world)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: present
|
||||||
|
register: install_again
|
||||||
|
|
||||||
|
- name: Assert package has been installed just once (hello-world)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- install is changed
|
||||||
|
- install_check is changed
|
||||||
|
- install_again is not changed
|
||||||
|
- install_again_check is not changed
|
||||||
|
|
||||||
|
- name: Check package has been installed correctly (hello-world)
|
||||||
|
command: hello-world
|
||||||
|
environment:
|
||||||
|
PATH: /snap/bin/
|
||||||
|
|
||||||
|
- name: Remove package (hello-world) (check mode)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: absent
|
||||||
|
register: remove_check
|
||||||
|
check_mode: true
|
||||||
|
|
||||||
|
- name: Remove package (hello-world)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: absent
|
||||||
|
register: remove
|
||||||
|
|
||||||
|
- name: Remove package again (hello-world) (check mode)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: absent
|
||||||
|
register: remove_again_check
|
||||||
|
check_mode: true
|
||||||
|
|
||||||
|
- name: Remove package again (hello-world)
|
||||||
|
community.general.snap:
|
||||||
|
name: hello-world
|
||||||
|
state: absent
|
||||||
|
register: remove_again
|
||||||
|
|
||||||
|
- name: Assert package has been removed just once (hello-world)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- remove is changed
|
||||||
|
- remove_check is changed
|
||||||
|
- remove_again is not changed
|
||||||
|
- remove_again_check is not changed
|
||||||
|
|
||||||
|
- name: Make sure package from classic snap is not installed (nvim)
|
||||||
|
community.general.snap:
|
||||||
|
name: nvim
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Install package from classic snap (nvim)
|
||||||
|
community.general.snap:
|
||||||
|
name: nvim
|
||||||
|
state: present
|
||||||
|
classic: true
|
||||||
|
register: classic_install
|
||||||
|
|
||||||
|
# testing classic idempotency
|
||||||
|
- name: Install package from classic snap again (nvim)
|
||||||
|
community.general.snap:
|
||||||
|
name: nvim
|
||||||
|
state: present
|
||||||
|
classic: true
|
||||||
|
register: classic_install_again
|
||||||
|
|
||||||
|
- name: Assert package has been installed just once (nvim)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- classic_install is changed
|
||||||
|
- classic_install_again is not changed
|
||||||
|
|
||||||
|
# this is just testing if a package which has been installed
|
||||||
|
# with true classic can be removed without setting classic to true
|
||||||
|
- name: Remove package from classic snap without setting classic to true (nvim)
|
||||||
|
community.general.snap:
|
||||||
|
name: nvim
|
||||||
|
state: absent
|
||||||
|
register: classic_remove_without_true_classic
|
||||||
|
|
||||||
|
- name: Remove package from classic snap with setting classic to true (nvim)
|
||||||
|
community.general.snap:
|
||||||
|
name: nvim
|
||||||
|
state: absent
|
||||||
|
classic: true
|
||||||
|
register: classic_remove_with_true_classic
|
||||||
|
|
||||||
|
- name: Assert package has been removed without setting classic to true (nvim)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- classic_remove_without_true_classic is changed
|
||||||
|
- classic_remove_with_true_classic is not changed
|
||||||
|
|
||||||
|
|
||||||
|
- name: Make sure package is not installed (uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name: uhttpd
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Install package (uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name: uhttpd
|
||||||
|
state: present
|
||||||
|
register: install
|
||||||
|
|
||||||
|
- name: Install package (uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name: uhttpd
|
||||||
|
state: present
|
||||||
|
options:
|
||||||
|
- "listening-port=8080"
|
||||||
|
register: install_with_option
|
||||||
|
|
||||||
|
- name: Install package again with option (uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name: uhttpd
|
||||||
|
state: present
|
||||||
|
options:
|
||||||
|
- "listening-port=8080"
|
||||||
|
register: install_with_option_again
|
||||||
|
|
||||||
|
- name: Install package again with different options (uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name: uhttpd
|
||||||
|
state: present
|
||||||
|
options:
|
||||||
|
- "listening-port=8088"
|
||||||
|
- "document-root-dir=/tmp"
|
||||||
|
register: install_with_option_changed
|
||||||
|
|
||||||
|
- name: Remove package (uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name: uhttpd
|
||||||
|
state: absent
|
||||||
|
register: remove
|
||||||
|
|
||||||
|
- name: Assert package has been installed with options just once and only changed options trigger a change (uhttpd)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- install is changed
|
||||||
|
- install_with_option is changed
|
||||||
|
- "install_with_option.options_changed[0] == 'uhttpd:listening-port=8080'"
|
||||||
|
- install_with_option_again is not changed
|
||||||
|
- install_with_option_changed is changed
|
||||||
|
- "'uhttpd:listening-port=8088' in install_with_option_changed.options_changed"
|
||||||
|
- "'uhttpd:document-root-dir=/tmp' in install_with_option_changed.options_changed"
|
||||||
|
- "'uhttpd:listening-port=8080' not in install_with_option_changed.options_changed"
|
||||||
|
- remove is changed
|
||||||
|
|
||||||
|
- name: Install two packages at the same time
|
||||||
|
community.general.snap:
|
||||||
|
name:
|
||||||
|
- hello-world
|
||||||
|
- uhttpd
|
||||||
|
state: present
|
||||||
|
register: install_two
|
||||||
|
|
||||||
|
- name: Install two packages at the same time (again)
|
||||||
|
community.general.snap:
|
||||||
|
name:
|
||||||
|
- hello-world
|
||||||
|
- uhttpd
|
||||||
|
state: present
|
||||||
|
register: install_two_again
|
||||||
|
|
||||||
|
- name: Remove packages (hello-world & uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name:
|
||||||
|
- hello-world
|
||||||
|
- uhttpd
|
||||||
|
state: absent
|
||||||
|
register: install_two_remove
|
||||||
|
|
||||||
|
- name: Remove packages again (hello-world & uhttpd)
|
||||||
|
community.general.snap:
|
||||||
|
name:
|
||||||
|
- hello-world
|
||||||
|
- uhttpd
|
||||||
|
state: absent
|
||||||
|
register: install_two_remove_again
|
||||||
|
|
||||||
|
- name: Assert installation of two packages
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- install_two is changed
|
||||||
|
- "'hello-world' in install_two.snaps_installed"
|
||||||
|
- "'uhttpd' in install_two.snaps_installed"
|
||||||
|
- install_two.snaps_removed is not defined
|
||||||
|
- install_two_again is not changed
|
||||||
|
- install_two_again.snaps_installed is not defined
|
||||||
|
- install_two_again.snaps_removed is not defined
|
||||||
|
- install_two_remove is changed
|
||||||
|
- install_two_again.snaps_installed is not defined
|
||||||
|
- "'hello-world' in install_two_remove.snaps_removed"
|
||||||
|
- "'uhttpd' in install_two_remove.snaps_removed"
|
||||||
|
- install_two_remove_again is not changed
|
||||||
|
- install_two_remove_again.snaps_installed is not defined
|
||||||
|
- install_two_remove_again.snaps_removed is not defined
|
46
tests/integration/targets/snap/tasks/test_channel.yml
Normal file
46
tests/integration/targets/snap/tasks/test_channel.yml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
- name: Make sure package is not installed (microk8s)
|
||||||
|
community.general.snap:
|
||||||
|
name: microk8s
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
# Test for https://github.com/ansible-collections/community.general/issues/1606
|
||||||
|
- name: Install package (microk8s)
|
||||||
|
community.general.snap:
|
||||||
|
name: microk8s
|
||||||
|
classic: true
|
||||||
|
state: present
|
||||||
|
register: install_microk8s
|
||||||
|
|
||||||
|
- name: Install package with channel (microk8s)
|
||||||
|
community.general.snap:
|
||||||
|
name: microk8s
|
||||||
|
classic: true
|
||||||
|
channel: 1.20/stable
|
||||||
|
state: present
|
||||||
|
register: install_microk8s_chan
|
||||||
|
|
||||||
|
- name: Install package with channel (microk8s) again
|
||||||
|
community.general.snap:
|
||||||
|
name: microk8s
|
||||||
|
classic: true
|
||||||
|
channel: 1.20/stable
|
||||||
|
state: present
|
||||||
|
register: install_microk8s_chan_again
|
||||||
|
|
||||||
|
- name: Remove package (microk8s)
|
||||||
|
community.general.snap:
|
||||||
|
name: microk8s
|
||||||
|
state: absent
|
||||||
|
register: remove_microk8s
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- install_microk8s is changed
|
||||||
|
- install_microk8s_chan is changed
|
||||||
|
- install_microk8s_chan_again is not changed
|
||||||
|
- remove_microk8s is changed
|
Loading…
Reference in a new issue