summaryrefslogtreecommitdiffstats
path: root/collections-debian-merged/ansible_collections/containers/podman/plugins/modules
diff options
context:
space:
mode:
Diffstat (limited to 'collections-debian-merged/ansible_collections/containers/podman/plugins/modules')
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container.py916
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container_info.py405
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_containers.py162
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image.py774
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image_info.py234
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_login_info.py117
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_logout.py154
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network.py614
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network_info.py138
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod.py232
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod_info.py145
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume.py477
-rw-r--r--collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume_info.py100
14 files changed, 4468 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/__init__.py
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container.py
new file mode 100644
index 00000000..99b14a39
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container.py
@@ -0,0 +1,916 @@
+#!/usr/bin/python
+# Copyright (c) 2020 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_container
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+version_added: '1.0.0'
+short_description: Manage podman containers
+notes: []
+description:
+ - Start, stop, restart and manage Podman containers
+requirements:
+ - podman
+options:
+ name:
+ description:
+ - Name of the container
+ required: True
+ 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
+ state:
+ description:
+ - I(absent) - A container matching the specified name will be stopped and
+ removed.
+ - I(present) - Asserts the existence of a container matching the name and
+ any provided configuration parameters. If no container matches the
+ name, a container will be created. If a container matches the name but
+ the provided configuration does not match, the container will be
+ updated, if it can be. If it cannot be updated, it will be removed and
+ re-created with the requested config. Image version will be taken into
+ account when comparing configuration. Use the recreate option to force
+ the re-creation of the matching container.
+ - I(started) - Asserts there is a running container matching the name and
+ any provided configuration. If no container matches the name, a
+ container will be created and started. Use recreate to always re-create
+ a matching container, even if it is running. Use force_restart to force
+ a matching container to be stopped and restarted.
+ - I(stopped) - Asserts that the container is first I(present), and then
+ if the container is running moves it to a stopped state.
+ type: str
+ default: started
+ choices:
+ - absent
+ - present
+ - stopped
+ - started
+ image:
+ description:
+ - Repository path (or image name) and tag used to create the container.
+ If an image is not found, the image will be pulled from the registry.
+ If no tag is included, C(latest) will be used.
+ - Can also be an image ID. If this is the case, the image is assumed to
+ be available locally.
+ type: str
+ annotation:
+ description:
+ - Add an annotation to the container. The format is key value, multiple
+ times.
+ type: dict
+ authfile:
+ description:
+ - Path of the authentication file. Default is
+ ``${XDG_RUNTIME_DIR}/containers/auth.json``
+ (Not available for remote commands) You can also override the default
+ path of the authentication file by setting the ``REGISTRY_AUTH_FILE``
+ environment variable. ``export REGISTRY_AUTH_FILE=path``
+ type: path
+ blkio_weight:
+ description:
+ - Block IO weight (relative weight) accepts a weight value between 10 and
+ 1000
+ type: int
+ blkio_weight_device:
+ description:
+ - Block IO weight (relative device weight, format DEVICE_NAME[:]WEIGHT).
+ type: dict
+ cap_add:
+ description:
+ - List of capabilities to add to the container.
+ type: list
+ elements: str
+ aliases:
+ - capabilities
+ cap_drop:
+ description:
+ - List of capabilities to drop from the container.
+ type: list
+ elements: str
+ cgroup_parent:
+ description:
+ - Path to cgroups under which the cgroup for the container will be
+ created.
+ If the path is not absolute, the path is considered to be relative to
+ the cgroups path of the init process. Cgroups will be created if they
+ do not already exist.
+ type: path
+ cgroupns:
+ description:
+ - Path to cgroups under which the cgroup for the container will be
+ created.
+ type: str
+ cgroups:
+ description:
+ - Determines whether the container will create CGroups.
+ Valid values are enabled and disabled, which the default being enabled.
+ The disabled option will force the container to not create CGroups,
+ and thus conflicts with CGroup options cgroupns and cgroup-parent.
+ type: str
+ choices:
+ - default
+ - disabled
+ cidfile:
+ description:
+ - Write the container ID to the file
+ type: path
+ cmd_args:
+ description:
+ - Any additional command options you want to pass to podman command,
+ cmd_args - ['--other-param', 'value']
+ Be aware module doesn't support idempotency if this is set.
+ type: list
+ elements: str
+ conmon_pidfile:
+ description:
+ - Write the pid of the conmon process to a file.
+ conmon runs in a separate process than Podman,
+ so this is necessary when using systemd to restart Podman containers.
+ type: path
+ command:
+ description:
+ - Override command of container. Can be a string or a list.
+ type: raw
+ cpu_period:
+ description:
+ - Limit the CPU real-time period in microseconds
+ type: int
+ cpu_rt_period:
+ description:
+ - Limit the CPU real-time period in microseconds.
+ Limit the container's Real Time CPU usage. This flag tell the kernel to
+ restrict the container's Real Time CPU usage to the period you specify.
+ type: int
+ cpu_rt_runtime:
+ description:
+ - Limit the CPU real-time runtime in microseconds.
+ This flag tells the kernel to limit the amount of time in a given CPU
+ period Real Time tasks may consume.
+ type: int
+ cpu_shares:
+ description:
+ - CPU shares (relative weight)
+ type: int
+ cpus:
+ description:
+ - Number of CPUs. The default is 0.0 which means no limit.
+ type: str
+ cpuset_cpus:
+ description:
+ - CPUs in which to allow execution (0-3, 0,1)
+ type: str
+ cpuset_mems:
+ description:
+ - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only
+ effective on NUMA systems.
+ type: str
+ detach:
+ description:
+ - Run container in detach mode
+ type: bool
+ default: True
+ debug:
+ description:
+ - Return additional information which can be helpful for investigations.
+ type: bool
+ default: False
+ detach_keys:
+ description:
+ - Override the key sequence for detaching a container. Format is a single
+ character or ctrl-value
+ type: str
+ device:
+ description:
+ - Add a host device to the container.
+ The format is <device-on-host>[:<device-on-container>][:<permissions>]
+ (e.g. device /dev/sdc:/dev/xvdc:rwm)
+ type: list
+ elements: str
+ device_read_bps:
+ description:
+ - Limit read rate (bytes per second) from a device
+ (e.g. device-read-bps /dev/sda:1mb)
+ type: list
+ device_read_iops:
+ description:
+ - Limit read rate (IO per second) from a device
+ (e.g. device-read-iops /dev/sda:1000)
+ type: list
+ device_write_bps:
+ description:
+ - Limit write rate (bytes per second) to a device
+ (e.g. device-write-bps /dev/sda:1mb)
+ type: list
+ device_write_iops:
+ description:
+ - Limit write rate (IO per second) to a device
+ (e.g. device-write-iops /dev/sda:1000)
+ type: list
+ dns:
+ description:
+ - Set custom DNS servers
+ type: list
+ elements: str
+ aliases:
+ - dns_servers
+ dns_option:
+ description:
+ - Set custom DNS options
+ type: str
+ aliases:
+ - dns_opts
+ dns_search:
+ description:
+ - Set custom DNS search domains (Use dns_search with '' if you don't wish
+ to set the search domain)
+ type: str
+ aliases:
+ - dns_search_domains
+ entrypoint:
+ description:
+ - Overwrite the default ENTRYPOINT of the image
+ type: str
+ env:
+ description:
+ - Set environment variables.
+ This option allows you to specify arbitrary environment variables that
+ are available for the process that will be launched inside of the
+ container.
+ type: dict
+ env_file:
+ description:
+ - Read in a line delimited file of environment variables
+ type: path
+ env_host:
+ description:
+ - Use all current host environment variables in container.
+ Defaults to false.
+ type: bool
+ etc_hosts:
+ description:
+ - Dict of host-to-IP mappings, where each host name is a key in the
+ dictionary. Each host name will be added to the container's
+ ``/etc/hosts`` file.
+ type: dict
+ aliases:
+ - add_hosts
+ expose:
+ description:
+ - Expose a port, or a range of ports (e.g. expose "3300-3310") to set up
+ port redirection on the host system.
+ type: list
+ elements: str
+ aliases:
+ - exposed
+ - exposed_ports
+ force_restart:
+ description:
+ - Force restart of container.
+ type: bool
+ default: False
+ aliases:
+ - restart
+ gidmap:
+ description:
+ - Run the container in a new user namespace using the supplied mapping.
+ type: list
+ elements: str
+ group_add:
+ description:
+ - Add additional groups to run as
+ type: list
+ aliases:
+ - groups
+ healthcheck:
+ description:
+ - Set or alter a healthcheck command for a container.
+ type: str
+ healthcheck_interval:
+ description:
+ - Set an interval for the healthchecks
+ (a value of disable results in no automatic timer setup)
+ (default "30s")
+ type: str
+ healthcheck_retries:
+ description:
+ - The number of retries allowed before a healthcheck is considered to be
+ unhealthy. The default value is 3.
+ type: int
+ healthcheck_start_period:
+ description:
+ - The initialization time needed for a container to bootstrap.
+ The value can be expressed in time format like 2m3s. The default value
+ is 0s
+ type: str
+ healthcheck_timeout:
+ description:
+ - The maximum time allowed to complete the healthcheck before an interval
+ is considered failed. Like start-period, the value can be expressed in
+ a time format such as 1m22s. The default value is 30s
+ type: str
+ hostname:
+ description:
+ - Container host name. Sets the container host name that is available
+ inside the container.
+ type: str
+ http_proxy:
+ description:
+ - By default proxy environment variables are passed into the container if
+ set for the podman process. This can be disabled by setting the
+ http_proxy option to false. The environment variables passed in
+ include http_proxy, https_proxy, ftp_proxy, no_proxy, and also the
+ upper case versions of those.
+ Defaults to true
+ type: bool
+ image_volume:
+ description:
+ - Tells podman how to handle the builtin image volumes.
+ The options are bind, tmpfs, or ignore (default bind)
+ type: str
+ choices:
+ - 'bind'
+ - 'tmpfs'
+ - 'ignore'
+ image_strict:
+ description:
+ - Whether to compare images in idempotency by taking into account a full
+ name with registry and namespaces.
+ type: bool
+ default: False
+ init:
+ description:
+ - Run an init inside the container that forwards signals and reaps
+ processes. The default is false.
+ type: bool
+ init_path:
+ description:
+ - Path to the container-init binary.
+ type: str
+ interactive:
+ description:
+ - Keep STDIN open even if not attached. The default is false.
+ When set to true, keep stdin open even if not attached.
+ The default is false.
+ type: bool
+ ip:
+ description:
+ - Specify a static IP address for the container, for example
+ '10.88.64.128'.
+ Can only be used if no additional CNI networks to join were specified
+ via 'network:', and if the container is not joining another container's
+ network namespace via 'network container:<name|id>'.
+ The address must be within the default CNI network's pool
+ (default 10.88.0.0/16).
+ type: str
+ ipc:
+ description:
+ - Default is to create a private IPC namespace (POSIX SysV IPC) for the
+ container
+ type: str
+ aliases:
+ - ipc_mode
+ kernel_memory:
+ description:
+ - Kernel memory limit
+ (format <number>[<unit>], where unit = b, k, m or g)
+ Note - idempotency is supported for integers only.
+ type: str
+ label:
+ description:
+ - Add metadata to a container, pass dictionary of label names and values
+ aliases:
+ - labels
+ type: dict
+ label_file:
+ description:
+ - Read in a line delimited file of labels
+ type: str
+ log_driver:
+ description:
+ - Logging driver. Used to set the log driver for the container.
+ For example log_driver "k8s-file".
+ type: str
+ choices:
+ - k8s-file
+ - journald
+ - json-file
+ log_level:
+ description:
+ - Logging level for Podman. Log messages above specified level
+ ("debug"|"info"|"warn"|"error"|"fatal"|"panic") (default "error")
+ type: str
+ choices:
+ - debug
+ - info
+ - warn
+ - error
+ - fatal
+ - panic
+ log_opt:
+ description:
+ - Logging driver specific options. Used to set the path to the container
+ log file.
+ type: dict
+ aliases:
+ - log_options
+ suboptions:
+ path:
+ description:
+ - Specify a path to the log file (e.g. /var/log/container/mycontainer.json).
+ type: str
+ required: false
+ max_size:
+ description:
+ - Specify a max size of the log file (e.g 10mb).
+ type: str
+ required: false
+ tag:
+ description:
+ - Specify a custom log tag for the container.
+ type: str
+ required: false
+
+ mac_address:
+ description:
+ - Specify a MAC address for the container, for example
+ '92:d0:c6:0a:29:33'.
+ Don't forget that it must be unique within one Ethernet network.
+ type: str
+ memory:
+ description:
+ - Memory limit (format 10k, where unit = b, k, m or g)
+ Note - idempotency is supported for integers only.
+ type: str
+ memory_reservation:
+ description:
+ - Memory soft limit (format 100m, where unit = b, k, m or g)
+ Note - idempotency is supported for integers only.
+ type: str
+ memory_swap:
+ description:
+ - A limit value equal to memory plus swap. Must be used with the -m
+ (--memory) flag.
+ The swap LIMIT should always be larger than -m (--memory) value.
+ By default, the swap LIMIT will be set to double the value of --memory
+ Note - idempotency is supported for integers only.
+ type: str
+ memory_swappiness:
+ description:
+ - Tune a container's memory swappiness behavior. Accepts an integer
+ between 0 and 100.
+ type: int
+ mount:
+ description:
+ - Attach a filesystem mount to the container. bind or tmpfs
+ For example mount
+ "type=bind,source=/path/on/host,destination=/path/in/container"
+ type: str
+ network:
+ description:
+ - Set the Network mode for the container
+ * bridge create a network stack on the default bridge
+ * none no networking
+ * container:<name|id> reuse another container's network stack
+ * host use the podman host network stack.
+ * <network-name>|<network-id> connect to a user-defined network
+ * ns:<path> path to a network namespace to join
+ * slirp4netns use slirp4netns to create a user network stack.
+ This is the default for rootless containers
+ type: list
+ elements: str
+ aliases:
+ - net
+ - network_mode
+ no_hosts:
+ description:
+ - Do not create /etc/hosts for the container
+ Default is false.
+ type: bool
+ oom_kill_disable:
+ description:
+ - Whether to disable OOM Killer for the container or not.
+ Default is false.
+ type: bool
+ oom_score_adj:
+ description:
+ - Tune the host's OOM preferences for containers (accepts -1000 to 1000)
+ type: int
+ pid:
+ description:
+ - Set the PID mode for the container
+ type: str
+ aliases:
+ - pid_mode
+ pids_limit:
+ description:
+ - Tune the container's PIDs limit. Set -1 to have unlimited PIDs for the
+ container.
+ type: str
+ pod:
+ description:
+ - Run container in an existing pod.
+ If you want podman to make the pod for you, preference the pod name
+ with "new:"
+ type: str
+ privileged:
+ description:
+ - Give extended privileges to this container. The default is false.
+ type: bool
+ publish:
+ description:
+ - Publish a container's port, or range of ports, to the host.
+ Format - ip:hostPort:containerPort | ip::containerPort |
+ hostPort:containerPort | containerPort
+ In case of only containerPort is set, the hostPort will chosen
+ randomly by Podman.
+ type: list
+ elements: str
+ aliases:
+ - ports
+ - published
+ - published_ports
+ publish_all:
+ description:
+ - Publish all exposed ports to random ports on the host interfaces. The
+ default is false.
+ type: bool
+ read_only:
+ description:
+ - Mount the container's root filesystem as read only. Default is false
+ type: bool
+ read_only_tmpfs:
+ description:
+ - If container is running in --read-only mode, then mount a read-write
+ tmpfs on /run, /tmp, and /var/tmp. The default is true
+ type: bool
+ recreate:
+ description:
+ - Use with present and started states to force the re-creation of an
+ existing container.
+ type: bool
+ default: False
+ restart_policy:
+ description:
+ - Restart policy to follow when containers exit.
+ Restart policy will not take effect if a container is stopped via the
+ podman kill or podman stop commands. Valid values are
+ * no - Do not restart containers on exit
+ * on-failure[:max_retries] - Restart containers when they exit with a
+ non-0 exit code, retrying indefinitely
+ or until the optional max_retries count is hit
+ * always - Restart containers when they exit, regardless of status,
+ retrying indefinitely
+ type: str
+ rm:
+ description:
+ - Automatically remove the container when it exits. The default is false.
+ type: bool
+ aliases:
+ - remove
+ - auto_remove
+ rootfs:
+ description:
+ - If true, the first argument refers to an exploded container on the file
+ system. The default is false.
+ type: bool
+ security_opt:
+ description:
+ - Security Options. For example security_opt "seccomp=unconfined"
+ type: list
+ elements: str
+ shm_size:
+ description:
+ - Size of /dev/shm. The format is <number><unit>. number must be greater
+ than 0.
+ Unit is optional and can be b (bytes), k (kilobytes), m(megabytes), or
+ g (gigabytes).
+ If you omit the unit, the system uses bytes. If you omit the size
+ entirely, the system uses 64m
+ type: str
+ sig_proxy:
+ description:
+ - Proxy signals sent to the podman run command to the container process.
+ SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is true.
+ type: bool
+ stop_signal:
+ description:
+ - Signal to stop a container. Default is SIGTERM.
+ type: int
+ stop_timeout:
+ description:
+ - Timeout (in seconds) to stop a container. Default is 10.
+ type: int
+ subgidname:
+ description:
+ - Run the container in a new user namespace using the map with 'name' in
+ the /etc/subgid file.
+ type: str
+ subuidname:
+ description:
+ - Run the container in a new user namespace using the map with 'name' in
+ the /etc/subuid file.
+ type: str
+ sysctl:
+ description:
+ - Configure namespaced kernel parameters at runtime
+ type: dict
+ systemd:
+ description:
+ - Run container in systemd mode. The default is true.
+ type: bool
+ tmpfs:
+ description:
+ - Create a tmpfs mount. For example tmpfs
+ "/tmp" "rw,size=787448k,mode=1777"
+ type: dict
+ tty:
+ description:
+ - Allocate a pseudo-TTY. The default is false.
+ type: bool
+ uidmap:
+ description:
+ - Run the container in a new user namespace using the supplied mapping.
+ type: list
+ elements: str
+ ulimit:
+ description:
+ - Ulimit options
+ type: list
+ aliases:
+ - ulimits
+ user:
+ description:
+ - Sets the username or UID used and optionally the groupname or GID for
+ the specified command.
+ type: str
+ userns:
+ description:
+ - Set the user namespace mode for the container.
+ It defaults to the PODMAN_USERNS environment variable.
+ An empty value means user namespaces are disabled.
+ type: str
+ aliases:
+ - userns_mode
+ uts:
+ description:
+ - Set the UTS mode for the container
+ type: str
+ volume:
+ description:
+ - Create a bind mount. If you specify, volume /HOST-DIR:/CONTAINER-DIR,
+ podman bind mounts /HOST-DIR in the host to /CONTAINER-DIR in the
+ podman container.
+ type: list
+ elements: str
+ aliases:
+ - volumes
+ volumes_from:
+ description:
+ - Mount volumes from the specified container(s).
+ type: list
+ elements: str
+ workdir:
+ description:
+ - Working directory inside the container.
+ The default working directory for running binaries within a container
+ is the root directory (/).
+ type: str
+ aliases:
+ - working_dir
+"""
+
+EXAMPLES = r"""
+- name: Run container
+ containers.podman.podman_container:
+ name: container
+ image: quay.io/bitnami/wildfly
+ state: started
+
+- name: Create a data container
+ containers.podman.podman_container:
+ name: mydata
+ image: busybox
+ volume:
+ - /tmp/data
+
+- name: Re-create a redis container
+ containers.podman.podman_container:
+ name: myredis
+ image: redis
+ command: redis-server --appendonly yes
+ state: present
+ recreate: yes
+ expose:
+ - 6379
+ volumes_from:
+ - mydata
+
+- name: Restart a container
+ containers.podman.podman_container:
+ name: myapplication
+ image: redis
+ state: started
+ restart: yes
+ etc_hosts:
+ other: "127.0.0.1"
+ restart_policy: "no"
+ device: "/dev/sda:/dev/xvda:rwm"
+ ports:
+ - "8080:9000"
+ - "127.0.0.1:8081:9001/udp"
+ env:
+ SECRET_KEY: "ssssh"
+ BOOLEAN_KEY: "yes"
+
+- name: Container present
+ containers.podman.podman_container:
+ name: mycontainer
+ state: present
+ image: ubuntu:14.04
+ command: "sleep 1d"
+
+- name: Stop a container
+ containers.podman.podman_container:
+ name: mycontainer
+ state: stopped
+
+- name: Start 4 load-balanced containers
+ containers.podman.podman_container:
+ name: "container{{ item }}"
+ recreate: yes
+ image: someuser/anotherappimage
+ command: sleep 1d
+ with_sequence: count=4
+
+- name: remove container
+ containers.podman.podman_container:
+ name: ohno
+ state: absent
+
+- name: Writing output
+ containers.podman.podman_container:
+ name: myservice
+ image: busybox
+ log_options: path=/var/log/container/mycontainer.json
+ log_driver: k8s-file
+"""
+
+RETURN = r"""
+container:
+ description:
+ - Facts representing the current state of the container. Matches the
+ podman inspection output.
+ - Note that facts are part of the registered vars since Ansible 2.8. For
+ compatibility reasons, the facts
+ are also accessible directly as C(podman_container). Note that the
+ returned fact will be removed in Ansible 2.12.
+ - Empty if C(state) is I(absent).
+ returned: always
+ type: dict
+ sample: '{
+ "AppArmorProfile": "",
+ "Args": [
+ "sh"
+ ],
+ "BoundingCaps": [
+ "CAP_CHOWN",
+ ...
+ ],
+ "Config": {
+ "Annotations": {
+ "io.kubernetes.cri-o.ContainerType": "sandbox",
+ "io.kubernetes.cri-o.TTY": "false"
+ },
+ "AttachStderr": false,
+ "AttachStdin": false,
+ "AttachStdout": false,
+ "Cmd": [
+ "sh"
+ ],
+ "Domainname": "",
+ "Entrypoint": "",
+ "Env": [
+ "PATH=/usr/sbin:/usr/bin:/sbin:/bin",
+ "TERM=xterm",
+ "HOSTNAME=",
+ "container=podman"
+ ],
+ "Hostname": "",
+ "Image": "docker.io/library/busybox:latest",
+ "Labels": null,
+ "OpenStdin": false,
+ "StdinOnce": false,
+ "StopSignal": 15,
+ "Tty": false,
+ "User": {
+ "gid": 0,
+ "uid": 0
+ },
+ "Volumes": null,
+ "WorkingDir": "/"
+ },
+ "ConmonPidFile": "...",
+ "Created": "2019-06-17T19:13:09.873858307+03:00",
+ "Dependencies": [],
+ "Driver": "overlay",
+ "EffectiveCaps": [
+ "CAP_CHOWN",
+ ...
+ ],
+ "ExecIDs": [],
+ "ExitCommand": [
+ "/usr/bin/podman",
+ "--root",
+ ...
+ ],
+ "GraphDriver": {
+ ...
+ },
+ "HostConfig": {
+ ...
+ },
+ "HostnamePath": "...",
+ "HostsPath": "...",
+ "ID": "...",
+ "Image": "...",
+ "ImageName": "docker.io/library/busybox:latest",
+ "IsInfra": false,
+ "LogPath": "/tmp/container/mycontainer.json",
+ "MountLabel": "system_u:object_r:container_file_t:s0:c282,c782",
+ "Mounts": [
+ ...
+ ],
+ "Name": "myservice",
+ "Namespace": "",
+ "NetworkSettings": {
+ "Bridge": "",
+ ...
+ },
+ "Path": "sh",
+ "ProcessLabel": "system_u:system_r:container_t:s0:c282,c782",
+ "ResolvConfPath": "...",
+ "RestartCount": 0,
+ "Rootfs": "",
+ "State": {
+ "Dead": false,
+ "Error": "",
+ "ExitCode": 0,
+ "FinishedAt": "2019-06-17T19:13:10.157518963+03:00",
+ "Healthcheck": {
+ "FailingStreak": 0,
+ "Log": null,
+ "Status": ""
+ },
+ "OOMKilled": false,
+ "OciVersion": "1.0.1-dev",
+ "Paused": false,
+ "Pid": 4083,
+ "Restarting": false,
+ "Running": false,
+ "StartedAt": "2019-06-17T19:13:10.152479729+03:00",
+ "Status": "exited"
+ },
+ "StaticDir": "..."
+ ...
+ }'
+"""
+
+from ansible.module_utils.basic import AnsibleModule # noqa: F402
+from ..module_utils.podman.podman_container_lib import PodmanManager # noqa: F402
+from ..module_utils.podman.podman_container_lib import ARGUMENTS_SPEC_CONTAINER # noqa: F402
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=ARGUMENTS_SPEC_CONTAINER,
+ mutually_exclusive=(
+ ['no_hosts', 'etc_hosts'],
+ ),
+ supports_check_mode=True,
+ )
+
+ # work on input vars
+ if module.params['state'] in ['started', 'present'] and \
+ not module.params['image']:
+ module.fail_json(msg="State '%s' required image to be configured!" %
+ module.params['state'])
+
+ results = PodmanManager(module, module.params).execute()
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container_info.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container_info.py
new file mode 100644
index 00000000..d3ec55c8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_container_info.py
@@ -0,0 +1,405 @@
+#!/usr/bin/python
+# Copyright (c) 2020 Red Hat
+# 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_container_info
+author:
+ - Sagi Shnaidman (@sshnaidm)
+ - Emilien Macchi (@EmilienM)
+short_description: Gather facts about containers using podman
+notes:
+ - Podman may require elevated privileges in order to run properly.
+description:
+ - Gather facts about containers using C(podman)
+requirements:
+ - "Podman installed on host"
+options:
+ name:
+ description:
+ - List of container names to gather facts about. If no name is given
+ return facts about all containers.
+ type: list
+ elements: 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 facts for all containers
+ containers.podman.podman_container_info:
+
+- name: Gather facts on a specific container
+ containers.podman.podman_container_info:
+ name: web1
+
+- name: Gather facts on several containers
+ containers.podman.podman_container_info:
+ name:
+ - redis
+ - web1
+"""
+
+RETURN = r"""
+containers:
+ description: Facts from all or specificed containers
+ returned: always
+ type: list
+ elements: dict
+ sample: [
+ {
+ "Id": "c5c39f9b80a6ea2ad665aa9946435934e478a0c5322da835f3883872f",
+ "Created": "2019-10-01T12:51:00.233106443Z",
+ "Path": "dumb-init",
+ "Args": [
+ "--single-child",
+ "--",
+ "kolla_start"
+ ],
+ "State": {
+ "OciVersion": "1.0.1-dev",
+ "Status": "configured",
+ "Running": false,
+ "Paused": false,
+ "Restarting": false,
+ "OOMKilled": false,
+ "Dead": false,
+ "Pid": 0,
+ "ExitCode": 0,
+ "Error": "",
+ "StartedAt": "0001-01-01T00:00:00Z",
+ "FinishedAt": "0001-01-01T00:00:00Z",
+ "Healthcheck": {
+ "Status": "",
+ "FailingStreak": 0,
+ "Log": null
+ }
+ },
+ "Image": "0e267acda67d0ebd643e900d820a91b961d859743039e620191ca1",
+ "ImageName": "docker.io/tripleomaster/centos-haproxy:latest",
+ "Rootfs": "",
+ "Pod": "",
+ "ResolvConfPath": "",
+ "HostnamePath": "",
+ "HostsPath": "",
+ "OCIRuntime": "runc",
+ "Name": "haproxy",
+ "RestartCount": 0,
+ "Driver": "overlay",
+ "MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c78,c866",
+ "ProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c785,c866",
+ "AppArmorProfile": "",
+ "EffectiveCaps": [
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FSETID",
+ "CAP_FOWNER",
+ "CAP_MKNOD",
+ "CAP_NET_RAW",
+ "CAP_SETGID",
+ "CAP_SETUID",
+ "CAP_SETFCAP",
+ "CAP_SETPCAP",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SYS_CHROOT",
+ "CAP_KILL",
+ "CAP_AUDIT_WRITE"
+ ],
+ "BoundingCaps": [
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FSETID",
+ "CAP_FOWNER",
+ "CAP_MKNOD",
+ "CAP_NET_RAW",
+ "CAP_SETGID",
+ "CAP_SETUID",
+ "CAP_SETFCAP",
+ "CAP_SETPCAP",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SYS_CHROOT",
+ "CAP_KILL",
+ "CAP_AUDIT_WRITE"
+ ],
+ "ExecIDs": [],
+ "GraphDriver": {
+ "Name": "overlay"
+ },
+ "Mounts": [],
+ "Dependencies": [],
+ "NetworkSettings": {
+ "Bridge": "",
+ "SandboxID": "",
+ "HairpinMode": false,
+ "LinkLocalIPv6Address": "",
+ "LinkLocalIPv6PrefixLen": 0,
+ "Ports": [],
+ "SandboxKey": "",
+ "SecondaryIPAddresses": null,
+ "SecondaryIPv6Addresses": null,
+ "EndpointID": "",
+ "Gateway": "",
+ "GlobalIPv6Address": "",
+ "GlobalIPv6PrefixLen": 0,
+ "IPAddress": "",
+ "IPPrefixLen": 0,
+ "IPv6Gateway": "",
+ "MacAddress": ""
+ },
+ "ExitCommand": [
+ "/usr/bin/podman",
+ "--root",
+ "/var/lib/containers/storage",
+ "--runroot",
+ "/var/run/containers/storage",
+ "--log-level",
+ "error",
+ "--cgroup-manager",
+ "systemd",
+ "--tmpdir",
+ "/var/run/libpod",
+ "--runtime",
+ "runc",
+ "--storage-driver",
+ "overlay",
+ "--events-backend",
+ "journald",
+ "container",
+ "cleanup",
+ "c9e813703f9b80a6ea2ad665aa9946435934e478a0c5322da835f3883872f"
+ ],
+ "Namespace": "",
+ "IsInfra": false,
+ "Config": {
+ "Hostname": "c5c39e813703",
+ "Domainname": "",
+ "User": "",
+ "AttachStdin": false,
+ "AttachStdout": false,
+ "AttachStderr": false,
+ "Tty": false,
+ "OpenStdin": false,
+ "StdinOnce": false,
+ "Env": [
+ "PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "TERM=xterm",
+ "HOSTNAME=",
+ "container=oci",
+ "KOLLA_INSTALL_METATYPE=rdo",
+ "KOLLA_BASE_DISTRO=centos",
+ "KOLLA_INSTALL_TYPE=binary",
+ "KOLLA_DISTRO_PYTHON_VERSION=2.7",
+ "KOLLA_BASE_ARCH=x86_64"
+ ],
+ "Cmd": [
+ "kolla_start"
+ ],
+ "Image": "docker.io/tripleomaster/centos-haproxy:latest",
+ "Volumes": null,
+ "WorkingDir": "/",
+ "Entrypoint": "dumb-init --single-child --",
+ "OnBuild": null,
+ "Labels": {
+ "build-date": "20190919",
+ "kolla_version": "8.1.0",
+ "name": "haproxy",
+ "org.label-schema.build-date": "20190801",
+ "org.label-schema.license": "GPLv2",
+ "org.label-schema.name": "CentOS Base Image",
+ "org.label-schema.schema-version": "1.0",
+ "org.label-schema.vendor": "CentOS"
+ },
+ "Annotations": {
+ "io.kubernetes.cri-o.ContainerType": "sandbox",
+ "io.kubernetes.cri-o.TTY": "false",
+ "io.podman.annotations.autoremove": "FALSE",
+ "io.podman.annotations.init": "FALSE",
+ "io.podman.annotations.privileged": "FALSE",
+ "io.podman.annotations.publish-all": "FALSE"
+ },
+ "StopSignal": 15
+ },
+ "HostConfig": {
+ "Binds": [],
+ "ContainerIDFile": "",
+ "LogConfig": {
+ "Type": "k8s-file",
+ "Config": null
+ },
+ "NetworkMode": "default",
+ "PortBindings": {},
+ "RestartPolicy": {
+ "Name": "",
+ "MaximumRetryCount": 0
+ },
+ "AutoRemove": false,
+ "VolumeDriver": "",
+ "VolumesFrom": null,
+ "CapAdd": [],
+ "CapDrop": [],
+ "Dns": [],
+ "DnsOptions": [],
+ "DnsSearch": [],
+ "ExtraHosts": [],
+ "GroupAdd": [],
+ "IpcMode": "",
+ "Cgroup": "",
+ "Links": null,
+ "OomScoreAdj": 0,
+ "PidMode": "",
+ "Privileged": false,
+ "PublishAllPorts": false,
+ "ReadonlyRootfs": false,
+ "SecurityOpt": [],
+ "Tmpfs": {},
+ "UTSMode": "",
+ "UsernsMode": "",
+ "ShmSize": 65536000,
+ "Runtime": "oci",
+ "ConsoleSize": [
+ 0,
+ 0
+ ],
+ "Isolation": "",
+ "CpuShares": 0,
+ "Memory": 0,
+ "NanoCpus": 0,
+ "CgroupParent": "",
+ "BlkioWeight": 0,
+ "BlkioWeightDevice": null,
+ "BlkioDeviceReadBps": null,
+ "BlkioDeviceWriteBps": null,
+ "BlkioDeviceReadIOps": null,
+ "BlkioDeviceWriteIOps": null,
+ "CpuPeriod": 0,
+ "CpuQuota": 0,
+ "CpuRealtimePeriod": 0,
+ "CpuRealtimeRuntime": 0,
+ "CpusetCpus": "",
+ "CpusetMems": "",
+ "Devices": [],
+ "DiskQuota": 0,
+ "KernelMemory": 0,
+ "MemoryReservation": 0,
+ "MemorySwap": 0,
+ "MemorySwappiness": -1,
+ "OomKillDisable": false,
+ "PidsLimit": 0,
+ "Ulimits": [
+ {
+ "Name": "RLIMIT_NOFILE",
+ "Soft": 1048576,
+ "Hard": 1048576
+ },
+ {
+ "Name": "RLIMIT_NPROC",
+ "Soft": 1048576,
+ "Hard": 1048576
+ }
+ ],
+ "CpuCount": 0,
+ "CpuPercent": 0,
+ "IOMaximumIOps": 0,
+ "IOMaximumBandwidth": 0
+ }
+ }
+ ]
+"""
+
+import json
+from ansible.module_utils.basic import AnsibleModule
+
+
+def get_containers_facts(module, executable, name):
+ """Collect containers facts for all containers or for specified in 'name'.
+
+ Arguments:
+ module {AnsibleModule} -- instance of AnsibleModule
+ executable {string} -- binary to execute when inspecting containers
+ name {list} -- list of names or None in case of all containers
+
+ Returns:
+ list of containers info, stdout, stderr
+ """
+ if not name:
+ all_names = [executable, 'container', 'ls', '-q', '-a']
+ rc, out, err = module.run_command(all_names)
+ if rc != 0:
+ module.fail_json(msg="Unable to get list of containers: %s" % err)
+ name = out.split()
+ if not name:
+ return [], out, err
+ command = [executable, 'container', 'inspect']
+ command.extend(name)
+ rc, out, err = module.run_command(command)
+ if rc == 0:
+ json_out = json.loads(out) if out else None
+ if json_out is None:
+ return [], out, err
+ return json_out, out, err
+ if rc != 0 and 'no such ' in err:
+ if len(name) < 2:
+ return [], out, err
+ return cycle_over(module, executable, name)
+ module.fail_json(msg="Unable to gather info for %s: %s" % (",".join(name), err))
+
+
+def cycle_over(module, executable, name):
+ """Inspect each container in a cycle in case some of them don't exist.
+
+ Arguments:
+ module {AnsibleModule} -- instance of AnsibleModule
+ executable {string} -- binary to execute when inspecting containers
+ name {list} -- list of containers names to inspect
+
+ Returns:
+ list of containers info, stdout as empty, stderr
+ """
+ inspection = []
+ stderrs = []
+ for container in name:
+ command = [executable, 'container', 'inspect', container]
+ rc, out, err = module.run_command(command)
+ if rc != 0 and 'no such ' not in err:
+ module.fail_json(msg="Unable to gather info for %s: %s" % (container, err))
+ if rc == 0 and out:
+ json_out = json.loads(out)
+ if json_out:
+ inspection += json_out
+ stderrs.append(err)
+ return inspection, "", "\n".join(stderrs)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec={
+ 'executable': {'type': 'str', 'default': 'podman'},
+ 'name': {'type': 'list', 'elements': 'str'},
+ },
+ supports_check_mode=True,
+ )
+
+ name = module.params['name']
+ executable = module.get_bin_path(module.params['executable'], required=True)
+ # pylint: disable=unused-variable
+ inspect_results, out, err = get_containers_facts(module, executable, name)
+
+ results = {
+ "changed": False,
+ "containers": inspect_results,
+ "stderr": err
+ }
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_containers.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_containers.py
new file mode 100644
index 00000000..75ebb057
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_containers.py
@@ -0,0 +1,162 @@
+#!/usr/bin/python
+# Copyright (c) 2020 Red Hat
+# 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 = '''
+---
+module: podman_containers
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+version_added: '1.4.0'
+short_description: Manage podman containers in a batch
+description:
+ - Manage groups of podman containers
+requirements:
+ - "podman"
+options:
+ containers:
+ description:
+ - List of dictionaries with data for running containers for podman_container module.
+ required: True
+ type: list
+ elements: dict
+ debug:
+ description:
+ - Return additional information which can be helpful for investigations.
+ type: bool
+ default: False
+'''
+
+EXAMPLES = '''
+- name: Run three containers at once
+ podman_containers:
+ containers:
+ - name: alpine
+ image: alpine
+ command: sleep 1d
+ - name: web
+ image: nginx
+ - name: test
+ image: python:3-alpine
+ command: python -V
+'''
+
+from copy import deepcopy # noqa: F402
+
+from ansible.module_utils.basic import AnsibleModule # noqa: F402
+from ..module_utils.podman.podman_container_lib import PodmanManager # noqa: F402
+from ..module_utils.podman.podman_container_lib import ARGUMENTS_SPEC_CONTAINER # noqa: F402
+
+
+def init_options():
+ default = {}
+ opts = ARGUMENTS_SPEC_CONTAINER
+ for k, v in opts.items():
+ if 'default' in v:
+ default[k] = v['default']
+ else:
+ default[k] = None
+ return default
+
+
+def update_options(opts_dict, container):
+ aliases = {}
+ for k, v in ARGUMENTS_SPEC_CONTAINER.items():
+ if 'aliases' in v:
+ for alias in v['aliases']:
+ aliases[alias] = k
+ for k in list(container):
+ if k in aliases:
+ key = aliases[k]
+ opts_dict[key] = container[k]
+ container.pop(k)
+ opts_dict.update(container)
+ return opts_dict
+
+
+def combine(results):
+ changed = any([i.get('changed', False) for i in results])
+ failed = any([i.get('failed', False) for i in results])
+ actions = []
+ podman_actions = []
+ containers = []
+ podman_version = ''
+ diffs = {}
+ stderr = ''
+ stdout = ''
+ for i in results:
+ if 'actions' in i and i['actions']:
+ actions += i['actions']
+ if 'podman_actions' in i and i['podman_actions']:
+ podman_actions += i['podman_actions']
+ if 'container' in i and i['container']:
+ containers.append(i['container'])
+ if 'podman_version' in i:
+ podman_version = i['podman_version']
+ if 'diff' in i:
+ diffs[i['container']['Name']] = i['diff']
+ if 'stderr' in i:
+ stderr += i['stderr']
+ if 'stdout' in i:
+ stdout += i['stdout']
+
+ total = {
+ 'changed': changed,
+ 'failed': failed,
+ 'actions': actions,
+ 'podman_actions': podman_actions,
+ 'containers': containers,
+ 'stdout': stdout,
+ 'stderr': stderr,
+ }
+ if podman_version:
+ total['podman_version'] = podman_version
+ if diffs:
+ before = after = ''
+ for k, v in diffs.items():
+ before += "".join([str(k), ": ", str(v['before']), "\n"])
+ after += "".join([str(k), ": ", str(v['after']), "\n"])
+ total['diff'] = {
+ 'before': before,
+ 'after': after
+ }
+ return total
+
+
+def check_input_strict(container):
+ if container['state'] in ['started', 'present'] and not container['image']:
+ return "State '%s' required image to be configured!" % container['state']
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ containers=dict(type='list', elements='dict', required=True),
+ debug=dict(type='bool', default=False),
+ ),
+ supports_check_mode=True,
+ )
+ # work on input vars
+
+ results = []
+ default_options_templ = init_options()
+ for container in module.params['containers']:
+ options_dict = deepcopy(default_options_templ)
+ options_dict = update_options(options_dict, container)
+ options_dict['debug'] = module.params['debug'] or options_dict['debug']
+ test_input = check_input_strict(options_dict)
+ if test_input:
+ module.fail_json(
+ msg="Failed to run container %s because: %s" % (options_dict['name'], test_input))
+ res = PodmanManager(module, options_dict).execute()
+ results.append(res)
+ total_results = combine(results)
+ module.exit_json(**total_results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image.py
new file mode 100644
index 00000000..186f0498
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image.py
@@ -0,0 +1,774 @@
+#!/usr/bin/python
+# Copyright (c) 2018 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_image
+ author:
+ - Sam Doran (@samdoran)
+ short_description: Pull images for use by podman
+ notes: []
+ description:
+ - Build, pull, or push images using Podman.
+ options:
+ name:
+ description:
+ - Name of the image to pull, push, or delete. It may contain a tag using the format C(image:tag).
+ required: True
+ 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
+ ca_cert_dir:
+ description:
+ - Path to directory containing TLS certificates and keys to use.
+ type: 'path'
+ tag:
+ description:
+ - Tag of the image to pull, push, or delete.
+ default: "latest"
+ type: str
+ pull:
+ description: Whether or not to pull the image.
+ default: True
+ type: bool
+ push:
+ description: Whether or not to push an image.
+ default: False
+ type: bool
+ path:
+ description: Path to directory containing the build file.
+ type: str
+ force:
+ description:
+ - Whether or not to force push or pull an image.
+ - When building, force the build even if the image already exists.
+ type: bool
+ default: False
+ state:
+ description:
+ - Whether an image should be present, absent, or built.
+ default: "present"
+ type: str
+ choices:
+ - present
+ - absent
+ - build
+ validate_certs:
+ description:
+ - Require HTTPS and validate certificates when pulling or pushing. Also used during build if a pull or push is necessary.
+ default: True
+ type: bool
+ aliases:
+ - tlsverify
+ - tls_verify
+ password:
+ description:
+ - Password to use when authenticating to remote registries.
+ type: str
+ username:
+ description:
+ - username to use when authenticating to remote registries.
+ type: str
+ auth_file:
+ description:
+ - Path to file containing authorization credentials to the remote registry.
+ aliases:
+ - authfile
+ type: path
+ build:
+ description: Arguments that control image build.
+ type: dict
+ aliases:
+ - build_args
+ - buildargs
+ suboptions:
+ volume:
+ description:
+ - Specify multiple volume / mount options to mount one or more mounts to a container.
+ type: list
+ elements: str
+ annotation:
+ description:
+ - Dictionary of key=value pairs to add to the image. Only works with OCI images. Ignored for Docker containers.
+ type: dict
+ force_rm:
+ description:
+ - Always remove intermediate containers after a build, even if the build is unsuccessful.
+ type: bool
+ default: False
+ format:
+ description:
+ - Format of the built image.
+ type: str
+ choices:
+ - docker
+ - oci
+ default: "oci"
+ cache:
+ description:
+ - Whether or not to use cached layers when building an image
+ type: bool
+ default: True
+ rm:
+ description: Remove intermediate containers after a successful build
+ type: bool
+ default: True
+ extra_args:
+ description:
+ - Extra args to pass to build, if executed. Does not idempotently check for new build args.
+ type: str
+ push_args:
+ description: Arguments that control pushing images.
+ type: dict
+ suboptions:
+ compress:
+ description:
+ - Compress tarball image layers when pushing to a directory using the 'dir' transport.
+ type: bool
+ format:
+ description:
+ - Manifest type to use when pushing an image using the 'dir' transport (default is manifest type of source).
+ type: str
+ choices:
+ - oci
+ - v2s1
+ - v2s2
+ remove_signatures:
+ description: Discard any pre-existing signatures in the image
+ type: bool
+ sign_by:
+ description:
+ - Path to a key file to use to sign the image.
+ type: str
+ dest:
+ description: Path or URL where image will be pushed.
+ type: str
+ aliases:
+ - destination
+ transport:
+ description:
+ - Transport to use when pushing in image. If no transport is set, will attempt to push to a remote registry.
+ type: str
+ choices:
+ - dir
+ - docker-archive
+ - docker-daemon
+ - oci-archive
+ - ostree
+'''
+
+EXAMPLES = r"""
+- name: Pull an image
+ container.podman.podman_image:
+ name: quay.io/bitnami/wildfly
+
+- name: Remove an image
+ container.podman.podman_image:
+ name: quay.io/bitnami/wildfly
+ state: absent
+
+- name: Pull a specific version of an image
+ container.podman.podman_image:
+ name: redis
+ tag: 4
+
+- name: Build a basic OCI image
+ container.podman.podman_image:
+ name: nginx
+ path: /path/to/build/dir
+
+- name: Build a basic OCI image with advanced parameters
+ container.podman.podman_image:
+ name: nginx
+ path: /path/to/build/dir
+ build:
+ cache: no
+ force_rm: yes
+ format: oci
+ annotation:
+ app: nginx
+ function: proxy
+ info: Load balancer for my cool app
+
+- name: Build a Docker formatted image
+ container.podman.podman_image:
+ name: nginx
+ path: /path/to/build/dir
+ build:
+ format: docker
+
+- name: Build and push an image using existing credentials
+ container.podman.podman_image:
+ name: nginx
+ path: /path/to/build/dir
+ push: yes
+ push_args:
+ dest: quay.io/acme
+
+- name: Build and push an image using an auth file
+ container.podman.podman_image:
+ name: nginx
+ push: yes
+ auth_file: /etc/containers/auth.json
+ push_args:
+ dest: quay.io/acme
+
+- name: Build and push an image using username and password
+ container.podman.podman_image:
+ name: nginx
+ push: yes
+ username: bugs
+ password: "{{ vault_registry_password }}"
+ push_args:
+ dest: quay.io/acme
+
+- name: Build and push an image to multiple registries
+ container.podman.podman_image:
+ name: "{{ item }}"
+ path: /path/to/build/dir
+ push: yes
+ auth_file: /etc/containers/auth.json
+ loop:
+ - quay.io/acme/nginx
+ - docker.io/acme/nginx
+
+- name: Build and push an image to multiple registries with separate parameters
+ container.podman.podman_image:
+ name: "{{ item.name }}"
+ tag: "{{ item.tag }}"
+ path: /path/to/build/dir
+ push: yes
+ auth_file: /etc/containers/auth.json
+ push_args:
+ dest: "{{ item.dest }}"
+ loop:
+ - name: nginx
+ tag: 4
+ dest: docker.io/acme
+
+ - name: nginx
+ tag: 3
+ dest: docker.io/acme
+"""
+
+RETURN = r"""
+ image:
+ description:
+ - Image inspection results for the image that was pulled, pushed, or built.
+ returned: success
+ type: dict
+ sample: [
+ {
+ "Annotations": {},
+ "Architecture": "amd64",
+ "Author": "",
+ "Comment": "from Bitnami with love",
+ "ContainerConfig": {
+ "Cmd": [
+ "/run.sh"
+ ],
+ "Entrypoint": [
+ "/app-entrypoint.sh"
+ ],
+ "Env": [
+ "PATH=/opt/bitnami/java/bin:/opt/bitnami/wildfly/bin:/opt/bitnami/nami/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "IMAGE_OS=debian-9",
+ "NAMI_VERSION=1.0.0-1",
+ "GPG_KEY_SERVERS_LIST=ha.pool.sks-keyservers.net",
+ "TINI_VERSION=v0.13.2",
+ "TINI_GPG_KEY=595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7",
+ "GOSU_VERSION=1.10",
+ "GOSU_GPG_KEY=B42F6819007F00F88E364FD4036A9C25BF357DD4",
+ "BITNAMI_IMAGE_VERSION=16.0.0-debian-9-r27",
+ "BITNAMI_PKG_CHMOD=-R g+rwX",
+ "BITNAMI_PKG_EXTRA_DIRS=/home/wildfly",
+ "HOME=/",
+ "BITNAMI_APP_NAME=wildfly",
+ "NAMI_PREFIX=/.nami",
+ "WILDFLY_HOME=/home/wildfly",
+ "WILDFLY_JAVA_HOME=",
+ "WILDFLY_JAVA_OPTS=",
+ "WILDFLY_MANAGEMENT_HTTP_PORT_NUMBER=9990",
+ "WILDFLY_PASSWORD=bitnami",
+ "WILDFLY_PUBLIC_CONSOLE=true",
+ "WILDFLY_SERVER_AJP_PORT_NUMBER=8009",
+ "WILDFLY_SERVER_HTTP_PORT_NUMBER=8080",
+ "WILDFLY_SERVER_INTERFACE=0.0.0.0",
+ "WILDFLY_USERNAME=user",
+ "WILDFLY_WILDFLY_HOME=/home/wildfly",
+ "WILDFLY_WILDFLY_OPTS=-Dwildfly.as.deployment.ondemand=false"
+ ],
+ "ExposedPorts": {
+ "8080/tcp": {},
+ "9990/tcp": {}
+ },
+ "Labels": {
+ "maintainer": "Bitnami <containers@bitnami.com>"
+ },
+ "User": "1001"
+ },
+ "Created": "2019-04-10T05:48:03.553887623Z",
+ "Digest": "sha256:5a8ab28e314c2222de3feaf6dac94a0436a37fc08979d2722c99d2bef2619a9b",
+ "GraphDriver": {
+ "Data": {
+ "LowerDir": "/var/lib/containers/storage/overlay/142c1beadf1bb09fbd929465ec98c9dca3256638220450efb4214727d0d0680e/diff:/var/lib/containers/s",
+ "MergedDir": "/var/lib/containers/storage/overlay/9aa10191f5bddb59e28508e721fdeb43505e5b395845fa99723ed787878dbfea/merged",
+ "UpperDir": "/var/lib/containers/storage/overlay/9aa10191f5bddb59e28508e721fdeb43505e5b395845fa99723ed787878dbfea/diff",
+ "WorkDir": "/var/lib/containers/storage/overlay/9aa10191f5bddb59e28508e721fdeb43505e5b395845fa99723ed787878dbfea/work"
+ },
+ "Name": "overlay"
+ },
+ "History": [
+ {
+ "comment": "from Bitnami with love",
+ "created": "2019-04-09T22:27:40.659377677Z"
+ },
+ {
+ "created": "2019-04-09T22:38:53.86336555Z",
+ "created_by": "/bin/sh -c #(nop) LABEL maintainer=Bitnami <containers@bitnami.com>",
+ "empty_layer": true
+ },
+ {
+ "created": "2019-04-09T22:38:54.022778765Z",
+ "created_by": "/bin/sh -c #(nop) ENV IMAGE_OS=debian-9",
+ "empty_layer": true
+ },
+ ],
+ "Id": "ace34da54e4af2145e1ad277005adb235a214e4dfe1114c2db9ab460b840f785",
+ "Labels": {
+ "maintainer": "Bitnami <containers@bitnami.com>"
+ },
+ "ManifestType": "application/vnd.docker.distribution.manifest.v1+prettyjws",
+ "Os": "linux",
+ "Parent": "",
+ "RepoDigests": [
+ "quay.io/bitnami/wildfly@sha256:5a8ab28e314c2222de3feaf6dac94a0436a37fc08979d2722c99d2bef2619a9b"
+ ],
+ "RepoTags": [
+ "quay.io/bitnami/wildfly:latest"
+ ],
+ "RootFS": {
+ "Layers": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "Type": "layers"
+ },
+ "Size": 466180019,
+ "User": "1001",
+ "Version": "18.09.3",
+ "VirtualSize": 466180019
+ }
+ ]
+"""
+
+import json
+import re
+import shlex
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.containers.podman.plugins.module_utils.podman.common import run_podman_command
+
+
+class PodmanImageManager(object):
+
+ def __init__(self, module, results):
+
+ super(PodmanImageManager, self).__init__()
+
+ self.module = module
+ self.results = results
+ self.name = self.module.params.get('name')
+ self.executable = self.module.get_bin_path(module.params.get('executable'), required=True)
+ self.tag = self.module.params.get('tag')
+ self.pull = self.module.params.get('pull')
+ self.push = self.module.params.get('push')
+ self.path = self.module.params.get('path')
+ self.force = self.module.params.get('force')
+ self.state = self.module.params.get('state')
+ self.validate_certs = self.module.params.get('validate_certs')
+ self.auth_file = self.module.params.get('auth_file')
+ self.username = self.module.params.get('username')
+ self.password = self.module.params.get('password')
+ self.ca_cert_dir = self.module.params.get('ca_cert_dir')
+ self.build = self.module.params.get('build')
+ self.push_args = self.module.params.get('push_args')
+
+ repo, repo_tag = parse_repository_tag(self.name)
+ if repo_tag:
+ self.name = repo
+ self.tag = repo_tag
+
+ self.image_name = '{name}:{tag}'.format(name=self.name, tag=self.tag)
+
+ if self.state in ['present', 'build']:
+ self.present()
+
+ if self.state in ['absent']:
+ self.absent()
+
+ def _run(self, args, expected_rc=0, ignore_errors=False):
+ return run_podman_command(
+ module=self.module,
+ executable=self.executable,
+ args=args,
+ expected_rc=expected_rc,
+ ignore_errors=ignore_errors)
+
+ def _get_id_from_output(self, lines, startswith=None, contains=None, split_on=' ', maxsplit=1):
+ layer_ids = []
+ for line in lines.splitlines():
+ if startswith and line.startswith(startswith) or contains and contains in line:
+ splitline = line.rsplit(split_on, maxsplit)
+ layer_ids.append(splitline[1])
+
+ # Podman 1.4 changed the output to only include the layer id when run in quiet mode
+ if not layer_ids:
+ layer_ids = lines.splitlines()
+
+ return(layer_ids[-1])
+
+ def present(self):
+ image = self.find_image()
+
+ if image:
+ digest_before = image[0].get('Digest', image[0].get('digest'))
+ else:
+ digest_before = None
+
+ if not image or self.force:
+ if self.path:
+ # Build the image
+ self.results['actions'].append('Built image {image_name} from {path}'.format(image_name=self.image_name, path=self.path))
+ if not self.module.check_mode:
+ image = self.results['image'] = self.build_image()
+ else:
+ # Pull the image
+ self.results['actions'].append('Pulled image {image_name}'.format(image_name=self.image_name))
+ if not self.module.check_mode:
+ image = self.results['image'] = self.pull_image()
+
+ if not image:
+ image = self.find_image()
+ digest_after = image[0].get('Digest', image[0].get('digest'))
+ self.results['changed'] = digest_before != digest_after
+
+ if self.push:
+ # Push the image
+ if '/' in self.image_name:
+ push_format_string = 'Pushed image {image_name}'
+ else:
+ push_format_string = 'Pushed image {image_name} to {dest}'
+ self.results['actions'].append(push_format_string.format(image_name=self.image_name, dest=self.push_args['dest']))
+ self.results['changed'] = True
+ if not self.module.check_mode:
+ self.results['image'] = self.push_image()
+
+ def absent(self):
+ image = self.find_image()
+
+ if image:
+ self.results['actions'].append('Removed image {name}'.format(name=self.name))
+ self.results['changed'] = True
+ self.results['image']['state'] = 'Deleted'
+ if not self.module.check_mode:
+ self.remove_image()
+
+ def find_image(self, image_name=None):
+ if image_name is None:
+ image_name = self.image_name
+ args = ['image', 'ls', image_name, '--format', 'json']
+ rc, images, err = self._run(args, ignore_errors=True)
+ if len(images) > 0:
+ return json.loads(images)
+ else:
+ return None
+
+ def inspect_image(self, image_name=None):
+ if image_name is None:
+ image_name = self.image_name
+ args = ['inspect', image_name, '--format', 'json']
+ rc, image_data, err = self._run(args)
+ if len(image_data) > 0:
+ return json.loads(image_data)
+ else:
+ return None
+
+ def pull_image(self, image_name=None):
+ if image_name is None:
+ image_name = self.image_name
+
+ args = ['pull', image_name, '-q']
+
+ if self.auth_file:
+ args.extend(['--authfile', self.auth_file])
+
+ if self.username and self.password:
+ cred_string = '{user}:{password}'.format(user=self.username, password=self.password)
+ args.extend(['--creds', cred_string])
+
+ if self.validate_certs is not None:
+ if self.validate_certs:
+ args.append('--tls-verify')
+ else:
+ args.append('--tls-verify=false')
+
+ if self.ca_cert_dir:
+ args.extend(['--cert-dir', self.ca_cert_dir])
+
+ rc, out, err = self._run(args, ignore_errors=True)
+ if rc != 0:
+ self.module.fail_json(msg='Failed to pull image {image_name}'.format(image_name=image_name))
+ return self.inspect_image(out.strip())
+
+ def build_image(self):
+ args = ['build', '-q']
+ args.extend(['-t', self.image_name])
+
+ if self.validate_certs is not None:
+ if self.validate_certs:
+ args.append('--tls-verify')
+ else:
+ args.append('--tls-verify=false')
+
+ annotation = self.build.get('annotation')
+ if annotation:
+ for k, v in annotation.items():
+ args.extend(['--annotation', '{k}={v}'.format(k=k, v=v)])
+
+ if self.ca_cert_dir:
+ args.extend(['--cert-dir', self.ca_cert_dir])
+
+ if self.build.get('force_rm'):
+ args.append('--force-rm')
+
+ image_format = self.build.get('format')
+ if image_format:
+ args.extend(['--format', image_format])
+
+ if not self.build.get('cache'):
+ args.append('--no-cache')
+
+ if self.build.get('rm'):
+ args.append('--rm')
+
+ volume = self.build.get('volume')
+ if volume:
+ for v in volume:
+ args.extend(['--volume', v])
+
+ if self.auth_file:
+ args.extend(['--authfile', self.auth_file])
+
+ if self.username and self.password:
+ cred_string = '{user}:{password}'.format(user=self.username, password=self.password)
+ args.extend(['--creds', cred_string])
+
+ extra_args = self.build.get('extra_args')
+ if extra_args:
+ args.extend([arg for arg in shlex.split(extra_args)])
+
+ args.append(self.path)
+
+ rc, out, err = self._run(args, ignore_errors=True)
+ if rc != 0:
+ self.module.fail_json(msg="Failed to build image {image}: {out} {err}".format(image=self.image_name, out=out, err=err))
+
+ last_id = self._get_id_from_output(out, startswith='-->')
+ return self.inspect_image(last_id)
+
+ def push_image(self):
+ args = ['push']
+
+ if self.validate_certs is not None:
+ if self.validate_certs:
+ args.append('--tls-verify')
+ else:
+ args.append('--tls-verify=false')
+
+ if self.ca_cert_dir:
+ args.extend(['--cert-dir', self.ca_cert_dir])
+
+ if self.username and self.password:
+ cred_string = '{user}:{password}'.format(user=self.username, password=self.password)
+ args.extend(['--creds', cred_string])
+
+ if self.auth_file:
+ args.extend(['--authfile', self.auth_file])
+
+ if self.push_args.get('compress'):
+ args.append('--compress')
+
+ push_format = self.push_args.get('format')
+ if push_format:
+ args.extend(['--format', push_format])
+
+ if self.push_args.get('remove_signatures'):
+ args.append('--remove-signatures')
+
+ sign_by_key = self.push_args.get('sign_by')
+ if sign_by_key:
+ args.extend(['--sign-by', sign_by_key])
+
+ args.append(self.image_name)
+
+ # Build the destination argument
+ dest = self.push_args.get('dest')
+ dest_format_string = '{dest}/{image_name}'
+ regexp = re.compile(r'/{name}(:{tag})?'.format(name=self.name, tag=self.tag))
+ if not dest:
+ if '/' not in self.name:
+ self.module.fail_json(msg="'push_args['dest']' is required when pushing images that do not have the remote registry in the image name")
+
+ # If the push destination contains the image name and/or the tag
+ # remove it and warn since it's not needed.
+ elif regexp.search(dest):
+ dest = regexp.sub('', dest)
+ self.module.warn("Image name and tag are automatically added to push_args['dest']. Destination changed to {dest}".format(dest=dest))
+
+ if dest and dest.endswith('/'):
+ dest = dest[:-1]
+
+ transport = self.push_args.get('transport')
+ if transport:
+ if not dest:
+ self.module.fail_json("'push_args['transport'] requires 'push_args['dest'] but it was not provided.")
+ if transport == 'docker':
+ dest_format_string = '{transport}://{dest}'
+ elif transport == 'ostree':
+ dest_format_string = '{transport}:{name}@{dest}'
+ else:
+ dest_format_string = '{transport}:{dest}'
+
+ dest_string = dest_format_string.format(transport=transport, name=self.name, dest=dest, image_name=self.image_name,)
+
+ # Only append the destination argument if the image name is not a URL
+ if '/' not in self.name:
+ args.append(dest_string)
+
+ rc, out, err = self._run(args, ignore_errors=True)
+ if rc != 0:
+ self.module.fail_json(msg="Failed to push image {image_name}: {err}".format(image_name=self.image_name, err=err))
+ last_id = self._get_id_from_output(
+ out + err, contains=':', split_on=':')
+
+ return self.inspect_image(last_id)
+
+ def remove_image(self, image_name=None):
+ if image_name is None:
+ image_name = self.image_name
+
+ args = ['rmi', image_name]
+ if self.force:
+ args.append('--force')
+ rc, out, err = self._run(args, ignore_errors=True)
+ if rc != 0:
+ self.module.fail_json(msg='Failed to remove image {image_name}. {err}'.format(image_name=image_name, err=err))
+ return out
+
+
+def parse_repository_tag(repo_name):
+ parts = repo_name.rsplit('@', 1)
+ if len(parts) == 2:
+ return tuple(parts)
+ parts = repo_name.rsplit(':', 1)
+ if len(parts) == 2 and '/' not in parts[1]:
+ return tuple(parts)
+ return repo_name, None
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(type='str', required=True),
+ tag=dict(type='str', default='latest'),
+ pull=dict(type='bool', default=True),
+ push=dict(type='bool', default=False),
+ path=dict(type='str'),
+ force=dict(type='bool', default=False),
+ state=dict(type='str', default='present', choices=['absent', 'present', 'build']),
+ validate_certs=dict(type='bool', default=True, aliases=['tlsverify', 'tls_verify']),
+ executable=dict(type='str', default='podman'),
+ auth_file=dict(type='path', aliases=['authfile']),
+ username=dict(type='str'),
+ password=dict(type='str', no_log=True),
+ ca_cert_dir=dict(type='path'),
+ build=dict(
+ type='dict',
+ aliases=['build_args', 'buildargs'],
+ default={},
+ options=dict(
+ annotation=dict(type='dict'),
+ force_rm=dict(type='bool', default=False),
+ format=dict(
+ type='str',
+ choices=['oci', 'docker'],
+ default='oci'
+ ),
+ cache=dict(type='bool', default=True),
+ rm=dict(type='bool', default=True),
+ volume=dict(type='list', elements='str'),
+ extra_args=dict(type='str'),
+ ),
+ ),
+ push_args=dict(
+ type='dict',
+ default={},
+ options=dict(
+ compress=dict(type='bool'),
+ format=dict(type='str', choices=['oci', 'v2s1', 'v2s2']),
+ remove_signatures=dict(type='bool'),
+ sign_by=dict(type='str'),
+ dest=dict(type='str', aliases=['destination'],),
+ transport=dict(
+ type='str',
+ choices=[
+ 'dir',
+ 'docker-archive',
+ 'docker-daemon',
+ 'oci-archive',
+ 'ostree',
+ ]
+ ),
+ ),
+ ),
+ ),
+ supports_check_mode=True,
+ required_together=(
+ ['username', 'password'],
+ ),
+ mutually_exclusive=(
+ ['authfile', 'username'],
+ ['authfile', 'password'],
+ ),
+ )
+
+ results = dict(
+ changed=False,
+ actions=[],
+ image={},
+ )
+
+ PodmanImageManager(module, results)
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image_info.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image_info.py
new file mode 100644
index 00000000..4712c56a
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_image_info.py
@@ -0,0 +1,234 @@
+#!/usr/bin/python
+# Copyright (c) 2019 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_image_info
+author:
+ - Sam Doran (@samdoran)
+short_description: Gather info about images using podman
+notes:
+ - Podman may required elevated privileges in order to run properly.
+description:
+ - Gather info about images using C(podman)
+options:
+ 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
+ name:
+ description:
+ - List of tags or UID to gather info about. If no name is given return info about all images.
+ type: list
+ elements: str
+
+'''
+
+EXAMPLES = r"""
+- name: Gather info for all images
+ containers.podman.podman_image_info:
+
+- name: Gather info on a specific image
+ containers.podman.podman_image_info:
+ name: nginx
+
+- name: Gather info on several images
+ containers.podman.podman_image_info:
+ name:
+ - redis
+ - quay.io/bitnami/wildfly
+"""
+
+RETURN = r"""
+images:
+ description: info from all or specified images
+ returned: always
+ type: dict
+ sample: [
+ {
+ "Annotations": {},
+ "Architecture": "amd64",
+ "Author": "",
+ "Comment": "from Bitnami with love",
+ "ContainerConfig": {
+ "Cmd": [
+ "nami",
+ "start",
+ "--foreground",
+ "wildfly"
+ ],
+ "Entrypoint": [
+ "/app-entrypoint.sh"
+ ],
+ "Env": [
+ "PATH=/opt/bitnami/java/bin:/opt/bitnami/wildfly/bin:/opt/bitnami/nami/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "IMAGE_OS=debian-9",
+ "NAMI_VERSION=0.0.9-0",
+ "GPG_KEY_SERVERS_LIST=ha.pool.sks-keyservers.net \
+hkp://p80.pool.sks-keyservers.net:80 keyserver.ubuntu.com hkp://keyserver.ubuntu.com:80 pgp.mit.edu",
+ "TINI_VERSION=v0.13.2",
+ "TINI_GPG_KEY=595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7",
+ "GOSU_VERSION=1.10",
+ "GOSU_GPG_KEY=B42F6819007F00F88E364FD4036A9C25BF357DD4",
+ "BITNAMI_IMAGE_VERSION=14.0.1-debian-9-r12",
+ "BITNAMI_APP_NAME=wildfly",
+ "WILDFLY_JAVA_HOME=",
+ "WILDFLY_JAVA_OPTS=",
+ "WILDFLY_MANAGEMENT_HTTP_PORT_NUMBER=9990",
+ "WILDFLY_PASSWORD=bitnami",
+ "WILDFLY_PUBLIC_CONSOLE=true",
+ "WILDFLY_SERVER_AJP_PORT_NUMBER=8009",
+ "WILDFLY_SERVER_HTTP_PORT_NUMBER=8080",
+ "WILDFLY_SERVER_INTERFACE=0.0.0.0",
+ "WILDFLY_USERNAME=user",
+ "WILDFLY_WILDFLY_HOME=/home/wildfly",
+ "WILDFLY_WILDFLY_OPTS=-Dwildfly.as.deployment.ondemand=false"
+ ],
+ "ExposedPorts": {
+ "8080/tcp": {},
+ "9990/tcp": {}
+ },
+ "Labels": {
+ "maintainer": "Bitnami <containers@bitnami.com>"
+ }
+ },
+ "Created": "2018-09-25T04:07:45.934395523Z",
+ "Digest": "sha256:5c7d8e2dd66dcf4a152a4032a1d3c5a33458c67e1c1335edd8d18d738892356b",
+ "GraphDriver": {
+ "Data": {
+ "LowerDir": "/var/lib/containers/storage/overlay/a9dbf5616cc16919a8ac0dfc60aff87a72b5be52994c4649fcc91a089a12931\
+f/diff:/var/lib/containers/storage/overlay/67129bd46022122a7d8b7acb490092af6c7ce244ce4fbd7d9e2d2b7f5979e090/diff:/var/lib/containers/storage/overlay/7c51242c\
+4c5db5c74afda76d7fdbeab6965d8b21804bb3fc597dee09c770b0ca/diff:/var/lib/containers/storage/overlay/f97315dc58a9c002ba0cabccb9933d4b0d2113733d204188c88d72f75569b57b/diff:/var/lib/containers/storage/overlay/1dbde2dd497ddde2b467727125b900958a051a72561e58d29abe3d660dcaa9a7/diff:/var/lib/containers/storage/overlay/4aad9d80f30c3f0608f58173558b7554d84dee4dc4479672926eca29f75e6e33/diff:/var/lib/containers/storage/overlay/6751fc9b6868254870c062d75a511543fc8cfda2ce6262f4945f107449219632/diff:/var/lib/containers/storage/overlay/a27034d79081347421dd24d7e9e776c18271cd9a6e51053cb39af4d3d9c400e8/diff:/var/lib/containers/storage/overlay/537cf0045ed9cd7989f7944e7393019c81b16c1799a2198d8348cd182665397f/diff:/var/lib/containers/storage/overlay/27578615c5ae352af4e8449862d61aaf5c11b105a7d5905af55bd01b0c656d6e/diff:/var/lib/containers/storage/overlay/566542742840fe3034b3596f7cb9e62a6274c95a69f368f9e713746f8712c0b6/diff",
+ "MergedDir": "/var/lib/containers/storage/overlay/72bb96d6\
+c53ad57a0b1e44cab226a6251598accbead40b23fac89c19ad8c25ca/merged",
+ "UpperDir": "/var/lib/containers/storage/overlay/72bb96d6c53ad57a0b1e44cab226a6251598accbead40b23fac89c19ad8c25ca/diff",
+ "WorkDir": "/var/lib/containers/storage/overlay/72bb96d6c53ad57a0b1e44cab226a6251598accbead40b23fac89c19ad8c25ca/work"
+ },
+ "Name": "overlay"
+ },
+ "Id": "bcacbdf7a119c0fa934661ca8af839e625ce6540d9ceb6827cdd389f823d49e0",
+ "Labels": {
+ "maintainer": "Bitnami <containers@bitnami.com>"
+ },
+ "ManifestType": "application/vnd.docker.distribution.manifest.v1+prettyjws",
+ "Os": "linux",
+ "Parent": "",
+ "RepoDigests": [
+ "quay.io/bitnami/wildfly@sha256:5c7d8e2dd66dcf4a152a4032a1d3c5a33458c67e1c1335edd8d18d738892356b"
+ ],
+ "RepoTags": [
+ "quay.io/bitnami/wildfly:latest"
+ ],
+ "RootFS": {
+ "Layers": [
+ "sha256:75391df2c87e076b0c2f72d20c95c57dc8be7ee684cc07273416cce622b43367",
+ "sha256:7dd303f041039bfe8f0833092673ac35f93137d10e0fbc4302021ea65ad57731",
+ "sha256:720d9edf0cd2a9bb56b88b80be9070dbfaad359514c70094c65066963fed485d",
+ "sha256:6a567ecbf97725501a634fcb486271999aa4591b633b4ae9932a46b40f5aaf47",
+ "sha256:59e9a6db8f178f3da868614564faabb2820cdfb69be32e63a4405d6f7772f68c",
+ "sha256:310a82ccb092cd650215ab375da8943d235a263af9a029b8ac26a281446c04db",
+ "sha256:36cb91cf4513543a8f0953fed785747ea18b675bc2677f3839889cfca0aac79e"
+ ],
+ "Type": "layers"
+ },
+ "Size": 569919342,
+ "User": "",
+ "Version": "17.06.0-ce",
+ "VirtualSize": 569919342
+ }
+ ]
+"""
+
+import json
+
+from ansible.module_utils.basic import AnsibleModule
+
+
+def image_exists(module, executable, name):
+ command = [executable, 'image', 'exists', name]
+ rc, out, err = module.run_command(command)
+ if rc == 1:
+ return False
+ elif 'Command "exists" not found' in err:
+ # The 'exists' test is available in podman >= 0.12.1
+ command = [executable, 'image', 'ls', '-q', name]
+ rc2, out2, err2 = module.run_command(command)
+ if rc2 != 0:
+ return False
+ return True
+
+
+def filter_invalid_names(module, executable, name):
+ valid_names = []
+ names = name
+ if not isinstance(name, list):
+ names = [name]
+
+ for name in names:
+ if image_exists(module, executable, name):
+ valid_names.append(name)
+
+ return valid_names
+
+
+def get_image_info(module, executable, name):
+ names = name
+ if not isinstance(name, list):
+ names = [name]
+
+ if len(names) > 0:
+ command = [executable, 'image', 'inspect']
+ command.extend(names)
+ rc, out, err = module.run_command(command)
+
+ if rc != 0:
+ module.fail_json(msg="Unable to gather info for '{0}': {1}".format(', '.join(names), err))
+ return out
+
+ else:
+ return json.dumps([])
+
+
+def get_all_image_info(module, executable):
+ command = [executable, 'image', 'ls', '-q']
+ rc, out, err = module.run_command(command)
+ name = out.strip().split('\n')
+ out = get_image_info(module, executable, name)
+
+ return out
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ executable=dict(type='str', default='podman'),
+ name=dict(type='list', elements='str')
+ ),
+ supports_check_mode=True,
+ )
+
+ executable = module.params['executable']
+ name = module.params.get('name')
+ executable = module.get_bin_path(executable, required=True)
+
+ if name:
+ valid_names = filter_invalid_names(module, executable, name)
+ results = json.loads(get_image_info(module, executable, valid_names))
+ else:
+ results = json.loads(get_all_image_info(module, executable))
+
+ results = dict(
+ changed=False,
+ images=results
+ )
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_login_info.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_login_info.py
new file mode 100644
index 00000000..0ff72e43
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_login_info.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+# 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_login_info
+author:
+ - "Clemens Lange (@clelange)"
+version_added: '1.0.0'
+short_description: Return the logged-in user if any for a given registry
+notes: []
+description:
+ - Return the logged-in user if any for a given registry.
+requirements:
+ - "Podman installed on host"
+options:
+ registry:
+ description:
+ - Registry server.
+ type: str
+ required: true
+ authfile:
+ description:
+ - Path of the authentication file. Default is
+ ``${XDG_RUNTIME_DIR}/containers/auth.json``
+ (Not available for remote commands) You can also override the default
+ path of the authentication file by setting the ``REGISTRY_AUTH_FILE``
+ environment variable. ``export REGISTRY_AUTH_FILE=path``
+ type: path
+ 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: Return the logged-in user for docker hub registry
+ containers.podman.podman_login_info:
+ registry: docker.io
+
+- name: Return the logged-in user for quay.io registry
+ containers.podman.podman_login_info:
+ registry: quay.io
+"""
+
+RETURN = r"""
+login:
+ description: Logged in user for a registry
+ returned: always
+ type: dict
+ sample: {
+ "logged_in": true,
+ "registry": "docker.io",
+ "username": "clelange",
+ }
+"""
+
+import json
+from ansible.module_utils.basic import AnsibleModule
+
+
+def get_login_info(module, executable, authfile, registry):
+ command = [executable, 'login', '--get-login']
+ result = dict(
+ registry=registry,
+ username='',
+ logged_in=False,
+ )
+ if authfile:
+ command.extend(['--authfile', authfile])
+ if registry:
+ command.append(registry)
+ rc, out, err = module.run_command(command)
+ if rc != 0:
+ if 'Error: not logged into' in err:
+ # The error message is e.g. 'Error: not logged into docker.io'
+ # Therefore get last word to extract registry name
+ result["registry"] = err.split()[-1]
+ err = ''
+ return result
+ module.fail_json(msg="Unable to gather info for %s: %s" % (registry, err))
+ result["username"] = out.strip()
+ result["logged_in"] = True
+ return result
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ executable=dict(type='str', default='podman'),
+ authfile=dict(type='path'),
+ registry=dict(type='str', required=True)
+ ),
+ supports_check_mode=True,
+ )
+
+ registry = module.params['registry']
+ authfile = module.params['authfile']
+ executable = module.get_bin_path(module.params['executable'], required=True)
+
+ inspect_results = get_login_info(module, executable, authfile, registry)
+
+ results = {
+ "changed": False,
+ "login": inspect_results,
+ }
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_logout.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_logout.py
new file mode 100644
index 00000000..35627e8e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_logout.py
@@ -0,0 +1,154 @@
+#!/usr/bin/python
+# 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_logout
+author:
+ - "Clemens Lange (@clelange)"
+short_description: Log out of a container registry using podman
+notes: []
+description:
+ - Log out of a container registry server using the podman logout command
+ by deleting the cached credentials stored in the `auth.json` file.
+ If the registry is not specified, the first registry under
+ `[registries.search]` from `registries.conf `will be used. The path of
+ the authentication file can be overridden by the user by setting the
+ `authfile` flag. The default path used is
+ `${XDG_RUNTIME_DIR}/containers/auth.json`.
+ All the cached credentials can be removed by setting the `all` flag.
+ Warning - podman will use credentials in `${HOME}/.docker/config.json`
+ to authenticate in case they are not found in the default `authfile`.
+ However, the logout command will only removed credentials in the
+ `authfile` specified.
+requirements:
+ - "Podman installed on host"
+options:
+ registry:
+ description:
+ - Registry server. If the registry is not specified,
+ the first registry under `[registries.search]` from
+ `registries.conf` will be used.
+ type: str
+ authfile:
+ description:
+ - Path of the authentication file. Default is
+ ``${XDG_RUNTIME_DIR}/containers/auth.json``
+ You can also override the default path of the authentication
+ file by setting the ``REGISTRY_AUTH_FILE`` environment
+ variable. ``export REGISTRY_AUTH_FILE=path``
+ type: path
+ all:
+ description:
+ - Remove the cached credentials for all registries in the auth file.
+ type: bool
+ ignore_docker_credentials:
+ description:
+ - Credentials created using other tools such as `docker login` are not
+ removed unless the corresponding `authfile` is explicitly specified.
+ Since podman also uses existing credentials in these files by default
+ (for docker e.g. `${HOME}/.docker/config.json`), module execution will
+ fail if a docker login exists for the registry specified in any
+ `authfile` is used by podman. This can be ignored by setting
+ `ignore_docker_credentials` to `yes` - the credentials will be kept and
+ `changed` will be false.
+ This option cannot be used together with `all` since in this case
+ podman will not check for existing `authfiles` created by other tools.
+ type: bool
+ 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: Log out of default registry
+ podman_logout:
+
+- name: Log out of quay.io
+ podman_logout:
+ registry: quay.io
+
+- name: Log out of all registries in auth file
+ podman_logout:
+ all: yes
+
+- name: Log out of all registries in specified auth file
+ podman_logout:
+ authfile: $HOME/.docker/config.json
+ all: yes
+"""
+# noqa: F402
+
+import json # noqa: F402
+from ansible.module_utils.basic import AnsibleModule
+
+
+def logout(module, executable, registry, authfile, all_registries, ignore_docker_credentials):
+ command = [executable, 'logout']
+ changed = False
+ if authfile:
+ command.extend(['--authfile', authfile])
+ if registry:
+ command.append(registry)
+ if all_registries:
+ command.append("--all")
+ rc, out, err = module.run_command(command)
+ if rc != 0:
+ if 'Error: Not logged into' not in err:
+ module.fail_json(msg="Unable to gather info for %s: %s" % (registry, err))
+ else:
+ # If the command is successful, we managed to log out
+ # Mind: This also applied if --all flag is used, while in this case
+ # there is no check whether one has been logged into any registry
+ changed = True
+ if 'Existing credentials were established via' in out:
+ # The command will return successfully but not log out the user if the
+ # credentials were initially created using docker. Catch this behaviour:
+ if not ignore_docker_credentials:
+ module.fail_json(msg="Unable to log out of %s: %s" % (registry, out))
+ else:
+ changed = False
+ return changed, out, err
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ executable=dict(type='str', default='podman'),
+ registry=dict(type='str'),
+ authfile=dict(type='path'),
+ all=dict(type='bool'),
+ ignore_docker_credentials=dict(type='bool'),
+ ),
+ supports_check_mode=True,
+ mutually_exclusive=(
+ ['registry', 'all'],
+ ['ignore_docker_credentials', 'all'],
+ ),
+ )
+
+ registry = module.params['registry']
+ authfile = module.params['authfile']
+ all_registries = module.params['all']
+ ignore_docker_credentials = module.params['ignore_docker_credentials']
+ executable = module.get_bin_path(module.params['executable'], required=True)
+
+ changed, out, err = logout(module, executable, registry, authfile,
+ all_registries, ignore_docker_credentials)
+
+ results = {
+ "changed": changed,
+ "stdout": out,
+ "stderr": err,
+ }
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network.py
new file mode 100644
index 00000000..590b4690
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network.py
@@ -0,0 +1,614 @@
+#!/usr/bin/python
+# Copyright (c) 2020 Red Hat
+# 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_network
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+version_added: '1.0.0'
+short_description: Manage podman networks
+notes: []
+description:
+ - Manage podman networks with podman network command.
+requirements:
+ - podman
+options:
+ name:
+ description:
+ - Name of the network
+ type: str
+ required: True
+ 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
+ disable_dns:
+ description:
+ - disable dns plugin (default "false")
+ type: bool
+ driver:
+ description:
+ - Driver to manage the network (default "bridge")
+ type: str
+ gateway:
+ description:
+ - IPv4 or IPv6 gateway for the subnet
+ type: str
+ internal:
+ description:
+ - Restrict external access from this network (default "false")
+ type: bool
+ ip_range:
+ description:
+ - Allocate container IP from range
+ type: str
+ ipv6:
+ description:
+ - Enable IPv6 (Dual Stack) networking. You must pass a IPv6 subnet.
+ The subnet option must be used with the ipv6 option.
+ type: bool
+ subnet:
+ description:
+ - Subnet in CIDR format
+ type: str
+ macvlan:
+ description:
+ - Create a Macvlan connection based on this device
+ type: str
+ opt:
+ description:
+ - Add network options. Currently 'vlan' and 'mtu' are supported.
+ type: dict
+ suboptions:
+ mtu:
+ description:
+ - MTU size for bridge network interface.
+ type: int
+ required: false
+ vlan:
+ description:
+ - VLAN tag for bridge which enables vlan_filtering.
+ type: int
+ required: false
+ debug:
+ description:
+ - Return additional information which can be helpful for investigations.
+ type: bool
+ default: False
+ state:
+ description:
+ - State of network, default 'present'
+ type: str
+ default: present
+ choices:
+ - present
+ - absent
+ recreate:
+ description:
+ - Recreate network even if exists.
+ type: bool
+ default: false
+"""
+
+EXAMPLES = r"""
+- name: Create a podman network
+ containers.podman.podman_network:
+ name: podman_network
+ become: true
+
+- name: Create internal podman network
+ containers.podman.podman_network:
+ name: podman_internal
+ internal: true
+ ip_range: 192.168.22.128/25
+ subnet: 192.168.22.0/24
+ gateway: 192.168.22.1
+ become: true
+"""
+
+RETURN = r"""
+network:
+ description: Facts from created or updated networks
+ returned: always
+ type: list
+ sample: [
+ {
+ "cniVersion": "0.4.0",
+ "name": "podman",
+ "plugins": [
+ {
+ "bridge": "cni-podman0",
+ "ipMasq": true,
+ "ipam": {
+ "ranges": [
+ [
+ {
+ "gateway": "10.88.0.1",
+ "subnet": "10.88.0.0/16"
+ }
+ ]
+ ],
+ "routes": [
+ {
+ "dst": "0.0.0.0/0"
+ }
+ ],
+ "type": "host-local"
+ },
+ "isGateway": true,
+ "type": "bridge"
+ },
+ {
+ "capabilities": {
+ "portMappings": true
+ },
+ "type": "portmap"
+ },
+ {
+ "backend": "iptables",
+ "type": "firewall"
+ }
+ ]
+ }
+ ]
+"""
+
+import json # noqa: F402
+from distutils.version import LooseVersion # noqa: F402
+import os # noqa: F402
+
+from ansible.module_utils.basic import AnsibleModule # noqa: F402
+from ansible.module_utils._text import to_bytes, to_native # noqa: F402
+
+from ansible_collections.containers.podman.plugins.module_utils.podman.common import lower_keys
+
+
+class PodmanNetworkModuleParams:
+ """Creates list of arguments for podman CLI command.
+
+ Arguments:
+ action {str} -- action type from 'create', 'delete'
+ params {dict} -- dictionary of module parameters
+
+ """
+
+ def __init__(self, action, params, podman_version, module):
+ self.params = params
+ self.action = action
+ self.podman_version = podman_version
+ self.module = module
+
+ def construct_command_from_params(self):
+ """Create a podman command from given module parameters.
+
+ Returns:
+ list -- list of byte strings for Popen command
+ """
+ if self.action in ['delete']:
+ return self._simple_action()
+ if self.action in ['create']:
+ return self._create_action()
+
+ def _simple_action(self):
+ if self.action == 'delete':
+ cmd = ['rm', '-f', self.params['name']]
+ return [to_bytes(i, errors='surrogate_or_strict') for i in cmd]
+
+ def _create_action(self):
+ cmd = [self.action, self.params['name']]
+ all_param_methods = [func for func in dir(self)
+ if callable(getattr(self, func))
+ and func.startswith("addparam")]
+ params_set = (i for i in self.params if self.params[i] is not None)
+ for param in params_set:
+ func_name = "_".join(["addparam", param])
+ if func_name in all_param_methods:
+ cmd = getattr(self, func_name)(cmd)
+ return [to_bytes(i, errors='surrogate_or_strict') for i in cmd]
+
+ def check_version(self, param, minv=None, maxv=None):
+ if minv and LooseVersion(minv) > LooseVersion(
+ self.podman_version):
+ self.module.fail_json(msg="Parameter %s is supported from podman "
+ "version %s only! Current version is %s" % (
+ param, minv, self.podman_version))
+ if maxv and LooseVersion(maxv) < LooseVersion(
+ self.podman_version):
+ self.module.fail_json(msg="Parameter %s is supported till podman "
+ "version %s only! Current version is %s" % (
+ param, minv, self.podman_version))
+
+ def addparam_gateway(self, c):
+ return c + ['--gateway', self.params['gateway']]
+
+ def addparam_driver(self, c):
+ return c + ['--driver', self.params['driver']]
+
+ def addparam_subnet(self, c):
+ return c + ['--subnet', self.params['subnet']]
+
+ def addparam_ip_range(self, c):
+ return c + ['--ip-range', self.params['ip_range']]
+
+ def addparam_ipv6(self, c):
+ return c + ['--ipv6']
+
+ def addparam_macvlan(self, c):
+ return c + ['--macvlan', self.params['macvlan']]
+
+ def addparam_internal(self, c):
+ return c + ['--internal=%s' % self.params['internal']]
+
+ def addparam_opt(self, c):
+ for opt in self.params['opt'].items():
+ c += ['--opt',
+ b"=".join([to_bytes(k, errors='surrogate_or_strict')
+ for k in opt])]
+ return c
+
+ def addparam_disable_dns(self, c):
+ return c + ['--disable-dns=%s' % self.params['disable_dns']]
+
+
+class PodmanNetworkDefaults:
+ def __init__(self, module, podman_version):
+ self.module = module
+ self.version = podman_version
+ self.defaults = {
+ 'driver': 'bridge',
+ 'disable_dns': False,
+ 'internal': False,
+ }
+
+ def default_dict(self):
+ # make here any changes to self.defaults related to podman version
+ return self.defaults
+
+
+class PodmanNetworkDiff:
+ def __init__(self, module, info, podman_version):
+ self.module = module
+ self.version = podman_version
+ self.default_dict = None
+ self.info = lower_keys(info)
+ self.params = self.defaultize()
+ self.diff = {'before': {}, 'after': {}}
+ self.non_idempotent = {}
+
+ def defaultize(self):
+ params_with_defaults = {}
+ self.default_dict = PodmanNetworkDefaults(
+ self.module, self.version).default_dict()
+ for p in self.module.params:
+ if self.module.params[p] is None and p in self.default_dict:
+ params_with_defaults[p] = self.default_dict[p]
+ else:
+ params_with_defaults[p] = self.module.params[p]
+ return params_with_defaults
+
+ def _diff_update_and_compare(self, param_name, before, after):
+ if before != after:
+ self.diff['before'].update({param_name: before})
+ self.diff['after'].update({param_name: after})
+ return True
+ return False
+
+ def diffparam_disable_dns(self):
+ dns_installed = False
+ for f in [
+ '/usr/libexec/cni/dnsname',
+ '/usr/lib/cni/dnsname',
+ '/opt/cni/bin/dnsname',
+ '/opt/bridge/bin/dnsname'
+ ]:
+ if os.path.exists(f):
+ dns_installed = True
+ before = not bool(
+ [k for k in self.info['plugins'] if 'domainname' in k])
+ after = self.params['disable_dns']
+ # If dnsname plugin is not installed, default is disable_dns=True
+ if not dns_installed and self.module.params['disable_dns'] is None:
+ after = True
+ return self._diff_update_and_compare('disable_dns', before, after)
+
+ def diffparam_driver(self):
+ # Currently only bridge is supported
+ before = after = 'bridge'
+ return self._diff_update_and_compare('driver', before, after)
+
+ def diffparam_gateway(self):
+ try:
+ before = self.info['plugins'][0]['ipam']['ranges'][0][0]['gateway']
+ except (IndexError, KeyError):
+ before = ''
+ after = before
+ if self.params['gateway'] is not None:
+ after = self.params['gateway']
+ return self._diff_update_and_compare('gateway', before, after)
+
+ def diffparam_internal(self):
+ try:
+ before = not self.info['plugins'][0]['isgateway']
+ except (IndexError, KeyError):
+ before = False
+ after = self.params['internal']
+ return self._diff_update_and_compare('internal', before, after)
+
+ def diffparam_ip_range(self):
+ # TODO(sshnaidm): implement IP to CIDR convert and vice versa
+ before = after = ''
+ return self._diff_update_and_compare('ip_range', before, after)
+
+ def diffparam_subnet(self):
+ try:
+ before = self.info['plugins'][0]['ipam']['ranges'][0][0]['subnet']
+ except (IndexError, KeyError):
+ before = ''
+ after = before
+ if self.params['subnet'] is not None:
+ after = self.params['subnet']
+ return self._diff_update_and_compare('subnet', before, after)
+
+ def diffparam_macvlan(self):
+ before = after = ''
+ return self._diff_update_and_compare('macvlan', before, after)
+
+ def diffparam_opt(self):
+ vlan_before = self.info['plugins'][0].get('vlan')
+ vlan_after = self.params['opt'].get('vlan') if self.params['opt'] else None
+ if vlan_before or vlan_after:
+ before, after = {'vlan': vlan_before}, {'vlan': vlan_after}
+ else:
+ before, after = {}, {}
+ mtu_before = self.info['plugins'][0].get('mtu')
+ mtu_after = self.params['opt'].get('mtu') if self.params['opt'] else None
+ if mtu_before or mtu_after:
+ before.update({'mtu': mtu_before})
+ after.update({'mtu': mtu_after})
+ return self._diff_update_and_compare('opt', before, after)
+
+ def is_different(self):
+ diff_func_list = [func for func in dir(self)
+ if callable(getattr(self, func)) and func.startswith(
+ "diffparam")]
+ fail_fast = not bool(self.module._diff)
+ different = False
+ for func_name in diff_func_list:
+ dff_func = getattr(self, func_name)
+ if dff_func():
+ if fail_fast:
+ return True
+ different = True
+ # Check non idempotent parameters
+ for p in self.non_idempotent:
+ if self.module.params[p] is not None and self.module.params[p] not in [{}, [], '']:
+ different = True
+ return different
+
+
+class PodmanNetwork:
+ """Perform network tasks.
+
+ Manages podman network, inspects it and checks its current state
+ """
+
+ def __init__(self, module, name):
+ """Initialize PodmanNetwork class.
+
+ Arguments:
+ module {obj} -- ansible module object
+ name {str} -- name of network
+ """
+
+ super(PodmanNetwork, self).__init__()
+ self.module = module
+ self.name = name
+ self.stdout, self.stderr = '', ''
+ self.info = self.get_info()
+ self.version = self._get_podman_version()
+ self.diff = {}
+ self.actions = []
+
+ @property
+ def exists(self):
+ """Check if network exists."""
+ return bool(self.info != {})
+
+ @property
+ def different(self):
+ """Check if network is different."""
+ diffcheck = PodmanNetworkDiff(
+ self.module,
+ self.info,
+ self.version)
+ is_different = diffcheck.is_different()
+ diffs = diffcheck.diff
+ if self.module._diff and is_different and diffs['before'] and diffs['after']:
+ self.diff['before'] = "\n".join(
+ ["%s - %s" % (k, v) for k, v in sorted(
+ diffs['before'].items())]) + "\n"
+ self.diff['after'] = "\n".join(
+ ["%s - %s" % (k, v) for k, v in sorted(
+ diffs['after'].items())]) + "\n"
+ return is_different
+
+ def get_info(self):
+ """Inspect network and gather info about it."""
+ # pylint: disable=unused-variable
+ rc, out, err = self.module.run_command(
+ [self.module.params['executable'], b'network', b'inspect', self.name])
+ return json.loads(out)[0] if rc == 0 else {}
+
+ def _get_podman_version(self):
+ # pylint: disable=unused-variable
+ rc, out, err = self.module.run_command(
+ [self.module.params['executable'], b'--version'])
+ if rc != 0 or not out or "version" not in out:
+ self.module.fail_json(msg="%s run failed!" %
+ self.module.params['executable'])
+ return out.split("version")[1].strip()
+
+ def _perform_action(self, action):
+ """Perform action with network.
+
+ Arguments:
+ action {str} -- action to perform - create, stop, delete
+ """
+ b_command = PodmanNetworkModuleParams(action,
+ self.module.params,
+ self.version,
+ self.module,
+ ).construct_command_from_params()
+ full_cmd = " ".join([self.module.params['executable'], 'network']
+ + [to_native(i) for i in b_command])
+ self.module.log("PODMAN-NETWORK-DEBUG: %s" % full_cmd)
+ self.actions.append(full_cmd)
+ if not self.module.check_mode:
+ rc, out, err = self.module.run_command(
+ [self.module.params['executable'], b'network'] + b_command,
+ expand_user_and_vars=False)
+ self.stdout = out
+ self.stderr = err
+ if rc != 0:
+ self.module.fail_json(
+ msg="Can't %s network %s" % (action, self.name),
+ stdout=out, stderr=err)
+
+ def delete(self):
+ """Delete the network."""
+ self._perform_action('delete')
+
+ def create(self):
+ """Create the network."""
+ self._perform_action('create')
+
+ def recreate(self):
+ """Recreate the network."""
+ self.delete()
+ self.create()
+
+
+class PodmanNetworkManager:
+ """Module manager class.
+
+ Defines according to parameters what actions should be applied to network
+ """
+
+ def __init__(self, module):
+ """Initialize PodmanManager class.
+
+ Arguments:
+ module {obj} -- ansible module object
+ """
+
+ super(PodmanNetworkManager, self).__init__()
+
+ self.module = module
+ self.results = {
+ 'changed': False,
+ 'actions': [],
+ 'network': {},
+ }
+ self.name = self.module.params['name']
+ self.executable = \
+ self.module.get_bin_path(self.module.params['executable'],
+ required=True)
+ self.state = self.module.params['state']
+ self.recreate = self.module.params['recreate']
+ self.network = PodmanNetwork(self.module, self.name)
+
+ def update_network_result(self, changed=True):
+ """Inspect the current network, update results with last info, exit.
+
+ Keyword Arguments:
+ changed {bool} -- whether any action was performed
+ (default: {True})
+ """
+ facts = self.network.get_info() if changed else self.network.info
+ out, err = self.network.stdout, self.network.stderr
+ self.results.update({'changed': changed, 'network': facts,
+ 'podman_actions': self.network.actions},
+ stdout=out, stderr=err)
+ if self.network.diff:
+ self.results.update({'diff': self.network.diff})
+ if self.module.params['debug']:
+ self.results.update({'podman_version': self.network.version})
+ self.module.exit_json(**self.results)
+
+ def execute(self):
+ """Execute the desired action according to map of actions & states."""
+ states_map = {
+ 'present': self.make_present,
+ 'absent': self.make_absent,
+ }
+ process_action = states_map[self.state]
+ process_action()
+ self.module.fail_json(msg="Unexpected logic error happened, "
+ "please contact maintainers ASAP!")
+
+ def make_present(self):
+ """Run actions if desired state is 'started'."""
+ if not self.network.exists:
+ self.network.create()
+ self.results['actions'].append('created %s' % self.network.name)
+ self.update_network_result()
+ elif self.recreate or self.network.different:
+ self.network.recreate()
+ self.results['actions'].append('recreated %s' %
+ self.network.name)
+ self.update_network_result()
+ else:
+ self.update_network_result(changed=False)
+
+ def make_absent(self):
+ """Run actions if desired state is 'absent'."""
+ if not self.network.exists:
+ self.results.update({'changed': False})
+ elif self.network.exists:
+ self.network.delete()
+ self.results['actions'].append('deleted %s' % self.network.name)
+ self.results.update({'changed': True})
+ self.results.update({'network': {},
+ 'podman_actions': self.network.actions})
+ self.module.exit_json(**self.results)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ state=dict(type='str', default="present",
+ choices=['present', 'absent']),
+ name=dict(type='str', required=True),
+ disable_dns=dict(type='bool', required=False),
+ driver=dict(type='str', required=False),
+ gateway=dict(type='str', required=False),
+ internal=dict(type='bool', required=False),
+ ip_range=dict(type='str', required=False),
+ ipv6=dict(type='bool', required=False),
+ subnet=dict(type='str', required=False),
+ macvlan=dict(type='str', required=False),
+ opt=dict(type='dict', required=False,
+ options=dict(
+ mtu=dict(type='int', required=False),
+ vlan=dict(type='int', required=False))),
+ executable=dict(type='str', required=False, default='podman'),
+ debug=dict(type='bool', default=False),
+ recreate=dict(type='bool', default=False),
+ ),
+ required_by=dict( # for IP range and GW to set 'subnet' is required
+ ip_range=('subnet'),
+ gateway=('subnet'),
+ ))
+
+ PodmanNetworkManager(module).execute()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network_info.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network_info.py
new file mode 100644
index 00000000..a9e18cd4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_network_info.py
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+# Copyright (c) 2020 Red Hat
+# 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_network_info
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+version_added: '1.0.0'
+short_description: Gather info about podman networks
+notes: []
+description:
+ - Gather info about podman networks with podman inspect command.
+requirements:
+ - "Podman installed on host"
+options:
+ name:
+ description:
+ - Name of the network
+ 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 present networks
+ containers.podman.podman_network_info:
+
+- name: Gather info about specific network
+ containers.podman.podman_network_info:
+ name: podman
+"""
+
+RETURN = r"""
+networks:
+ description: Facts from all or specified networks
+ returned: always
+ type: list
+ sample: [
+ {
+ "cniVersion": "0.4.0",
+ "name": "podman",
+ "plugins": [
+ {
+ "bridge": "cni-podman0",
+ "ipMasq": true,
+ "ipam": {
+ "ranges": [
+ [
+ {
+ "gateway": "10.88.0.1",
+ "subnet": "10.88.0.0/16"
+ }
+ ]
+ ],
+ "routes": [
+ {
+ "dst": "0.0.0.0/0"
+ }
+ ],
+ "type": "host-local"
+ },
+ "isGateway": true,
+ "type": "bridge"
+ },
+ {
+ "capabilities": {
+ "portMappings": true
+ },
+ "type": "portmap"
+ },
+ {
+ "backend": "iptables",
+ "type": "firewall"
+ }
+ ]
+ }
+ ]
+"""
+
+import json
+from ansible.module_utils.basic import AnsibleModule
+
+
+def get_network_info(module, executable, name):
+ command = [executable, 'network', 'inspect']
+ if not name:
+ all_names = [executable, 'network', 'ls', '-q']
+ rc, out, err = module.run_command(all_names)
+ if rc != 0:
+ module.fail_json(msg="Unable to get list of networks: %s" % err)
+ name = out.split()
+ if not name:
+ return [], out, err
+ command += name
+ else:
+ command.append(name)
+ rc, out, err = module.run_command(command)
+ if rc != 0 or 'unable to find network configuration' in err:
+ module.fail_json(msg="Unable to gather info for %s: %s" % (name, err))
+ if not out or json.loads(out) is None:
+ return [], out, err
+ return json.loads(out), out, err
+
+
+def main():
+ 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_network_info(module, executable, name)
+
+ results = {
+ "changed": False,
+ "networks": inspect_results,
+ "stderr": err
+ }
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod.py
new file mode 100644
index 00000000..01dbc627
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod.py
@@ -0,0 +1,232 @@
+#!/usr/bin/python
+# Copyright (c) 2020 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 = '''
+---
+module: podman_pod
+short_description: Manage Podman pods
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+version_added: '1.0.0'
+description:
+ - Manage podman pods.
+options:
+ state:
+ description:
+ - This variable is set for state
+ type: str
+ default: created
+ choices:
+ - created
+ - killed
+ - restarted
+ - absent
+ - started
+ - stopped
+ - paused
+ - unpaused
+ recreate:
+ description:
+ - Use with present and started states to force the re-creation of an
+ existing pod.
+ type: bool
+ default: False
+ add_host:
+ description:
+ - Add a host to the /etc/hosts file shared between all containers in the pod.
+ type: list
+ elements: str
+ required: false
+ cgroup_parent:
+ description:
+ - Path to cgroups under which the cgroup for the pod will be created. If the path
+ is not absolute, he path is considered to be relative to the cgroups path of the
+ init process. Cgroups will be created if they do not already exist.
+ type: str
+ required: false
+ dns:
+ description:
+ - Set custom DNS servers in the /etc/resolv.conf file that will be shared between
+ all containers in the pod. A special option, "none" is allowed which disables
+ creation of /etc/resolv.conf for the pod.
+ type: list
+ elements: str
+ required: false
+ dns_opt:
+ description:
+ - Set custom DNS options in the /etc/resolv.conf file that will be shared between
+ all containers in the pod.
+ type: list
+ elements: str
+ required: false
+ dns_search:
+ description:
+ - Set custom DNS search domains in the /etc/resolv.conf file that will be shared
+ between all containers in the pod.
+ type: list
+ elements: str
+ required: false
+ hostname:
+ description:
+ - Set a hostname to the pod
+ type: str
+ required: false
+ infra:
+ description:
+ - Create an infra container and associate it with the pod. An infra container is
+ a lightweight container used to coordinate the shared kernel namespace of a pod.
+ Default is true.
+ type: bool
+ required: false
+ infra_conmon_pidfile:
+ description:
+ - Write the pid of the infra container's conmon process to a file. As conmon runs
+ in a separate process than Podman, this is necessary when using systemd to manage
+ Podman containers and pods.
+ type: str
+ required: false
+ infra_command:
+ description:
+ - The command that will be run to start the infra container. Default is "/pause".
+ type: str
+ required: false
+ infra_image:
+ description:
+ - The image that will be created for the infra container. Default is "k8s.gcr.io/pause:3.1".
+ type: str
+ required: false
+ ip:
+ description:
+ - Set a static IP for the pod's shared network.
+ type: str
+ required: false
+ label:
+ description:
+ - Add metadata to a pod, pass dictionary of label keys and values.
+ type: dict
+ required: false
+ label_file:
+ description:
+ - Read in a line delimited file of labels.
+ type: str
+ required: false
+ mac_address:
+ description:
+ - Set a static MAC address for the pod's shared network.
+ type: str
+ required: false
+ name:
+ description:
+ - Assign a name to the pod.
+ type: str
+ required: true
+ network:
+ description:
+ - Set network mode for the pod. Supported values are bridge (the default), host
+ (do not create a network namespace, all containers in the pod will use the host's
+ network), or a comma-separated list of the names of CNI networks the pod should
+ join.
+ type: str
+ required: false
+ no_hosts:
+ description:
+ - Disable creation of /etc/hosts for the pod.
+ type: bool
+ required: false
+ pod_id_file:
+ description:
+ - Write the pod ID to the file.
+ type: str
+ required: false
+ publish:
+ description:
+ - Publish a port or range of ports from the pod to the host.
+ type: list
+ elements: str
+ required: false
+ aliases:
+ - ports
+ share:
+ description:
+ - A comma delimited list of kernel namespaces to share. If none or "" is specified,
+ no namespaces will be shared. The namespaces to choose from are ipc, net, pid,
+ user, uts.
+ type: str
+ required: false
+ 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
+ debug:
+ description:
+ - Return additional information which can be helpful for investigations.
+ type: bool
+ default: False
+
+requirements:
+ - "podman"
+
+'''
+
+RETURN = '''
+pod:
+ description: Pod inspection results for the given pod
+ built.
+ returned: always
+ type: dict
+ sample:
+ Config:
+ cgroupParent: /libpod_parent
+ created: '2020-06-14T15:16:12.230818767+03:00'
+ hostname: newpod
+ id: a5a5c6cdf8c72272fc5c33f787e8d7501e2fa0c1e92b2b602860defdafeeec58
+ infraConfig:
+ infraPortBindings: null
+ makeInfraContainer: true
+ labels: {}
+ lockID: 515
+ name: newpod
+ sharesCgroup: true
+ sharesIpc: true
+ sharesNet: true
+ sharesUts: true
+ Containers:
+ - id: dc70a947c7ae15198ec38b3c817587584085dee3919cbeb9969e3ab77ba10fd2
+ state: configured
+ State:
+ cgroupPath: /libpod_parent/a5a5c6cdf8c72272fc5c33f787e8d7501e2fa0c1e92b2b602860defdafeeec58
+ infraContainerID: dc70a947c7ae15198ec38b3c817587584085dee3919cbeb9969e3ab77ba10fd2
+ status: Created
+
+'''
+
+EXAMPLES = '''
+# What modules does for example
+- podman_pod:
+ name: pod1
+ state: started
+ ports:
+ - 4444:5555
+'''
+from ansible.module_utils.basic import AnsibleModule # noqa: F402
+from ..module_utils.podman.podman_pod_lib import PodmanPodManager # noqa: F402
+from ..module_utils.podman.podman_pod_lib import ARGUMENTS_SPEC_POD # noqa: F402
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=ARGUMENTS_SPEC_POD
+ )
+ results = PodmanPodManager(module, module.params).execute()
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod_info.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod_info.py
new file mode 100644
index 00000000..c02e503c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_pod_info.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python
+# Copyright (c) 2020 Red Hat
+# 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_pod_info
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+version_added: '1.0.0'
+short_description: Gather info about podman pods
+notes: []
+description:
+ - Gather info about podman pods with podman inspect command.
+requirements:
+ - "Podman installed on host"
+options:
+ name:
+ description:
+ - Name of the pod
+ 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 present pods
+ containers.podman.podman_pod_info:
+
+- name: Gather info about specific pods
+ containers.podman.podman_pod_info:
+ name: special_pod
+"""
+
+RETURN = r"""
+pods:
+ description: Facts from all or specified pods
+ returned: always
+ type: list
+ sample: [
+ {
+ "Config": {
+ "id": "d9cb6dbb0....",
+ "name": "pod1",
+ "hostname": "pod1host",
+ "labels": {
+ },
+ "cgroupParent": "/libpod_parent",
+ "sharesCgroup": true,
+ "sharesIpc": true,
+ "sharesNet": true,
+ "sharesUts": true,
+ "infraConfig": {
+ "makeInfraContainer": true,
+ "infraPortBindings": [
+ {
+ "hostPort": 7777,
+ "containerPort": 7111,
+ "protocol": "tcp",
+ "hostIP": ""
+ }
+ ]
+ },
+ "created": "2020-07-13T20:29:12.572282186+03:00",
+ "lockID": 682
+ },
+ "State": {
+ "cgroupPath": "/libpod_parent/d9cb6dbb0....",
+ "infraContainerID": "ad46737bf....",
+ "status": "Created"
+ },
+ "Containers": [
+ {
+ "id": "ad46737bf....",
+ "state": "configured"
+ }
+ ]
+ }
+ ]
+"""
+
+import json
+from ansible.module_utils.basic import AnsibleModule
+
+
+def get_pod_info(module, executable, name):
+ command = [executable, 'pod', 'inspect']
+ pods = [name]
+ result = []
+ errs = []
+ rcs = []
+ if not name:
+ all_names = [executable, 'pod', 'ls', '-q']
+ rc, out, err = module.run_command(all_names)
+ if rc != 0:
+ module.fail_json(msg="Unable to get list of pods: %s" % err)
+ name = out.split()
+ if not name:
+ return [], out, err
+ pods = name
+ for pod in pods:
+ rc, out, err = module.run_command(command + [pod])
+ errs.append(err.strip())
+ rcs += [rc]
+ if not out or json.loads(out) is None:
+ continue
+ result.append(json.loads(out))
+ return result, errs, rcs
+
+
+def main():
+ 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, errs, rcs = get_pod_info(module, executable, name)
+
+ if len(rcs) > 1 and 0 not in rcs:
+ module.fail_json(msg="Failed to inspect pods", stderr="\n".join(errs))
+
+ results = {
+ "changed": False,
+ "pods": inspect_results,
+ "stderr": "\n".join(errs),
+ }
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume.py
new file mode 100644
index 00000000..d74e39d3
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume.py
@@ -0,0 +1,477 @@
+#!/usr/bin/python
+# Copyright (c) 2020 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 = '''
+---
+module: podman_volume
+short_description: Manage Podman volumes
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+version_added: '1.1.0'
+description:
+ - Manage Podman volumes
+options:
+ state:
+ description:
+ - State of volume, default 'present'
+ type: str
+ default: present
+ choices:
+ - present
+ - absent
+ recreate:
+ description:
+ - Recreate volume even if exists.
+ type: bool
+ default: false
+ name:
+ description:
+ - Name of volume.
+ type: str
+ required: true
+ label:
+ description:
+ - Add metadata to a pod volume (e.g., label com.example.key=value).
+ type: dict
+ required: false
+ driver:
+ description:
+ - Specify volume driver name (default local).
+ type: str
+ required: false
+ options:
+ description:
+ - Set driver specific options. For example 'device=tpmfs', 'type=tmpfs'.
+ type: list
+ elements: str
+ required: false
+ 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
+ debug:
+ description:
+ - Return additional information which can be helpful for investigations.
+ type: bool
+ default: False
+
+requirements:
+ - "podman"
+
+'''
+
+RETURN = '''
+volume:
+ description: Volume inspection results if exists.
+ returned: always
+ type: dict
+ sample:
+ CreatedAt: '2020-06-05T16:38:55.277628769+03:00'
+ Driver: local
+ Labels:
+ key.com: value
+ key.org: value2
+ Mountpoint: /home/user/.local/share/containers/storage/volumes/test/_data
+ Name: test
+ Options: {}
+ Scope: local
+
+'''
+
+EXAMPLES = '''
+# What modules does for example
+- podman_volume:
+ state: present
+ name: volume1
+ label:
+ key: value
+ key2: value2
+ options:
+ - "device=/dev/loop1"
+ - "type=ext4"
+'''
+# noqa: F402
+import json # noqa: F402
+from distutils.version import LooseVersion # noqa: F402
+
+from ansible.module_utils.basic import AnsibleModule # noqa: F402
+from ansible.module_utils._text import to_bytes, to_native # noqa: F402
+
+from ansible_collections.containers.podman.plugins.module_utils.podman.common import lower_keys
+
+
+class PodmanVolumeModuleParams:
+ """Creates list of arguments for podman CLI command.
+
+ Arguments:
+ action {str} -- action type from 'create', 'delete'
+ params {dict} -- dictionary of module parameters
+
+ """
+
+ def __init__(self, action, params, podman_version, module):
+ self.params = params
+ self.action = action
+ self.podman_version = podman_version
+ self.module = module
+
+ def construct_command_from_params(self):
+ """Create a podman command from given module parameters.
+
+ Returns:
+ list -- list of byte strings for Popen command
+ """
+ if self.action in ['delete']:
+ return self._simple_action()
+ if self.action in ['create']:
+ return self._create_action()
+
+ def _simple_action(self):
+ if self.action == 'delete':
+ cmd = ['rm', '-f', self.params['name']]
+ return [to_bytes(i, errors='surrogate_or_strict') for i in cmd]
+
+ def _create_action(self):
+ cmd = [self.action, self.params['name']]
+ all_param_methods = [func for func in dir(self)
+ if callable(getattr(self, func))
+ and func.startswith("addparam")]
+ params_set = (i for i in self.params if self.params[i] is not None)
+ for param in params_set:
+ func_name = "_".join(["addparam", param])
+ if func_name in all_param_methods:
+ cmd = getattr(self, func_name)(cmd)
+ return [to_bytes(i, errors='surrogate_or_strict') for i in cmd]
+
+ def check_version(self, param, minv=None, maxv=None):
+ if minv and LooseVersion(minv) > LooseVersion(
+ self.podman_version):
+ self.module.fail_json(msg="Parameter %s is supported from podman "
+ "version %s only! Current version is %s" % (
+ param, minv, self.podman_version))
+ if maxv and LooseVersion(maxv) < LooseVersion(
+ self.podman_version):
+ self.module.fail_json(msg="Parameter %s is supported till podman "
+ "version %s only! Current version is %s" % (
+ param, minv, self.podman_version))
+
+ def addparam_label(self, c):
+ for label in self.params['label'].items():
+ c += ['--label', b'='.join(
+ [to_bytes(l, errors='surrogate_or_strict') for l in label])]
+ return c
+
+ def addparam_driver(self, c):
+ return c + ['--driver', self.params['driver']]
+
+ def addparam_options(self, c):
+ for opt in self.params['options']:
+ c += ['--opt', opt]
+ return c
+
+
+class PodmanVolumeDefaults:
+ def __init__(self, module, podman_version):
+ self.module = module
+ self.version = podman_version
+ self.defaults = {
+ 'driver': 'local',
+ 'label': {},
+ 'options': {}
+ }
+
+ def default_dict(self):
+ # make here any changes to self.defaults related to podman version
+ return self.defaults
+
+
+class PodmanVolumeDiff:
+ def __init__(self, module, info, podman_version):
+ self.module = module
+ self.version = podman_version
+ self.default_dict = None
+ self.info = lower_keys(info)
+ self.params = self.defaultize()
+ self.diff = {'before': {}, 'after': {}}
+ self.non_idempotent = {}
+
+ def defaultize(self):
+ params_with_defaults = {}
+ self.default_dict = PodmanVolumeDefaults(
+ self.module, self.version).default_dict()
+ for p in self.module.params:
+ if self.module.params[p] is None and p in self.default_dict:
+ params_with_defaults[p] = self.default_dict[p]
+ else:
+ params_with_defaults[p] = self.module.params[p]
+ return params_with_defaults
+
+ def _diff_update_and_compare(self, param_name, before, after):
+ if before != after:
+ self.diff['before'].update({param_name: before})
+ self.diff['after'].update({param_name: after})
+ return True
+ return False
+
+ def diffparam_label(self):
+ before = self.info['labels'] if 'labels' in self.info else {}
+ after = self.params['label']
+ return self._diff_update_and_compare('label', before, after)
+
+ def diffparam_driver(self):
+ before = self.info['driver']
+ after = self.params['driver']
+ return self._diff_update_and_compare('driver', before, after)
+
+ def diffparam_options(self):
+ before = self.info['options'] if 'options' in self.info else {}
+ before = ["=".join((k, v)) for k, v in before.items()]
+ after = self.params['options']
+ # Gor UID, GID
+ ids = []
+ if self.info['uid']:
+ before += ['uid=%s' % str(self.info['uid'])]
+ if self.info['gid']:
+ before += ['gid=%s' % str(self.info['gid'])]
+ if self.params['options']:
+ for opt in self.params['options']:
+ if 'uid=' in opt or 'gid=' in opt:
+ ids += opt.split("o=")[1].split(",")
+ after = [i for i in after if 'gid' not in i and 'uid' not in i]
+ after += ids
+ before, after = sorted(list(set(before))), sorted(list(set(after)))
+ return self._diff_update_and_compare('options', before, after)
+
+ def is_different(self):
+ diff_func_list = [func for func in dir(self)
+ if callable(getattr(self, func)) and func.startswith(
+ "diffparam")]
+ fail_fast = not bool(self.module._diff)
+ different = False
+ for func_name in diff_func_list:
+ dff_func = getattr(self, func_name)
+ if dff_func():
+ if fail_fast:
+ return True
+ else:
+ different = True
+ # Check non idempotent parameters
+ for p in self.non_idempotent:
+ if self.module.params[p] is not None and self.module.params[p] not in [{}, [], '']:
+ different = True
+ return different
+
+
+class PodmanVolume:
+ """Perform volume tasks.
+
+ Manages podman volume, inspects it and checks its current state
+ """
+
+ def __init__(self, module, name):
+ """Initialize PodmanVolume class.
+
+ Arguments:
+ module {obj} -- ansible module object
+ name {str} -- name of volume
+ """
+
+ super(PodmanVolume, self).__init__()
+ self.module = module
+ self.name = name
+ self.stdout, self.stderr = '', ''
+ self.info = self.get_info()
+ self.version = self._get_podman_version()
+ self.diff = {}
+ self.actions = []
+
+ @property
+ def exists(self):
+ """Check if volume exists."""
+ return bool(self.info != {})
+
+ @property
+ def different(self):
+ """Check if volume is different."""
+ diffcheck = PodmanVolumeDiff(
+ self.module,
+ self.info,
+ self.version)
+ is_different = diffcheck.is_different()
+ diffs = diffcheck.diff
+ if self.module._diff and is_different and diffs['before'] and diffs['after']:
+ self.diff['before'] = "\n".join(
+ ["%s - %s" % (k, v) for k, v in sorted(
+ diffs['before'].items())]) + "\n"
+ self.diff['after'] = "\n".join(
+ ["%s - %s" % (k, v) for k, v in sorted(
+ diffs['after'].items())]) + "\n"
+ return is_different
+
+ def get_info(self):
+ """Inspect volume and gather info about it."""
+ # pylint: disable=unused-variable
+ rc, out, err = self.module.run_command(
+ [self.module.params['executable'], b'volume', b'inspect', self.name])
+ return json.loads(out)[0] if rc == 0 else {}
+
+ def _get_podman_version(self):
+ # pylint: disable=unused-variable
+ rc, out, err = self.module.run_command(
+ [self.module.params['executable'], b'--version'])
+ if rc != 0 or not out or "version" not in out:
+ self.module.fail_json(msg="%s run failed!" %
+ self.module.params['executable'])
+ return out.split("version")[1].strip()
+
+ def _perform_action(self, action):
+ """Perform action with volume.
+
+ Arguments:
+ action {str} -- action to perform - create, stop, delete
+ """
+ b_command = PodmanVolumeModuleParams(action,
+ self.module.params,
+ self.version,
+ self.module,
+ ).construct_command_from_params()
+ full_cmd = " ".join([self.module.params['executable'], 'volume']
+ + [to_native(i) for i in b_command])
+ self.module.log("PODMAN-VOLUME-DEBUG: %s" % full_cmd)
+ self.actions.append(full_cmd)
+ if not self.module.check_mode:
+ rc, out, err = self.module.run_command(
+ [self.module.params['executable'], b'volume'] + b_command,
+ expand_user_and_vars=False)
+ self.stdout = out
+ self.stderr = err
+ if rc != 0:
+ self.module.fail_json(
+ msg="Can't %s volume %s" % (action, self.name),
+ stdout=out, stderr=err)
+
+ def delete(self):
+ """Delete the volume."""
+ self._perform_action('delete')
+
+ def create(self):
+ """Create the volume."""
+ self._perform_action('create')
+
+ def recreate(self):
+ """Recreate the volume."""
+ self.delete()
+ self.create()
+
+
+class PodmanVolumeManager:
+ """Module manager class.
+
+ Defines according to parameters what actions should be applied to volume
+ """
+
+ def __init__(self, module):
+ """Initialize PodmanManager class.
+
+ Arguments:
+ module {obj} -- ansible module object
+ """
+
+ super(PodmanVolumeManager, self).__init__()
+
+ self.module = module
+ self.results = {
+ 'changed': False,
+ 'actions': [],
+ 'volume': {},
+ }
+ self.name = self.module.params['name']
+ self.executable = \
+ self.module.get_bin_path(self.module.params['executable'],
+ required=True)
+ self.state = self.module.params['state']
+ self.recreate = self.module.params['recreate']
+ self.volume = PodmanVolume(self.module, self.name)
+
+ def update_volume_result(self, changed=True):
+ """Inspect the current volume, update results with last info, exit.
+
+ Keyword Arguments:
+ changed {bool} -- whether any action was performed
+ (default: {True})
+ """
+ facts = self.volume.get_info() if changed else self.volume.info
+ out, err = self.volume.stdout, self.volume.stderr
+ self.results.update({'changed': changed, 'volume': facts,
+ 'podman_actions': self.volume.actions},
+ stdout=out, stderr=err)
+ if self.volume.diff:
+ self.results.update({'diff': self.volume.diff})
+ if self.module.params['debug']:
+ self.results.update({'podman_version': self.volume.version})
+ self.module.exit_json(**self.results)
+
+ def execute(self):
+ """Execute the desired action according to map of actions & states."""
+ states_map = {
+ 'present': self.make_present,
+ 'absent': self.make_absent,
+ }
+ process_action = states_map[self.state]
+ process_action()
+ self.module.fail_json(msg="Unexpected logic error happened, "
+ "please contact maintainers ASAP!")
+
+ def make_present(self):
+ """Run actions if desired state is 'started'."""
+ if not self.volume.exists:
+ self.volume.create()
+ self.results['actions'].append('created %s' % self.volume.name)
+ self.update_volume_result()
+ elif self.recreate or self.volume.different:
+ self.volume.recreate()
+ self.results['actions'].append('recreated %s' %
+ self.volume.name)
+ self.update_volume_result()
+ else:
+ self.update_volume_result(changed=False)
+
+ def make_absent(self):
+ """Run actions if desired state is 'absent'."""
+ if not self.volume.exists:
+ self.results.update({'changed': False})
+ elif self.volume.exists:
+ self.volume.delete()
+ self.results['actions'].append('deleted %s' % self.volume.name)
+ self.results.update({'changed': True})
+ self.results.update({'volume': {},
+ 'podman_actions': self.volume.actions})
+ self.module.exit_json(**self.results)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ state=dict(type='str', default="present",
+ choices=['present', 'absent']),
+ name=dict(type='str', required=True),
+ label=dict(type='dict', required=False),
+ driver=dict(type='str', required=False),
+ options=dict(type='list', elements='str', required=False),
+ recreate=dict(type='bool', default=False),
+ executable=dict(type='str', required=False, default='podman'),
+ debug=dict(type='bool', default=False),
+ ))
+
+ PodmanVolumeManager(module).execute()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume_info.py b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume_info.py
new file mode 100644
index 00000000..97b43b3c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/containers/podman/plugins/modules/podman_volume_info.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python
+# Copyright (c) 2020 Red Hat
+# 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_volume_info
+author:
+ - "Sagi Shnaidman (@sshnaidm)"
+short_description: Gather info about podman volumes
+notes: []
+description:
+ - Gather info about podman volumes with podman inspect command.
+requirements:
+ - "Podman installed on host"
+options:
+ name:
+ description:
+ - Name of the volume
+ 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 present volumes
+ podman_volume_info:
+
+- name: Gather info about specific volume
+ podman_volume_info:
+ name: specific_volume
+"""
+
+RETURN = r"""
+volumes:
+ description: Facts from all or specified volumes
+ returned: always
+ type: list
+ sample: [
+ {
+ "name": "testvolume",
+ "labels": {},
+ "mountPoint": "/home/ansible/.local/share/testvolume/_data",
+ "driver": "local",
+ "options": {},
+ "scope": "local"
+ }
+ ]
+"""
+
+import json
+from ansible.module_utils.basic import AnsibleModule
+
+
+def get_volume_info(module, executable, name):
+ command = [executable, 'volume', 'inspect']
+ if name:
+ command.append(name)
+ else:
+ command.append("--all")
+ rc, out, err = module.run_command(command)
+ if rc != 0 or 'no such volume' in err:
+ module.fail_json(msg="Unable to gather info for %s: %s" % (name or 'all volumes', err))
+ if not out or json.loads(out) is None:
+ return [], out, err
+ return json.loads(out), out, err
+
+
+def main():
+ 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_volume_info(module, executable, name)
+
+ results = {
+ "changed": False,
+ "volumes": inspect_results,
+ "stderr": err
+ }
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()