mirror of
https://github.com/containers/ansible-podman-collections.git
synced 2026-02-03 23:01:48 +00:00
Add podman system connection modules (#971)
Signed-off-by: Sagi Shnaidman <sshnaidm@redhat.com>
This commit is contained in:
parent
ee52d9de78
commit
f333fe7fca
8 changed files with 1410 additions and 0 deletions
32
.github/workflows/podman_system_connection.yml
vendored
Normal file
32
.github/workflows/podman_system_connection.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Podman system connection
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/podman_system_connection.yml'
|
||||
- '.github/workflows/reusable-module-test.yml'
|
||||
- 'ci/*.yml'
|
||||
- 'ci/run_containers_tests.sh'
|
||||
- 'ci/playbooks/containers/podman_system_connection.yml'
|
||||
- 'plugins/modules/podman_system_connection.py'
|
||||
- 'tests/integration/targets/podman_system_connection/**'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/podman_system_connection.yml'
|
||||
- '.github/workflows/reusable-module-test.yml'
|
||||
- 'ci/*.yml'
|
||||
- 'ci/run_containers_tests.sh'
|
||||
- 'ci/playbooks/containers/podman_system_connection.yml'
|
||||
- 'plugins/modules/podman_system_connection.py'
|
||||
- 'tests/integration/targets/podman_system_connection/**'
|
||||
schedule:
|
||||
- cron: 4 0 * * * # Run daily at 0:03 UTC
|
||||
|
||||
jobs:
|
||||
test_podman_system_connection:
|
||||
uses: ./.github/workflows/reusable-module-test.yml
|
||||
with:
|
||||
module_name: 'podman_system_connection'
|
||||
display_name: 'Podman system connection'
|
||||
32
.github/workflows/podman_system_connection_info.yml
vendored
Normal file
32
.github/workflows/podman_system_connection_info.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Podman system connection info
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/podman_system_connection_info.yml'
|
||||
- '.github/workflows/reusable-module-test.yml'
|
||||
- 'ci/*.yml'
|
||||
- 'ci/run_containers_tests.sh'
|
||||
- 'ci/playbooks/containers/podman_system_connection_info.yml'
|
||||
- 'plugins/modules/podman_system_connection_info.py'
|
||||
- 'tests/integration/targets/podman_system_connection_info/**'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/podman_system_connection_info.yml'
|
||||
- '.github/workflows/reusable-module-test.yml'
|
||||
- 'ci/*.yml'
|
||||
- 'ci/run_containers_tests.sh'
|
||||
- 'ci/playbooks/containers/podman_system_connection_info.yml'
|
||||
- 'plugins/modules/podman_system_connection_info.py'
|
||||
- 'tests/integration/targets/podman_system_connection_info/**'
|
||||
schedule:
|
||||
- cron: 4 0 * * * # Run daily at 0:03 UTC
|
||||
|
||||
jobs:
|
||||
test_podman_system_connection_info:
|
||||
uses: ./.github/workflows/reusable-module-test.yml
|
||||
with:
|
||||
module_name: 'podman_system_connection_info'
|
||||
display_name: 'Podman system connection info'
|
||||
8
ci/playbooks/containers/podman_system_connection.yml
Normal file
8
ci/playbooks/containers/podman_system_connection.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
- hosts: all
|
||||
gather_facts: true
|
||||
tasks:
|
||||
- include_role:
|
||||
name: podman_system_connection
|
||||
vars:
|
||||
ansible_python_interpreter: "{{ _ansible_python_interpreter }}"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
- hosts: all
|
||||
gather_facts: true
|
||||
tasks:
|
||||
- include_role:
|
||||
name: podman_system_connection_info
|
||||
vars:
|
||||
ansible_python_interpreter: "{{ _ansible_python_interpreter }}"
|
||||
689
plugins/modules/podman_system_connection.py
Normal file
689
plugins/modules/podman_system_connection.py
Normal file
|
|
@ -0,0 +1,689 @@
|
|||
#!/usr/bin/python
|
||||
# Copyright (c) 2025 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
module: podman_system_connection
|
||||
author:
|
||||
- "Sagi Shnaidman (@sshnaidm)"
|
||||
version_added: '1.18.0'
|
||||
short_description: Manage podman system connections
|
||||
notes: []
|
||||
description:
|
||||
- Manage podman system connections with podman system connection command.
|
||||
- Add, remove, rename and set default connections to Podman services.
|
||||
requirements:
|
||||
- podman
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the connection
|
||||
type: str
|
||||
required: True
|
||||
state:
|
||||
description:
|
||||
- State of the connection
|
||||
type: str
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
executable:
|
||||
description:
|
||||
- Path to C(podman) executable if it is not in the C($PATH) on the
|
||||
machine running C(podman)
|
||||
default: 'podman'
|
||||
type: str
|
||||
destination:
|
||||
description:
|
||||
- Destination for the connection. Required when I(state=present).
|
||||
- Can be in the format C([user@]hostname[:port]), C(ssh://[user@]hostname[:port]),
|
||||
C(unix://path), C(tcp://hostname:port)
|
||||
type: str
|
||||
default:
|
||||
description:
|
||||
- Make this connection the default for this user
|
||||
type: bool
|
||||
identity:
|
||||
description:
|
||||
- Path to SSH identity file
|
||||
type: str
|
||||
port:
|
||||
description:
|
||||
- SSH port (default is 22)
|
||||
type: int
|
||||
socket_path:
|
||||
description:
|
||||
- Path to the Podman service unix domain socket on the ssh destination host
|
||||
type: str
|
||||
new_name:
|
||||
description:
|
||||
- New name for the connection when renaming (used with I(state=present))
|
||||
type: str
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
- name: Add a basic SSH connection
|
||||
containers.podman.podman_system_connection:
|
||||
name: production
|
||||
destination: root@server.example.com
|
||||
state: present
|
||||
|
||||
- name: Add SSH connection with custom port and identity
|
||||
containers.podman.podman_system_connection:
|
||||
name: staging
|
||||
destination: user@staging.example.com
|
||||
port: 2222
|
||||
identity: ~/.ssh/staging_rsa
|
||||
state: present
|
||||
|
||||
- name: Add connection and set as default
|
||||
containers.podman.podman_system_connection:
|
||||
name: development
|
||||
destination: dev@dev.example.com
|
||||
default: true
|
||||
state: present
|
||||
|
||||
- name: Add unix socket connection
|
||||
containers.podman.podman_system_connection:
|
||||
name: local
|
||||
destination: unix:///run/podman/podman.sock
|
||||
state: present
|
||||
|
||||
- name: Add TCP connection
|
||||
containers.podman.podman_system_connection:
|
||||
name: remote_tcp
|
||||
destination: tcp://remote.example.com:8080
|
||||
state: present
|
||||
|
||||
- name: Rename a connection
|
||||
containers.podman.podman_system_connection:
|
||||
name: old_name
|
||||
new_name: new_name
|
||||
state: present
|
||||
|
||||
- name: Remove a connection
|
||||
containers.podman.podman_system_connection:
|
||||
name: old_connection
|
||||
state: absent
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
connection:
|
||||
description: Connection information in podman JSON format
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"Name": "production",
|
||||
"URI": "ssh://root@server.example.com:22/run/user/0/podman/podman.sock",
|
||||
"Default": true,
|
||||
"ReadWrite": true
|
||||
}
|
||||
actions:
|
||||
description: Actions performed on the connection
|
||||
returned: always
|
||||
type: list
|
||||
sample:
|
||||
- "Connection 'production' added"
|
||||
- "Connection 'production' set as default"
|
||||
"""
|
||||
|
||||
import json
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def get_connection_info(module, executable, name):
|
||||
"""Get specific connection information from podman system connection list.
|
||||
|
||||
Retrieves connection information by executing 'podman system connection list --format json'
|
||||
and searches for a connection with the specified name.
|
||||
|
||||
Args:
|
||||
module (AnsibleModule): The Ansible module instance for running commands and error handling
|
||||
executable (str): Path to the podman executable
|
||||
name (str): Name of the specific connection to search for
|
||||
|
||||
Returns:
|
||||
dict or None: Connection dictionary if found, None if not found
|
||||
|
||||
Connection dictionary may contain:
|
||||
- Name (str): Connection name
|
||||
- URI (str): Connection URI (ssh://, unix://, tcp://)
|
||||
- Default (bool): Whether this is the default connection
|
||||
- ReadWrite (bool, optional): Read/write access (Podman version dependent)
|
||||
- Identity (str, optional): SSH identity file path (Podman version dependent)
|
||||
- IsMachine (bool, optional): Whether this is a machine connection (Podman version dependent)
|
||||
|
||||
Raises:
|
||||
AnsibleFailJson: If the podman command fails or JSON parsing fails
|
||||
|
||||
Note:
|
||||
This function differs from the _info module's get_connection_info by returning
|
||||
a single connection dict or None, rather than a list of connections.
|
||||
"""
|
||||
command = [executable, "system", "connection", "list", "--format", "json"]
|
||||
rc, out, err = module.run_command(command)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to list connections: %s" % err)
|
||||
|
||||
try:
|
||||
connections = json.loads(out) if out.strip() else []
|
||||
for conn in connections:
|
||||
if conn.get("Name") == name:
|
||||
return conn
|
||||
return None
|
||||
except json.JSONDecodeError as e:
|
||||
module.fail_json(msg="Failed to parse connection list JSON: %s" % str(e))
|
||||
|
||||
|
||||
def connections_are_identical(conn1, conn2):
|
||||
"""Check if two connections are identical by comparing their attributes (excluding Name).
|
||||
|
||||
Compares all relevant connection attributes to determine if two connections
|
||||
represent the same configuration. The Name field is excluded from comparison
|
||||
to allow for rename operations.
|
||||
|
||||
Args:
|
||||
conn1 (dict or None): First connection dictionary to compare
|
||||
conn2 (dict or None): Second connection dictionary to compare
|
||||
|
||||
Returns:
|
||||
bool: True if connections have identical attributes, False otherwise
|
||||
|
||||
Compared attributes:
|
||||
- URI (str): Connection URI (must match exactly)
|
||||
- Default (bool): Default status (must match)
|
||||
- ReadWrite (bool, optional): Read/write access (Podman version dependent)
|
||||
- Identity (str, optional): SSH identity file path (Podman version dependent)
|
||||
- IsMachine (bool, optional): Machine connection flag (Podman version dependent)
|
||||
|
||||
Note:
|
||||
Returns False if either connection is None or empty. Optional fields
|
||||
(ReadWrite, Identity, IsMachine) are handled gracefully - missing fields
|
||||
are treated as None for comparison purposes.
|
||||
"""
|
||||
if not conn1 or not conn2:
|
||||
return False
|
||||
# Compare all relevant attributes except Name
|
||||
return {**conn1, "Name": None} == {**conn2, "Name": None}
|
||||
|
||||
|
||||
def destination_matches_uri(destination, current_uri):
|
||||
"""Check if a destination specification matches an existing connection URI.
|
||||
|
||||
Compares a user-provided destination with the current connection URI,
|
||||
handling both full protocol URIs and simplified hostname formats.
|
||||
|
||||
Args:
|
||||
destination (str): User-provided destination specification
|
||||
current_uri (str): Existing connection URI from podman
|
||||
|
||||
Returns:
|
||||
bool: True if destination matches the current URI, False otherwise
|
||||
|
||||
Matching logic:
|
||||
- Full URIs (ssh://, unix://, tcp://): Requires exact match
|
||||
- Simple format (user@host): Checks if contained in expanded URI
|
||||
|
||||
Examples:
|
||||
destination_matches_uri("ssh://user@host:22", "ssh://user@host:22/path") -> True
|
||||
destination_matches_uri("user@host", "ssh://user@host:22/path") -> True
|
||||
destination_matches_uri("unix:///tmp/sock", "unix:///tmp/sock") -> True
|
||||
destination_matches_uri("user@host", "ssh://other@host:22/path") -> False
|
||||
|
||||
Note:
|
||||
Podman typically expands simple formats like "user@host" into full URIs
|
||||
like "ssh://user@host:22/run/user/uid/podman/podman.sock", so this
|
||||
function allows matching against the simplified form.
|
||||
"""
|
||||
if destination.startswith(("ssh://", "unix://", "tcp://")):
|
||||
# Exact protocol match required for full URIs
|
||||
return current_uri == destination
|
||||
# Simple hostname format - check if it's contained in the expanded URI
|
||||
# podman expands "user@host" to "ssh://user@host:22/run/user/uid/podman/podman.sock"
|
||||
return destination in current_uri
|
||||
|
||||
|
||||
def connection_needs_update(current_conn, params):
|
||||
"""Check if a connection needs to be updated based on current vs desired state.
|
||||
|
||||
Compares the current connection configuration with the desired module parameters
|
||||
to determine if changes are needed. Generates diff information for changed fields.
|
||||
|
||||
Args:
|
||||
current_conn (dict or None): Current connection dictionary from podman, or None if not exists
|
||||
params (dict): Module parameters containing desired connection configuration
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing:
|
||||
- needs_update (bool): True if connection needs changes, False if current state matches desired
|
||||
- diffs (dict): Dictionary with 'before' and 'after' keys containing changed fields
|
||||
|
||||
Checked parameters:
|
||||
- destination: Compared against current URI using destination_matches_uri()
|
||||
- default: Compared against current Default field
|
||||
- identity: Compared against current Identity field (if provided)
|
||||
|
||||
Examples:
|
||||
# Connection doesn't exist
|
||||
connection_needs_update(None, {...}) -> (True, {"before": {}, "after": {}})
|
||||
|
||||
# URI change needed
|
||||
connection_needs_update({"URI": "old"}, {"destination": "new"}) ->
|
||||
(True, {"before": {"URI": "old"}, "after": {"URI": "new"}})
|
||||
|
||||
# No changes needed
|
||||
connection_needs_update({"URI": "same", "Default": False}, {"destination": "same", "default": False}) ->
|
||||
(False, {"before": {}, "after": {}})
|
||||
|
||||
Note:
|
||||
The identity parameter is only checked if explicitly provided (not None).
|
||||
Missing identity in params is not treated as a change requirement.
|
||||
"""
|
||||
if not current_conn:
|
||||
return True, {"before": {}, "after": {}}
|
||||
|
||||
destination = params["destination"]
|
||||
default = params["default"]
|
||||
diffs = {"before": {}, "after": {}}
|
||||
|
||||
# Check if URI matches the expected destination format
|
||||
current_uri = current_conn.get("URI", "")
|
||||
if not destination_matches_uri(destination, current_uri):
|
||||
diffs["before"]["URI"] = current_uri
|
||||
diffs["after"]["URI"] = destination
|
||||
|
||||
# Check if default status needs to change
|
||||
# Compare "Default" only when it's set explicitly in parameters,
|
||||
# first system connection is always default
|
||||
if default is not None and default != current_conn.get("Default"):
|
||||
diffs["before"]["Default"] = current_conn.get("Default")
|
||||
diffs["after"]["Default"] = default
|
||||
|
||||
# Check Identity if provided
|
||||
identity = params.get("identity")
|
||||
if identity is not None and identity != current_conn.get("Identity", ""):
|
||||
diffs["before"]["Identity"] = current_conn.get("Identity", "")
|
||||
diffs["after"]["Identity"] = identity
|
||||
|
||||
if diffs["before"] or diffs["after"]:
|
||||
return True, diffs
|
||||
|
||||
return False, diffs
|
||||
|
||||
|
||||
def add_connection(module, executable, name, destination, default, identity, port, socket_path):
|
||||
"""Add a new podman system connection with specified parameters.
|
||||
|
||||
Executes 'podman system connection add' with the provided configuration parameters.
|
||||
Supports all connection options including SSH settings and default flag.
|
||||
|
||||
Args:
|
||||
module (AnsibleModule): The Ansible module instance for running commands and error handling
|
||||
executable (str): Path to the podman executable
|
||||
name (str): Name for the new connection
|
||||
destination (str): Connection destination (URI or simple hostname format)
|
||||
default (bool): Whether to set this connection as the default
|
||||
identity (str or None): Path to SSH identity file (optional)
|
||||
port (int or None): SSH port number (optional, defaults to 22 for SSH)
|
||||
socket_path (str or None): Path to podman socket on remote host (optional)
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing:
|
||||
- changed (bool): Always True since a connection is being added
|
||||
- actions (list): List of action messages describing what was done
|
||||
|
||||
Command construction:
|
||||
Base: 'podman system connection add'
|
||||
Options added conditionally:
|
||||
--default (if default=True)
|
||||
--identity <path> (if identity provided)
|
||||
--port <port> (if port provided)
|
||||
--socket-path <path> (if socket_path provided)
|
||||
Arguments: <name> <destination>
|
||||
|
||||
Actions generated:
|
||||
- "Connection '<name>' added" (always)
|
||||
- "Connection '<name>' set as default" (if default=True)
|
||||
|
||||
Raises:
|
||||
AnsibleFailJson: If the podman command fails
|
||||
|
||||
Note:
|
||||
In check mode, the command is not executed but actions are still generated
|
||||
to show what would happen. This allows for proper diff and change reporting.
|
||||
"""
|
||||
actions = []
|
||||
command = [executable, "system", "connection", "add"]
|
||||
|
||||
if default:
|
||||
command.extend(["--default"])
|
||||
|
||||
if identity:
|
||||
command.extend(["--identity", identity])
|
||||
|
||||
if port:
|
||||
command.extend(["--port", str(port)])
|
||||
|
||||
if socket_path:
|
||||
command.extend(["--socket-path", socket_path])
|
||||
|
||||
command.extend([name, destination])
|
||||
|
||||
if not module.check_mode:
|
||||
rc, out, err = module.run_command(command)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to add connection '%s': %s" % (name, err))
|
||||
|
||||
actions.append("Connection '%s' added" % name)
|
||||
|
||||
if default:
|
||||
actions.append("Connection '%s' set as default" % name)
|
||||
|
||||
return True, actions
|
||||
|
||||
|
||||
def remove_connection(module, executable, name):
|
||||
"""Remove an existing podman system connection.
|
||||
|
||||
Executes 'podman system connection remove' to delete the specified connection.
|
||||
|
||||
Args:
|
||||
module (AnsibleModule): The Ansible module instance for running commands and error handling
|
||||
executable (str): Path to the podman executable
|
||||
name (str): Name of the connection to remove
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing:
|
||||
- changed (bool): Always True since a connection is being removed
|
||||
- actions (list): List containing single action message about the removal
|
||||
|
||||
Command executed:
|
||||
'podman system connection remove <name>'
|
||||
|
||||
Actions generated:
|
||||
- "Connection '<name>' removed"
|
||||
|
||||
Raises:
|
||||
AnsibleFailJson: If the podman command fails (e.g., connection doesn't exist)
|
||||
|
||||
Note:
|
||||
In check mode, the command is not executed but the action message is still
|
||||
generated to show what would happen. The caller should verify the connection
|
||||
exists before calling this function if idempotent behavior is required.
|
||||
"""
|
||||
command = [executable, "system", "connection", "remove", name]
|
||||
|
||||
if not module.check_mode:
|
||||
rc, out, err = module.run_command(command)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to remove connection '%s': %s" % (name, err))
|
||||
|
||||
return True, ["Connection '%s' removed" % name]
|
||||
|
||||
|
||||
def rename_connection(module, executable, old_name, new_name):
|
||||
"""Rename an existing podman system connection.
|
||||
|
||||
Executes 'podman system connection rename' to change the name of an existing connection.
|
||||
All connection attributes (URI, default status, etc.) remain unchanged.
|
||||
|
||||
Args:
|
||||
module (AnsibleModule): The Ansible module instance for running commands and error handling
|
||||
executable (str): Path to the podman executable
|
||||
old_name (str): Current name of the connection to rename
|
||||
new_name (str): New name for the connection
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing:
|
||||
- changed (bool): Always True since a connection is being renamed
|
||||
- actions (list): List containing single action message about the rename
|
||||
|
||||
Command executed:
|
||||
'podman system connection rename <old_name> <new_name>'
|
||||
|
||||
Actions generated:
|
||||
- "Connection '<old_name>' renamed to '<new_name>'"
|
||||
|
||||
Raises:
|
||||
AnsibleFailJson: If the podman command fails (e.g., old connection doesn't exist,
|
||||
new name already exists, etc.)
|
||||
|
||||
Note:
|
||||
In check mode, the command is not executed but the action message is still
|
||||
generated to show what would happen. The caller should verify the old connection
|
||||
exists and the new name is available before calling this function.
|
||||
"""
|
||||
command = [executable, "system", "connection", "rename", old_name, new_name]
|
||||
|
||||
if not module.check_mode:
|
||||
rc, out, err = module.run_command(command)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to rename connection '%s' to '%s': %s" % (old_name, new_name, err))
|
||||
|
||||
return True, ["Connection '%s' renamed to '%s'" % (old_name, new_name)]
|
||||
|
||||
|
||||
def set_default_connection(module, executable, name):
|
||||
"""Set an existing connection as the default connection.
|
||||
|
||||
Executes 'podman system connection default' to mark the specified connection
|
||||
as the default for the current user. Any previously default connection will
|
||||
no longer be the default.
|
||||
|
||||
Args:
|
||||
module (AnsibleModule): The Ansible module instance for running commands and error handling
|
||||
executable (str): Path to the podman executable
|
||||
name (str): Name of the connection to set as default
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing:
|
||||
- changed (bool): Always True since default status is being changed
|
||||
- actions (list): List containing single action message about setting default
|
||||
|
||||
Command executed:
|
||||
'podman system connection default <name>'
|
||||
|
||||
Actions generated:
|
||||
- "Connection '<name>' set as default"
|
||||
|
||||
Raises:
|
||||
AnsibleFailJson: If the podman command fails (e.g., connection doesn't exist)
|
||||
|
||||
Note:
|
||||
In check mode, the command is not executed but the action message is still
|
||||
generated to show what would happen. This function does not verify that
|
||||
the connection exists - the caller should handle that validation.
|
||||
|
||||
Setting a connection as default automatically unsets any previous default
|
||||
connection, but this function only reports the action for the specified connection.
|
||||
"""
|
||||
command = [executable, "system", "connection", "default", name]
|
||||
|
||||
if not module.check_mode:
|
||||
rc, out, err = module.run_command(command)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to set connection '%s' as default: %s" % (name, err))
|
||||
|
||||
return True, ["Connection '%s' set as default" % name]
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for the podman_system_connection Ansible module.
|
||||
|
||||
This function sets up the Ansible module, validates parameters, and orchestrates
|
||||
the management of podman system connections based on the desired state.
|
||||
|
||||
The module supports the following operations:
|
||||
- Creating new connections (state=present with destination)
|
||||
- Updating existing connections (state=present with different parameters)
|
||||
- Renaming connections (state=present with new_name)
|
||||
- Removing connections (state=absent)
|
||||
- Setting connections as default (default=true)
|
||||
|
||||
Module Parameters:
|
||||
name (str, required): Name of the connection
|
||||
state (str): 'present' or 'absent' (default: 'present')
|
||||
executable (str): Path to podman executable (default: 'podman')
|
||||
destination (str): Connection destination (required for state=present, except rename)
|
||||
default (bool): Set as default connection (default: False)
|
||||
identity (str): SSH identity file path (optional)
|
||||
port (int): SSH port number (optional)
|
||||
socket_path (str): Remote podman socket path (optional)
|
||||
new_name (str): New name for rename operation (optional)
|
||||
|
||||
Parameter constraints:
|
||||
- destination and new_name are mutually exclusive
|
||||
- destination is required when state=present (except for rename operations)
|
||||
|
||||
Operation logic:
|
||||
state=present with new_name: Rename operation
|
||||
- Fails if source connection doesn't exist
|
||||
- Idempotent if target name exists with identical configuration
|
||||
- Performs rename if target name doesn't exist
|
||||
|
||||
state=present with destination: Add/update operation
|
||||
- Checks if connection needs update using connection_needs_update()
|
||||
- Removes existing connection if changes needed
|
||||
- Adds new connection with desired parameters
|
||||
- Idempotent if existing connection matches desired state
|
||||
|
||||
state=absent: Remove operation
|
||||
- Removes connection if it exists
|
||||
- Idempotent if connection doesn't exist
|
||||
|
||||
Cross-version compatibility:
|
||||
Handles optional fields (ReadWrite, Identity, IsMachine) that may not be
|
||||
present in all Podman versions. Missing fields are treated gracefully.
|
||||
|
||||
Note:
|
||||
The module follows the 'always require full description of desired state'
|
||||
design pattern, requiring destination for all present operations except rename.
|
||||
"""
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(type="str", required=True),
|
||||
state=dict(type="str", choices=["present", "absent"], default="present"),
|
||||
executable=dict(type="str", default="podman"),
|
||||
destination=dict(type="str"),
|
||||
default=dict(type="bool"),
|
||||
identity=dict(type="str"),
|
||||
port=dict(type="int"),
|
||||
socket_path=dict(type="str"),
|
||||
new_name=dict(type="str"),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=[
|
||||
("destination", "new_name"),
|
||||
],
|
||||
)
|
||||
|
||||
name = module.params["name"]
|
||||
state = module.params["state"]
|
||||
executable = module.get_bin_path(module.params["executable"], required=True)
|
||||
destination = module.params["destination"]
|
||||
default = module.params["default"]
|
||||
identity = module.params["identity"]
|
||||
port = module.params["port"]
|
||||
socket_path = module.params["socket_path"]
|
||||
new_name = module.params["new_name"]
|
||||
|
||||
# Validate required parameters - always require destination when state=present (except for rename)
|
||||
if state == "present" and not new_name and not destination:
|
||||
module.fail_json(msg="destination is required when state=present")
|
||||
|
||||
# Get current connection state
|
||||
current_conn = get_connection_info(module, executable, name)
|
||||
|
||||
changed = False
|
||||
actions = []
|
||||
connection_info = {}
|
||||
diff = {"before": {}, "after": {}}
|
||||
|
||||
if state == "present":
|
||||
if new_name:
|
||||
# Handle rename operation
|
||||
if not current_conn:
|
||||
module.fail_json(msg="Cannot rename non-existent connection '%s'" % name)
|
||||
|
||||
# Check if new name already exists
|
||||
new_conn = get_connection_info(module, executable, new_name)
|
||||
if new_conn:
|
||||
# Check if the existing connection with new_name is identical to current_conn
|
||||
if connections_are_identical(current_conn, new_conn):
|
||||
# Connections are identical - idempotent, no changes needed
|
||||
connection_info = new_conn
|
||||
else:
|
||||
# Different connection exists with the same name - fail
|
||||
module.fail_json(msg="Connection with name '%s' already exists and is different" % new_name)
|
||||
else:
|
||||
# Perform rename
|
||||
changed, rename_actions = rename_connection(module, executable, name, new_name)
|
||||
actions.extend(rename_actions)
|
||||
|
||||
# Get connection info after rename
|
||||
if not module.check_mode:
|
||||
final_conn = get_connection_info(module, executable, new_name)
|
||||
connection_info = final_conn
|
||||
else:
|
||||
old_conn_info = get_connection_info(module, executable, name)
|
||||
old_conn_info["Name"] = new_name
|
||||
connection_info = old_conn_info
|
||||
|
||||
else:
|
||||
# Handle add/update operation (destination is always provided)
|
||||
needs_update, diff = connection_needs_update(current_conn, module.params)
|
||||
if needs_update:
|
||||
# Remove existing connection if it exists with different parameters
|
||||
if current_conn:
|
||||
changed, remove_actions = remove_connection(module, executable, name)
|
||||
actions.extend(remove_actions)
|
||||
|
||||
# Add the connection with desired parameters
|
||||
changed, add_actions = add_connection(
|
||||
module, executable, name, destination, default, identity, port, socket_path
|
||||
)
|
||||
actions.extend(add_actions)
|
||||
|
||||
# Get final connection state
|
||||
if not module.check_mode:
|
||||
final_conn = get_connection_info(module, executable, name)
|
||||
connection_info = final_conn
|
||||
else:
|
||||
# In check mode, provide expected values
|
||||
connection_info = {
|
||||
"Name": name,
|
||||
"URI": destination,
|
||||
"Default": default,
|
||||
}
|
||||
|
||||
else:
|
||||
# Connection exists and matches desired state - idempotent
|
||||
connection_info = current_conn
|
||||
|
||||
elif state == "absent":
|
||||
if current_conn:
|
||||
changed, remove_actions = remove_connection(module, executable, name)
|
||||
actions.extend(remove_actions)
|
||||
connection_info = {}
|
||||
module.log("PODMAN-SYSTEM-CONNECTION: changed=%s, actions=%s, diff=%s" % (changed, actions, diff))
|
||||
diff_info = {}
|
||||
if diff["before"] or diff["after"]:
|
||||
diff_info = {
|
||||
"before": "\n".join(["%s - %s" % (k, v) for k, v in sorted(diff["before"].items())]) + "\n",
|
||||
"after": "\n".join(["%s - %s" % (k, v) for k, v in sorted(diff["after"].items())]) + "\n",
|
||||
}
|
||||
module.exit_json(
|
||||
changed=changed,
|
||||
connection=connection_info,
|
||||
actions=actions,
|
||||
diff=diff_info,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
174
plugins/modules/podman_system_connection_info.py
Normal file
174
plugins/modules/podman_system_connection_info.py
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/python
|
||||
# Copyright (c) 2025 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
module: podman_system_connection_info
|
||||
author:
|
||||
- "Sagi Shnaidman (@sshnaidm)"
|
||||
version_added: '1.18.0'
|
||||
short_description: Gather info about podman system connections
|
||||
notes: []
|
||||
description:
|
||||
- Gather info about podman system connections with podman system connection list command.
|
||||
requirements:
|
||||
- "Podman installed on host"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the connection to gather info about
|
||||
- If not provided, info about all connections will be returned
|
||||
type: str
|
||||
executable:
|
||||
description:
|
||||
- Path to C(podman) executable if it is not in the C($PATH) on the
|
||||
machine running C(podman)
|
||||
default: 'podman'
|
||||
type: str
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
- name: Gather info about all connections
|
||||
containers.podman.podman_system_connection_info:
|
||||
|
||||
- name: Gather info about specific connection
|
||||
containers.podman.podman_system_connection_info:
|
||||
name: production
|
||||
|
||||
- name: Get connection info and register result
|
||||
containers.podman.podman_system_connection_info:
|
||||
name: staging
|
||||
register: staging_connection
|
||||
|
||||
- name: Display connection URI
|
||||
debug:
|
||||
msg: "Staging connection URI: {{ staging_connection.connections[0].URI }}"
|
||||
when: staging_connection.connections | length > 0
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
connections:
|
||||
description: Facts from all or specified connections
|
||||
returned: always
|
||||
type: list
|
||||
sample: [
|
||||
{
|
||||
"Name": "production",
|
||||
"URI": "ssh://root@server.example.com:22/run/user/0/podman/podman.sock",
|
||||
"Identity": "/home/user/.ssh/id_rsa",
|
||||
"Default": true,
|
||||
"ReadWrite": true
|
||||
},
|
||||
{
|
||||
"Name": "local",
|
||||
"URI": "unix:///run/user/1000/podman/podman.sock",
|
||||
"Identity": "",
|
||||
"Default": false,
|
||||
"ReadWrite": false
|
||||
},
|
||||
{
|
||||
"Name": "development",
|
||||
"URI": "ssh://dev@dev.example.com:22/run/user/1000/podman/podman.sock",
|
||||
"Identity": "/home/user/.ssh/dev_rsa",
|
||||
"Default": false,
|
||||
"ReadWrite": true
|
||||
}
|
||||
]
|
||||
"""
|
||||
|
||||
import json
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def get_connection_info(module, executable, name):
|
||||
"""Get connection information from podman system connection list.
|
||||
|
||||
Retrieves connection information by executing 'podman system connection list --format json'
|
||||
and optionally filters the results for a specific connection by name.
|
||||
|
||||
Args:
|
||||
module (AnsibleModule): The Ansible module instance for running commands and error handling
|
||||
executable (str): Path to the podman executable
|
||||
name (str or None): Name of specific connection to filter for, or None to get all connections
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing:
|
||||
- connections (list): List of connection dictionaries matching the filter criteria
|
||||
- out (str): Raw stdout from the podman command
|
||||
- err (str): Raw stderr from the podman command
|
||||
|
||||
Raises:
|
||||
AnsibleFailJson: If the podman command fails or JSON parsing fails
|
||||
|
||||
Note:
|
||||
When a specific connection name is provided but not found, an empty list is returned
|
||||
rather than failing. This allows for idempotent behavior when checking if connections exist.
|
||||
"""
|
||||
command = [executable, "system", "connection", "list", "--format", "json"]
|
||||
rc, out, err = module.run_command(command)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Unable to get list of connections: %s" % err)
|
||||
|
||||
try:
|
||||
connections = json.loads(out) if out.strip() else []
|
||||
except json.JSONDecodeError as e:
|
||||
module.fail_json(msg="Failed to parse connection list JSON: %s" % str(e))
|
||||
|
||||
if name:
|
||||
# Filter for specific connection
|
||||
filtered_connections = [conn for conn in connections if conn.get("Name") == name]
|
||||
# if not filtered_connections:
|
||||
# module.fail_json(msg="Connection '%s' not found" % name)
|
||||
return filtered_connections, out, err
|
||||
|
||||
return connections, out, err
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for the podman_system_connection_info Ansible module.
|
||||
|
||||
This function sets up the Ansible module, validates parameters, retrieves connection
|
||||
information from podman, and returns the results in the expected format.
|
||||
|
||||
The module supports check mode and never reports changes since it's an info-gathering
|
||||
module that doesn't modify system state.
|
||||
|
||||
Module Parameters:
|
||||
executable (str): Path to podman executable (default: "podman")
|
||||
name (str, optional): Name of specific connection to get info about.
|
||||
If not provided, returns info about all connections.
|
||||
|
||||
Each connection dictionary may contain the following fields:
|
||||
- Name (str): Connection name
|
||||
- URI (str): Connection URI (ssh://, unix://, tcp://)
|
||||
- Default (bool): Whether this is the default connection
|
||||
- ReadWrite (bool, optional): Read/write access (Podman version dependent)
|
||||
- Identity (str, optional): SSH identity file path (Podman version dependent)
|
||||
- IsMachine (bool, optional): Whether this is a machine connection (Podman version dependent)
|
||||
|
||||
Note:
|
||||
Some fields like ReadWrite, Identity, and IsMachine are optional and may not be present
|
||||
in all Podman versions. The module handles this gracefully.
|
||||
"""
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(executable=dict(type="str", default="podman"), name=dict(type="str")),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
name = module.params["name"]
|
||||
executable = module.get_bin_path(module.params["executable"], required=True)
|
||||
|
||||
inspect_results, out, err = get_connection_info(module, executable, name)
|
||||
|
||||
results = {"changed": False, "connections": inspect_results, "stderr": err}
|
||||
|
||||
module.exit_json(**results)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
- name: Test podman_system_connection
|
||||
block:
|
||||
|
||||
- name: Print podman version
|
||||
command: podman version
|
||||
|
||||
- name: Generate random values for connection names
|
||||
set_fact:
|
||||
test_connection_1: "{{ 'ansible-test-conn1-%0x' % ((2**32) | random) }}"
|
||||
test_connection_2: "{{ 'ansible-test-conn2-%0x' % ((2**32) | random) }}"
|
||||
test_connection_3: "{{ 'ansible-test-conn3-%0x' % ((2**32) | random) }}"
|
||||
|
||||
- name: Clean up any existing test connections
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
loop:
|
||||
- "{{ test_connection_1 }}"
|
||||
- "{{ test_connection_2 }}"
|
||||
- "{{ test_connection_3 }}"
|
||||
|
||||
- name: Test adding a basic unix socket connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_1 }}"
|
||||
destination: "unix:///tmp/test-socket-{{ test_connection_1 }}.sock"
|
||||
state: present
|
||||
register: add_result
|
||||
|
||||
- name: Check add connection results
|
||||
assert:
|
||||
that:
|
||||
- add_result is changed
|
||||
- add_result.connection.Name == test_connection_1
|
||||
- "'unix://' in add_result.connection.URI"
|
||||
- add_result.actions | length > 0
|
||||
- "'added' in add_result.actions[0]"
|
||||
|
||||
- name: Test idempotency - add same connection again
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_1 }}"
|
||||
destination: "unix:///tmp/test-socket-{{ test_connection_1 }}.sock"
|
||||
state: present
|
||||
register: add_idem_result
|
||||
|
||||
- name: Check idempotency
|
||||
assert:
|
||||
that:
|
||||
- add_idem_result is not changed
|
||||
- add_idem_result.connection.Name == test_connection_1
|
||||
|
||||
- name: Test adding connection with unix socket
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_2 }}"
|
||||
destination: "unix:///tmp/test-socket-{{ test_connection_2 }}.sock"
|
||||
state: present
|
||||
register: add_custom_result
|
||||
|
||||
- name: Check custom connection results
|
||||
assert:
|
||||
that:
|
||||
- add_custom_result is changed
|
||||
- add_custom_result.connection.Name == test_connection_2
|
||||
- "'unix://' in add_custom_result.connection.URI"
|
||||
- add_custom_result.actions | length > 0
|
||||
|
||||
- name: Test adding connection with default flag
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_3 }}"
|
||||
destination: "unix:///tmp/test-socket-{{ test_connection_3 }}.sock"
|
||||
default: true
|
||||
state: present
|
||||
register: add_default_result
|
||||
|
||||
- name: Check default connection results
|
||||
assert:
|
||||
that:
|
||||
- add_default_result is changed
|
||||
- add_default_result.connection.Name == test_connection_3
|
||||
- add_default_result.connection.Default == true
|
||||
|
||||
- name: Test unix socket connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-unix"
|
||||
destination: "unix:///run/podman/podman.sock"
|
||||
state: present
|
||||
register: unix_result
|
||||
|
||||
- name: Check unix socket connection
|
||||
assert:
|
||||
that:
|
||||
- unix_result is changed
|
||||
- unix_result.connection.Name == "test-unix"
|
||||
- "'unix://' in unix_result.connection.URI"
|
||||
|
||||
- name: Test unix socket connection again for idempotency
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-unix"
|
||||
destination: "unix:///run/podman/podman.sock"
|
||||
state: present
|
||||
register: unix_result2
|
||||
|
||||
- name: Check unix socket connection
|
||||
assert:
|
||||
that:
|
||||
- unix_result2 is not changed
|
||||
- unix_result2.connection.Name == "test-unix"
|
||||
- "'unix://' in unix_result2.connection.URI"
|
||||
|
||||
- name: Test unix socket connection - different
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-unix"
|
||||
destination: "unix:///run/podman/podman2.sock"
|
||||
state: present
|
||||
register: unix_result3
|
||||
|
||||
- name: Check unix socket connection
|
||||
assert:
|
||||
that:
|
||||
- unix_result3 is changed
|
||||
- unix_result3.connection.Name == "test-unix"
|
||||
- "'unix://' in unix_result3.connection.URI"
|
||||
|
||||
- name: Test TCP connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-tcp"
|
||||
destination: "tcp://localhost:8080"
|
||||
state: present
|
||||
register: tcp_result
|
||||
|
||||
- name: Check TCP connection
|
||||
assert:
|
||||
that:
|
||||
- tcp_result is changed
|
||||
- tcp_result.connection.Name == "test-tcp"
|
||||
- "'tcp://' in tcp_result.connection.URI"
|
||||
|
||||
- name: Test connection rename
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_1 }}"
|
||||
new_name: "{{ test_connection_1 }}-renamed"
|
||||
state: present
|
||||
register: rename_result
|
||||
|
||||
- name: Check rename results
|
||||
assert:
|
||||
that:
|
||||
- rename_result is changed
|
||||
- rename_result.connection.Name == test_connection_1 + "-renamed"
|
||||
|
||||
- name: Test rename non-existent connection (should fail)
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "non-existent-connection"
|
||||
new_name: "new-name"
|
||||
state: present
|
||||
register: rename_fail_result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check rename failure
|
||||
assert:
|
||||
that:
|
||||
- rename_fail_result is failed
|
||||
- "'Cannot rename non-existent connection' in rename_fail_result.msg"
|
||||
|
||||
- name: Test setting existing connection as default
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_2 }}"
|
||||
destination: "unix:///tmp/test-socket-{{ test_connection_2 }}.sock"
|
||||
default: true
|
||||
state: present
|
||||
register: set_default_result
|
||||
|
||||
- name: Check set default results
|
||||
assert:
|
||||
that:
|
||||
- set_default_result is changed
|
||||
- set_default_result.actions | select('search', 'set as default') | list | length > 0
|
||||
|
||||
- name: Test removing connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_2 }}"
|
||||
state: absent
|
||||
register: remove_result
|
||||
|
||||
- name: Check remove results
|
||||
assert:
|
||||
that:
|
||||
- remove_result is changed
|
||||
- "'removed' in remove_result.actions[0]"
|
||||
|
||||
- name: Test idempotency - remove non-existent connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_2 }}"
|
||||
state: absent
|
||||
register: remove_idem_result
|
||||
|
||||
- name: Check remove idempotency
|
||||
assert:
|
||||
that:
|
||||
- remove_idem_result is not changed
|
||||
|
||||
- name: Test check mode for adding connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "check-mode-test"
|
||||
destination: "unix:///tmp/test-socket-check.sock"
|
||||
state: present
|
||||
check_mode: true
|
||||
register: check_add_result
|
||||
|
||||
- name: Verify check mode add
|
||||
assert:
|
||||
that:
|
||||
- check_add_result is changed
|
||||
- check_add_result.connection.Name == "check-mode-test"
|
||||
|
||||
- name: Verify connection was not actually added in check mode
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "check-mode-test"
|
||||
register: check_verify
|
||||
|
||||
- name: Check that connection doesn't exist
|
||||
assert:
|
||||
that:
|
||||
- check_verify.connections | length == 0
|
||||
|
||||
- name: Test check mode for removing connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_3 }}"
|
||||
state: absent
|
||||
check_mode: true
|
||||
register: check_remove_result
|
||||
|
||||
- name: Verify check mode remove
|
||||
assert:
|
||||
that:
|
||||
- check_remove_result is changed
|
||||
|
||||
- name: Verify connection still exists after check mode
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_3 }}"
|
||||
register: check_still_exists
|
||||
|
||||
- name: Check that connection still exists
|
||||
assert:
|
||||
that:
|
||||
- check_still_exists.connections | length > 0
|
||||
|
||||
always:
|
||||
- name: Clean up test connections
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
loop:
|
||||
- "{{ test_connection_1 }}"
|
||||
- "{{ test_connection_1 }}-renamed"
|
||||
- "{{ test_connection_2 }}"
|
||||
- "{{ test_connection_3 }}"
|
||||
- "test-unix"
|
||||
- "test-tcp"
|
||||
- "check-mode-test"
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
- name: Test podman_system_connection_info
|
||||
block:
|
||||
|
||||
- name: Print podman version
|
||||
command: podman version
|
||||
|
||||
- name: Generate random values for connection names
|
||||
set_fact:
|
||||
test_connection_1: "{{ 'ansible-test-info1-%0x' % ((2**32) | random) }}"
|
||||
test_connection_2: "{{ 'ansible-test-info2-%0x' % ((2**32) | random) }}"
|
||||
|
||||
- name: Clean up any existing test connections
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
loop:
|
||||
- "{{ test_connection_1 }}"
|
||||
- "{{ test_connection_2 }}"
|
||||
|
||||
- name: Get info about all connections (empty list)
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
register: empty_list_result
|
||||
|
||||
- name: Check empty connections list
|
||||
assert:
|
||||
that:
|
||||
- empty_list_result is not changed
|
||||
- empty_list_result.connections is defined
|
||||
- empty_list_result.connections is iterable
|
||||
|
||||
- name: Create test connection 1 (unix socket)
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_1 }}"
|
||||
destination: "unix:///tmp/test-socket-1.sock"
|
||||
state: present
|
||||
|
||||
- name: Create test connection 2 as default (tcp)
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_2 }}"
|
||||
destination: "tcp://127.0.0.1:8080"
|
||||
default: true
|
||||
state: present
|
||||
|
||||
- name: Get info about all connections
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
register: all_connections_result
|
||||
|
||||
- name: Check all connections results
|
||||
assert:
|
||||
that:
|
||||
- all_connections_result is not changed
|
||||
- all_connections_result.connections | length >= 2
|
||||
- all_connections_result.connections | selectattr('Name', 'equalto', test_connection_1) | list | length == 1
|
||||
- all_connections_result.connections | selectattr('Name', 'equalto', test_connection_2) | list | length == 1
|
||||
|
||||
- name: Get info about specific connection
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_1 }}"
|
||||
register: specific_connection_result
|
||||
|
||||
- name: Check specific connection results
|
||||
assert:
|
||||
that:
|
||||
- specific_connection_result is not changed
|
||||
- specific_connection_result.connections | length == 1
|
||||
- specific_connection_result.connections[0].Name == test_connection_1
|
||||
- "'unix://' in specific_connection_result.connections[0].URI"
|
||||
|
||||
- name: Get info about default connection
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ test_connection_2 }}"
|
||||
register: default_connection_result
|
||||
|
||||
- name: Check default connection results
|
||||
assert:
|
||||
that:
|
||||
- default_connection_result is not changed
|
||||
- default_connection_result.connections | length == 1
|
||||
- default_connection_result.connections[0].Name == test_connection_2
|
||||
- default_connection_result.connections[0].Default == true
|
||||
- "'tcp://' in default_connection_result.connections[0].URI"
|
||||
|
||||
- name: Try to get info about non-existent connection
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "non-existent-connection"
|
||||
register: non_existent_result
|
||||
|
||||
- name: Check non-existent connection failure
|
||||
assert:
|
||||
that:
|
||||
- non_existent_result.connections | length == 0
|
||||
|
||||
- name: Test check mode
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
check_mode: true
|
||||
register: check_mode_result
|
||||
|
||||
- name: Check check mode results
|
||||
assert:
|
||||
that:
|
||||
- check_mode_result is not changed
|
||||
- check_mode_result.connections is defined
|
||||
|
||||
- name: Verify connection attributes for readwrite connections
|
||||
set_fact:
|
||||
test_conn_1_info: "{{ all_connections_result.connections | selectattr('Name', 'equalto', test_connection_1) | first }}"
|
||||
test_conn_2_info: "{{ all_connections_result.connections | selectattr('Name', 'equalto', test_connection_2) | first }}"
|
||||
|
||||
- name: Check connection 1 attributes
|
||||
assert:
|
||||
that:
|
||||
- test_conn_1_info.Name == test_connection_1
|
||||
- test_conn_1_info.URI is defined
|
||||
- test_conn_1_info.Default is defined
|
||||
- test_conn_1_info.Default == false
|
||||
# ReadWrite, Identity, and IsMachine are optional fields
|
||||
|
||||
- name: Check connection 2 attributes (default)
|
||||
assert:
|
||||
that:
|
||||
- test_conn_2_info.Name == test_connection_2
|
||||
- test_conn_2_info.URI is defined
|
||||
- test_conn_2_info.Default == true
|
||||
# ReadWrite, Identity, and IsMachine are optional fields
|
||||
|
||||
- name: Test with unix socket connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-unix-info"
|
||||
destination: "unix:///run/podman/podman.sock"
|
||||
state: present
|
||||
|
||||
- name: Get info about unix socket connection
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-unix-info"
|
||||
register: unix_info_result
|
||||
|
||||
- name: Check unix socket connection info
|
||||
assert:
|
||||
that:
|
||||
- unix_info_result.connections | length == 1
|
||||
- unix_info_result.connections[0].Name == "test-unix-info"
|
||||
- "'unix://' in unix_info_result.connections[0].URI"
|
||||
|
||||
- name: Test with TCP connection
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-tcp-info"
|
||||
destination: "tcp://localhost:8080"
|
||||
state: present
|
||||
|
||||
- name: Get info about TCP connection
|
||||
containers.podman.podman_system_connection_info:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "test-tcp-info"
|
||||
register: tcp_info_result
|
||||
|
||||
- name: Check TCP connection info
|
||||
assert:
|
||||
that:
|
||||
- tcp_info_result.connections | length == 1
|
||||
- tcp_info_result.connections[0].Name == "test-tcp-info"
|
||||
- "'tcp://' in tcp_info_result.connections[0].URI"
|
||||
|
||||
always:
|
||||
- name: Clean up test connections
|
||||
containers.podman.podman_system_connection:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
loop:
|
||||
- "{{ test_connection_1 }}"
|
||||
- "{{ test_connection_2 }}"
|
||||
- "test-unix-info"
|
||||
- "test-tcp-info"
|
||||
Loading…
Add table
Add a link
Reference in a new issue