1
0
Fork 0
mirror of https://github.com/containers/ansible-podman-collections.git synced 2026-02-03 23:01:48 +00:00
ansible-podman-collections/plugins/modules/podman_quadlet_info.py
Sagi Shnaidman 09bb5454a9 Add podman Quadlet modules
This commit introduces two new modules for managing Podman Quadlets:

- podman_quadlet: Install and remove Podman Quadlet files
  * Supports installing single files, directories, and additional config files
  * Implements idempotent state management (present/absent)
  * Validates parameters and provides meaningful error messages
  * Default force=true for removal operations
  * Removed deprecated 'ignore' parameter in favor of built-in idempotency

- podman_quadlet_info: Gather information about installed Quadlets
  * Lists all installed quadlets or prints specific quadlet content
  * Supports filtering by quadlet kinds (container, pod, network, etc.)
  * Provides detailed quadlet metadata including status and paths

Key features:
- Shared utilities in module_utils/podman/quadlet.py for code reuse
- Comprehensive integration tests for both modules
- Full idempotency support for all operations
- Proper handling of edge cases (missing files, malformed quadlets, etc.)
- Check mode support for safe dry-run operations
- Extensive documentation and examples

The modules use relative imports for module_utils to support local
development and testing with the containers.podman collection.

Signed-off-by: Sagi Shnaidman <sshnaidm@redhat.com>
2026-02-02 18:10:59 +02:00

255 lines
7 KiB
Python

#!/usr/bin/python
# Copyright (c) 2025 Red Hat
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# flake8: noqa: E501
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r"""
module: podman_quadlet_info
author:
- "Sagi Shnaidman (@sshnaidm)"
short_description: Gather information about Podman Quadlets
description:
- List installed Podman Quadlets or print one quadlet content using C(podman quadlet list/print).
- Gather information about Podman Quadlets available on the system.
options:
name:
description:
- Name of the quadlet to print content for.
- When specified, runs C(podman quadlet print) instead of list.
type: str
required: false
kinds:
description:
- List of quadlet kinds to filter by (based on file suffix).
- For example, C(container) matches quadlets ending with C(.container).
type: list
elements: str
choices:
- container
- pod
- network
- volume
- kube
- image
required: false
quadlet_dir:
description:
- Filter results to quadlets whose path is under this directory.
- By default no filtering is applied.
type: path
required: false
executable:
description:
- Path to the podman executable.
type: str
default: podman
cmd_args:
description:
- Extra global arguments to pass to the C(podman) command (e.g., C(--log-level=debug)).
- These are placed after the executable and before the subcommand.
type: list
elements: str
required: false
debug:
description:
- Return additional debug information.
type: bool
default: false
"""
EXAMPLES = r"""
- name: List all quadlets
containers.podman.podman_quadlet_info:
- name: Get information about a specific quadlet
containers.podman.podman_quadlet_info:
name: myapp.container
- name: List only container quadlets
containers.podman.podman_quadlet_info:
kinds:
- container
- name: List quadlets in a custom directory
containers.podman.podman_quadlet_info:
quadlet_dir: /etc/containers/systemd
"""
RETURN = r"""
changed:
description: Always false
returned: always
type: bool
quadlets:
description: List of installed quadlets when listing
returned: when name is not provided
type: list
content:
description: Content of the quadlet when name is provided
returned: when name is provided
type: str
stdout:
description: podman stdout
returned: when debug=true
type: str
stderr:
description: podman stderr
returned: when debug=true
type: str
"""
import json
import os
from ansible.module_utils.basic import AnsibleModule # noqa: F402
try:
from ansible.module_utils.common.text.converters import to_native # noqa: F402
except ImportError:
from ansible.module_utils.common.text import to_native # noqa: F402
# Mapping from kind name to file suffix
KIND_SUFFIXES = {
"container": ".container",
"pod": ".pod",
"network": ".network",
"volume": ".volume",
"kube": ".kube",
"image": ".image",
}
def _get_quadlet_kind(name):
"""Extract kind from quadlet name based on suffix."""
if not name:
return None
for kind, suffix in KIND_SUFFIXES.items():
if name.endswith(suffix):
return kind
return None
def _build_base_cmd(module, executable):
"""Build base command with executable and global args."""
cmd = [executable]
if module.params.get("cmd_args"):
cmd.extend(module.params["cmd_args"])
return cmd
def _list_quadlets(module, executable):
"""List installed quadlets with optional filtering."""
cmd = _build_base_cmd(module, executable)
cmd.extend(["quadlet", "list", "--format", "json"])
module.log("PODMAN-QUADLET-INFO-DEBUG: %s" % " ".join([to_native(i) for i in cmd]))
rc, out, err = module.run_command(cmd)
if rc != 0:
module.fail_json(msg="Failed to list quadlets: %s" % err, stdout=out, stderr=err)
# Strict JSON parsing - fail on errors instead of returning empty
try:
data = json.loads(out) if out.strip() else []
except json.JSONDecodeError as e:
module.fail_json(
msg="Failed to parse quadlet list output: %s" % str(e),
stdout=out,
stderr=err,
)
# Filter by kinds (based on file suffix in Name)
kinds = module.params.get("kinds")
if kinds:
kinds_set = set(kinds)
filtered = []
for q in data:
name = q.get("Name", "")
kind = _get_quadlet_kind(name)
if kind and kind in kinds_set:
filtered.append(q)
data = filtered
# Filter by quadlet_dir (based on Path)
quadlet_dir = module.params.get("quadlet_dir")
if quadlet_dir:
# Normalize the directory path
quadlet_dir = os.path.normpath(quadlet_dir)
filtered = []
for q in data:
path = q.get("Path", "")
if path:
# Check if the quadlet's path is under the specified directory
normalized_path = os.path.normpath(path)
if normalized_path.startswith(quadlet_dir + os.sep) or os.path.dirname(normalized_path) == quadlet_dir:
filtered.append(q)
data = filtered
result = {
"changed": False,
"quadlets": data,
}
if module.params["debug"]:
result.update({"stdout": out, "stderr": err})
return result
def _print_quadlet(module, executable):
"""Print content of a specific quadlet."""
name = module.params["name"]
cmd = _build_base_cmd(module, executable)
cmd.extend(["quadlet", "print", name])
module.log("PODMAN-QUADLET-INFO-DEBUG: %s" % " ".join([to_native(i) for i in cmd]))
rc, out, err = module.run_command(cmd)
if rc != 0:
module.fail_json(msg="Failed to print quadlet %s: %s" % (name, err), stdout=out, stderr=err)
result = {
"changed": False,
"content": out,
}
if module.params["debug"]:
result.update({"stdout": out, "stderr": err})
return result
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type="str", required=False),
quadlet_dir=dict(type="path", required=False),
kinds=dict(
type="list",
elements="str",
required=False,
choices=["container", "pod", "network", "volume", "kube", "image"],
),
executable=dict(type="str", default="podman"),
cmd_args=dict(type="list", elements="str", required=False),
debug=dict(type="bool", default=False),
),
supports_check_mode=True,
)
executable = module.get_bin_path(module.params["executable"], required=True)
if module.params.get("name"):
result = _print_quadlet(module, executable)
else:
result = _list_quadlets(module, executable)
module.exit_json(**result)
if __name__ == "__main__":
main()