1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-06-04 15:27:00 +00:00

snap: support system as a configuration target (#12025)

* feat(snap): support snap system configuration via name=system

Treat `system` as a virtual snap that is always considered installed,
bypassing snap info lookup and install/refresh logic, while still
allowing snap set/get operations via the options parameter.

Fixes #11266

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(snap): note version_added for system support; add changelog fragment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alexei Znamensky 2026-05-14 22:02:28 +12:00 committed by GitHub
parent fba7da4394
commit 862d7d7aaf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 120 additions and 9 deletions

View file

@ -0,0 +1,5 @@
minor_changes:
- snap - add support for ``system`` as a special configuration target, allowing
``snap set system`` to be used via the ``options`` parameter
(https://github.com/ansible-collections/community.general/issues/11266,
https://github.com/ansible-collections/community.general/pull/12025).

View file

@ -29,6 +29,10 @@ options:
- Name of the snaps to be installed.
- Any named snap accepted by the C(snap) command is valid.
- O(dangerous=true) may be necessary when installing C(.snap) files. See O(dangerous) for more details.
- The special name V(system) refers to the snapd system-wide configuration namespace.
When used with O(options), it runs C(snap set system <key=value>).
It is always considered present and only V(state=present) and O(options) are meaningful for it.
Support for V(system) was added in community.general 13.0.0.
required: true
type: list
elements: str
@ -155,6 +159,14 @@ EXAMPLES = r"""
name: helm
classic: true
revision: 481
# Set snap system-wide configuration
- name: Configure snapd proxy
community.general.snap:
name: system
options:
- proxy.http=http://proxy.example.com:3128/
- proxy.https=http://proxy.example.com:3128/
"""
RETURN = r"""
@ -201,6 +213,8 @@ import re
from ansible.module_utils.common.text.converters import to_native
_VIRTUAL_SNAPS = frozenset({"system"})
from ansible_collections.community.general.plugins.module_utils._module_helper import StateModuleHelper
from ansible_collections.community.general.plugins.module_utils._snap import get_version, snap_runner
@ -345,6 +359,11 @@ class Snap(StateModuleHelper):
)
def names_from_snaps(self, snaps):
real_snaps = [s for s in snaps if s not in _VIRTUAL_SNAPS]
if not real_snaps:
return list(snaps)
def process_one(rc, out, err):
res = [line for line in out.split("\n") if line.startswith("name:")]
name = res[0].split()[1]
@ -361,7 +380,7 @@ class Snap(StateModuleHelper):
return res
def process(rc, out, err):
if len(snaps) == 1:
if len(real_snaps) == 1:
check_error = err
process_ = process_one
else:
@ -373,17 +392,20 @@ class Snap(StateModuleHelper):
self.do_raise(f"Snaps not found: {snaps_not_found}.")
return process_(rc, out, err)
names = []
if snaps:
with self.runner("info name", output_process=process) as ctx:
try:
names = ctx.run(name=snaps)
finally:
self.vars.snapinfo_run_info.append(ctx.run_info)
return names
real_names = []
with self.runner("info name", output_process=process) as ctx:
try:
real_names = ctx.run(name=real_snaps)
finally:
self.vars.snapinfo_run_info.append(ctx.run_info)
real_name_iter = iter(real_names)
return [s if s in _VIRTUAL_SNAPS else next(real_name_iter) for s in snaps]
def snap_status(self, snap_name, channel, revision=None):
def _status_check(name, channel, revision, installed):
if name in _VIRTUAL_SNAPS:
return Snap.INSTALLED
match = [(r, c) for n, r, c in installed if n == name]
if not match:
return Snap.NOT_INSTALLED

View file

@ -438,6 +438,90 @@ TEST_SPEC = dict(
],
),
),
dict(
id="set_system_option",
input={"name": ["system"], "options": ["proxy.http=http://proxy.example.com:3128/"]},
output=dict(changed=True, options_changed=["system:proxy.http=http://proxy.example.com:3128/"]),
flags={},
mocks=dict(
run_command=[
dict(
command=["/testbin/snap", "version"],
environ=default_env,
rc=0,
out=default_version_out,
err="",
),
# No "snap info system" — virtual snap bypasses names_from_snaps
dict(
command=["/testbin/snap", "list"],
environ=default_env,
rc=0,
out="",
err="",
),
dict(
command=["/testbin/snap", "get", "-d", "system"],
environ=default_env,
rc=0,
out="{}",
err="",
),
dict(
command=["/testbin/snap", "set", "system", "proxy.http=http://proxy.example.com:3128/"],
environ=default_env,
rc=0,
out="",
err="",
),
dict(
command=["/testbin/snap", "list"],
environ=default_env,
rc=0,
out="",
err="",
),
],
),
),
dict(
id="set_system_option_idempotent",
input={"name": ["system"], "options": ["proxy.http=http://proxy.example.com:3128/"]},
output=dict(changed=False),
flags={},
mocks=dict(
run_command=[
dict(
command=["/testbin/snap", "version"],
environ=default_env,
rc=0,
out=default_version_out,
err="",
),
dict(
command=["/testbin/snap", "list"],
environ=default_env,
rc=0,
out="",
err="",
),
dict(
command=["/testbin/snap", "get", "-d", "system"],
environ=default_env,
rc=0,
out='{"proxy": {"http": "http://proxy.example.com:3128/"}}',
err="",
),
dict(
command=["/testbin/snap", "list"],
environ=default_env,
rc=0,
out="",
err="",
),
],
),
),
dict(
id="issue_6803",
input={"name": ["microk8s", "kubectl"], "classic": True},