From 40d383b180f19c1d4ad85753c4ece36df6e3f3fe Mon Sep 17 00:00:00 2001 From: Sagi Shnaidman Date: Thu, 3 Jun 2021 17:31:43 +0300 Subject: [PATCH 1/5] Add option to run with podman-py API Add Podman API support for podman_container and podman_container_info modules using podman-py module. Signed-off-by: Sagi Shnaidman --- .github/workflows/podman_container_api.yml | 118 +++++ bindep.txt | 1 + .../containers/podman_container_api.yml | 12 + plugins/module_utils/podman/common.py | 17 + plugins/module_utils/podman/podman_api.py | 287 +++++++++++ .../podman/podman_container_lib.py | 456 ++++++++++++++++-- plugins/modules/podman_container.py | 8 +- plugins/modules/podman_container_info.py | 33 +- requirements.txt | 1 + .../targets/podman_container/tasks/main.yml | 94 +++- .../targets/podman_container_api/files | 1 + .../podman_container_api/tasks/main.yml | 38 ++ .../tasks/idem_all.yml | 31 ++ .../tasks/idem_labels.yml | 17 + .../tasks/idem_networks.yml | 4 + .../tasks/idem_pods.yml | 5 + .../tasks/idem_ports.yml | 21 + .../tasks/idem_stopsignal.yml | 20 + .../tasks/idem_users.yml | 16 + .../tasks/idem_volumes.yml | 21 + .../tasks/idem_workdir.yml | 20 + .../tasks/root-podman-network.yml | 6 +- .../tasks/root-podman.yml | 82 ++++ .../tasks/rootless-podman-network.yml | 29 ++ .../podman_container_info/tasks/main.yml | 8 + 25 files changed, 1283 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/podman_container_api.yml create mode 100644 bindep.txt create mode 100644 ci/playbooks/containers/podman_container_api.yml create mode 100644 plugins/module_utils/podman/podman_api.py create mode 100644 requirements.txt create mode 120000 tests/integration/targets/podman_container_api/files create mode 100644 tests/integration/targets/podman_container_api/tasks/main.yml diff --git a/.github/workflows/podman_container_api.yml b/.github/workflows/podman_container_api.yml new file mode 100644 index 00000000..84708d3e --- /dev/null +++ b/.github/workflows/podman_container_api.yml @@ -0,0 +1,118 @@ +name: Podman API container + +on: + push: + paths: + - '.github/workflows/podman_container_api.yml' + - 'ci/*.yml' + - 'ci/run_containers_tests.sh' + - 'ci/playbooks/containers/podman_container_api.yml' + #- 'plugins/modules/podman_container.py' + - 'plugins/module_utils/podman/podman_container_lib.py' + - 'plugins/module_utils/podman/podman_api.py' + - 'plugins/module_utils/podman/common.py' + - 'tests/integration/targets/podman_container_api/**' + branches: + - master + pull_request: + paths: + - '.github/workflows/podman_container_api.yml' + - 'ci/*.yml' + - 'ci/run_containers_tests.sh' + - 'ci/playbooks/containers/podman_container_api.yml' + #- 'plugins/modules/podman_container.py' + - 'plugins/module_utils/podman/podman_container_lib.py' + - 'plugins/module_utils/podman/podman_api.py' + - 'plugins/module_utils/podman/common.py' + - 'tests/integration/targets/podman_container_api/**' + schedule: + - cron: 4 0 * * * # Run daily at 0:03 UTC + +jobs: + + test_podman_container_api: + name: Podman API container ${{ matrix.ansible-version }}-${{ matrix.os || 'ubuntu-22.04' }} + runs-on: ${{ matrix.os || 'ubuntu-22.04' }} + defaults: + run: + shell: bash + strategy: + fail-fast: false + matrix: + ansible-version: + - ansible<2.10 + - git+https://github.com/ansible/ansible.git@stable-2.15 + - git+https://github.com/ansible/ansible.git@devel + os: + - ubuntu-22.04 + python-version: + - "3.10" + + steps: + + - name: Check out repository + uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Upgrade pip and display Python and PIP versions + run: | + sudo apt-get update + sudo apt-get install -y python*-wheel python*-yaml + python -m pip install --upgrade pip + python -V + pip --version + + - name: Set up pip cache + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ github.ref }}-units-VMs + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: Install Ansible ${{ matrix.ansible-version }} + run: python3 -m pip install --user --force-reinstall --upgrade '${{ matrix.ansible-version }}' + + - name: Build and install the collection tarball + run: | + export PATH=~/.local/bin:$PATH + + echo "Run ansible version" + command -v ansible + ansible --version + rm -rf /tmp/just_new_collection + ~/.local/bin/ansible-galaxy collection build --output-path /tmp/just_new_collection --force + ~/.local/bin/ansible-galaxy collection install -vvv --force /tmp/just_new_collection/*.tar.gz + + - name: Run collection tests for podman container API + run: | + export PATH=~/.local/bin:$PATH + + if [[ '${{ matrix.ansible-version }}' == 'git+https://github.com/ansible/ansible.git@devel' ]]; then + export ANSIBLE_CONFIG=$(pwd)/ci/ansible-dev.cfg + elif [[ '${{ matrix.ansible-version }}' == 'ansible<2.10' ]]; then + export ANSIBLE_CONFIG=$(pwd)/ci/ansible-2.9.cfg + fi + python3 -m pip install --user -r requirements.txt + podman system service --time=0 unix:///tmp/podman.sock & + sudo podman system service --time=0 unix:///tmp/root-podman.sock & + + echo $ANSIBLE_CONFIG + command -v ansible-playbook + pip --version + python --version + ansible-playbook --version + + ansible-playbook -vv ci/playbooks/pre.yml \ + -e host=localhost \ + -i localhost, \ + -e ansible_connection=local \ + -e setup_python=false + + TEST2RUN=podman_container_api ./ci/run_containers_tests.sh + shell: bash diff --git a/bindep.txt b/bindep.txt new file mode 100644 index 00000000..5247d591 --- /dev/null +++ b/bindep.txt @@ -0,0 +1 @@ +podman diff --git a/ci/playbooks/containers/podman_container_api.yml b/ci/playbooks/containers/podman_container_api.yml new file mode 100644 index 00000000..ae4ffe14 --- /dev/null +++ b/ci/playbooks/containers/podman_container_api.yml @@ -0,0 +1,12 @@ +--- +- hosts: all + gather_facts: true + module_defaults: + containers.podman.podman_container: + podman_socket: unix:///tmp/podman.sock + tasks: + - include_role: + name: podman_container_api + vars: + idem_image: idempotency_test + ansible_python_interpreter: "{{ _ansible_python_interpreter }}" diff --git a/plugins/module_utils/podman/common.py b/plugins/module_utils/podman/common.py index acdc6490..5c19b55e 100644 --- a/plugins/module_utils/podman/common.py +++ b/plugins/module_utils/podman/common.py @@ -18,6 +18,13 @@ raise_from(ImportError('To use this plugin or module with ansible-core' ' < 2.11, you need to use Python < 3.12 with ' 'distutils.version present'), exc) +try: + import requests # pylint: disable=unused-import + from .podman_api import PodmanAPIClient + HAS_REQUESTS = True +except ImportError: + PodmanAPIClient = object + HAS_REQUESTS = False ARGUMENTS_OPTS_DICT = { '--attach': ['--attach', '-a'], @@ -426,3 +433,13 @@ def diff_generic(params, info_config, module_arg, cmd_arg, boolean_type=False): else: before = ",".join(sorted(before)) if len(before) > 1 else before[0] return before, after +class PodmanAPI: + def __init__(self, module, module_params): + if module_params.get('podman_socket') and not HAS_REQUESTS: + module.fail_json( + msg="Requests module is not installed while socket was provided!") + self.client = PodmanAPIClient(module_params.get('podman_socket')) + try: + self.client.version() + except Exception as api_error: + module.fail_json(msg="Podman API error: %s" % str(api_error)) diff --git a/plugins/module_utils/podman/podman_api.py b/plugins/module_utils/podman/podman_api.py new file mode 100644 index 00000000..9d3fe83a --- /dev/null +++ b/plugins/module_utils/podman/podman_api.py @@ -0,0 +1,287 @@ + +# The follwing code is taken from +# https://github.com/msabramo/requests-unixsocket/blob/master/ +# requests_unixsocket/adapters.py +from __future__ import (absolute_import, division, print_function) + +import socket +try: + import requests + from requests.adapters import HTTPAdapter + from requests.compat import urlparse, unquote, quote + HAS_REQUESTS = True +except ImportError: + HAS_REQUESTS = False + +try: + from requests.packages import urllib3 + HAS_URLLIB3 = True +except ImportError: + try: + import urllib3 + HAS_URLLIB3 = True + except ImportError: + HAS_URLLIB3 = False + +try: + import http.client as httplib +except ImportError: + import httplib + +import json + + +__metaclass__ = type + + +DEFAULT_SCHEME = 'http+unix://' + + +# The following was adapted from some code from docker-py +# https://github.com/docker/docker-py/blob/master/docker/transport/unixconn.py +class UnixHTTPConnection(httplib.HTTPConnection, object): + + def __init__(self, unix_socket_url, timeout=60): + """Create an HTTP connection to a unix domain socket + :param unix_socket_url: A URL with a scheme of 'http+unix' and the + netloc is a percent-encoded path to a unix domain socket. E.g.: + 'http+unix://%2Ftmp%2Fprofilesvc.sock/status/pid' + """ + super(UnixHTTPConnection, self).__init__('localhost', timeout=timeout) + self.unix_socket_url = unix_socket_url + self.timeout = timeout + self.sock = None + + def __del__(self): # base class does not have d'tor + if self.sock: + self.sock.close() + + def connect(self): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.settimeout(self.timeout) + socket_path = unquote(urlparse(self.unix_socket_url).netloc) + sock.connect(socket_path) + self.sock = sock + + +if HAS_URLLIB3: + class UnixHTTPConnectionPool(urllib3.connectionpool.HTTPConnectionPool): + + def __init__(self, socket_path, timeout=60): + super(UnixHTTPConnectionPool, self).__init__( + 'localhost', timeout=timeout) + self.socket_path = socket_path + self.timeout = timeout + + def _new_conn(self): + return UnixHTTPConnection(self.socket_path, self.timeout) + + +if HAS_REQUESTS: + class UnixAdapter(HTTPAdapter): + + def __init__(self, timeout=60, pool_connections=25, *args, **kwargs): + super(UnixAdapter, self).__init__(*args, **kwargs) + self.timeout = timeout + self.pools = urllib3._collections.RecentlyUsedContainer( + pool_connections, dispose_func=lambda p: p.close() + ) + + def get_connection(self, url, proxies=None): + proxies = proxies or {} + proxy = proxies.get(urlparse(url.lower()).scheme) + + if proxy: + raise ValueError('%s does not support specifying proxies' + % self.__class__.__name__) + + with self.pools.lock: + pool = self.pools.get(url) + if pool: + return pool + + pool = UnixHTTPConnectionPool(url, self.timeout) + self.pools[url] = pool + + return pool + + def request_url(self, request, proxies): + return request.path_url + + def close(self): + self.pools.clear() + + +if HAS_REQUESTS: + class APISession(requests.Session): + def __init__(self, url_scheme=DEFAULT_SCHEME, *args, **kwargs): + super(APISession, self).__init__(*args, **kwargs) + self.mount(url_scheme, UnixAdapter()) + + +class PodmanAPIHTTP: + def __init__(self, base_url): + self.api_url = "".join((DEFAULT_SCHEME, + quote(base_url, safe=""), + "/v2.0.0/libpod")) + self.session = APISession() + + def request(self, method, url, **kwargs): + return self.session.request(method=method, url=self.api_url + url, **kwargs) + + def get(self, url, **kwargs): + kwargs.setdefault('allow_redirects', True) + return self.request('get', url, **kwargs) + + def head(self, url, **kwargs): + kwargs.setdefault('allow_redirects', False) + return self.request('head', url, **kwargs) + + def post(self, url, data=None, json=None, **kwargs): + return self.request('post', url, data=data, json=json, **kwargs) + + def patch(self, url, data=None, **kwargs): + return self.request('patch', url, data=data, **kwargs) + + def put(self, url, data=None, **kwargs): + return self.request('put', url, data=data, **kwargs) + + def delete(self, url, **kwargs): + return self.request('delete', url, **kwargs) + + def options(self, url, **kwargs): + kwargs.setdefault('allow_redirects', True) + return self.request('options', url, **kwargs) + + +class PodmanAPIClient: + def __init__(self, base_url): + if not HAS_REQUESTS: + raise Exception("requests package is required for podman API") + socket_opt = urlparse(base_url) + if socket_opt.scheme != "unix": + raise Exception("Scheme %s is not supported! Use %s" % ( + socket_opt.scheme, + DEFAULT_SCHEME + )) + self.api = PodmanAPIHTTP(socket_opt.path) + self.containers = PodmanAPIContainers(self.api) + self.images = PodmanAPIImages(api=self.api) + + def version(self): + response = self.api.get( + '/version') + return response.json() + + +class PodmanAPIContainers: + def __init__(self, api): + self.api = api + self.quote = quote + + def list( + self, all_=None, filters=None, limit=None, size=None, sync=None): + """List all images for a Podman service.""" + query = {} + if all_ is not None: + query["all"] = True + if filters is not None: + query["filters"] = filters + if limit is not None: + query["limit"] = limit + if size is not None: + query["size"] = size + if sync is not None: + query["sync"] = sync + response = self.api.get("/containers/json", params=query) + # observed to return None when no containers + return response.json() or [] + + def create(self, **container_data): + response = self.api.post( + "/containers/create", + json=container_data, + ) + if response.ok: + return response.json() + raise Exception("Container %s failed to create! Error: %s" % + (container_data.get('name'), response.text)) + + def get(self, name): + response = self.api.get( + '/containers/{0}/json'.format(self.quote(name))) + data = response.json() + if data.get('response') == 404: + data = {} + # raise Exception("Container %s not found!" % name) + return data + + def run(self, **container_data): + _ = self.create(**container_data) # pylint: disable=blacklisted-name + name = container_data.get("name") + _ = self.api.post( # pylint: disable=blacklisted-name + "/containers/{0}/start".format(self.quote(name)), + ) + return self.get(name) + + def start(self, name): + _ = self.api.post( # pylint: disable=blacklisted-name + "/containers/{0}/start".format(self.quote(name)), + ) + return self.get(name) + + def stop(self, name): + _ = self.api.post( # pylint: disable=blacklisted-name + "/containers/{0}/stop".format(self.quote(name)), + ) + return self.get(name) + + def restart(self, name): + _ = self.api.post( # pylint: disable=blacklisted-name + "/containers/{0}/restart".format(self.quote(name)), + ) + return self.get(name) + + def remove(self, name, force=False): + _ = self.api.delete( # pylint: disable=blacklisted-name + "/containers/{0}".format(self.quote(name)), + params={"force": force} + ) + return + + +class PodmanAPIImages: + def __init__(self, api): + self.api = api + self.quote = quote + self.inspect = self.get + + def exists(self, name): + response = self.api.get( + '/images/{0}/exists'.format(self.quote(name))) + return response.status_code == 204 + + def pull(self, reference): + response = self.api.post( + '/images/pull', + params={'reference': reference} + ) + if response.ok: + correct_response = {'stream': '', 'text': response.text} + for i in response.text.splitlines(): + if '"images"' in i: + correct_response['images'] = json.loads(i)['images'] + if '"id"' in i: + correct_response['id'] = json.loads(i)['id'] + elif '"stream"' in i: + correct_response['stream'] += json.loads(i)['stream'] + elif '"error"' in i: + correct_response['error'] = json.loads(i)['error'] + correct_response['code'] = response.status_code + return correct_response + return {"error": "HTTP %s Error: %s" % (response.json()['message'])} + + def get(self, name): + response = self.api.get( + '/images/{0}/json'.format(self.quote(name))) + return response.json() diff --git a/plugins/module_utils/podman/podman_container_lib.py b/plugins/module_utils/podman/podman_container_lib.py index 76458f14..4bee466b 100644 --- a/plugins/module_utils/podman/podman_container_lib.py +++ b/plugins/module_utils/podman/podman_container_lib.py @@ -2,23 +2,31 @@ import json # noqa: F402 import os # noqa: F402 import shlex # noqa: F402 +import time from ansible.module_utils._text import to_bytes, to_native # noqa: F402 from ansible_collections.containers.podman.plugins.module_utils.podman.common import LooseVersion from ansible_collections.containers.podman.plugins.module_utils.podman.common import lower_keys from ansible_collections.containers.podman.plugins.module_utils.podman.common import generate_systemd from ansible_collections.containers.podman.plugins.module_utils.podman.common import delete_systemd +<<<<<<< HEAD from ansible_collections.containers.podman.plugins.module_utils.podman.common import diff_generic from ansible_collections.containers.podman.plugins.module_utils.podman.common import createcommand from ansible_collections.containers.podman.plugins.module_utils.podman.quadlet import create_quadlet_state from ansible_collections.containers.podman.plugins.module_utils.podman.quadlet import ContainerQuadlet +======= +from ansible_collections.containers.podman.plugins.module_utils.podman.common import normalize_signal +from .common import PodmanAPI +>>>>>>> e7671a8 (Add option to run with podman-py API) __metaclass__ = type +USE_API = False ARGUMENTS_SPEC_CONTAINER = dict( name=dict(required=True, type='str'), executable=dict(default='podman', type='str'), + podman_socket=dict(type='str'), state=dict(type='str', default='started', choices=[ 'absent', 'present', 'stopped', 'started', 'created', 'quadlet']), image=dict(type='str'), @@ -62,7 +70,7 @@ device_write_iops=dict(type='list', elements='str'), dns=dict(type='list', elements='str', aliases=['dns_servers']), dns_option=dict(type='str', aliases=['dns_opts']), - dns_search=dict(type='str', aliases=['dns_search_domains']), + dns_search=dict(type='list', elements='str', aliases=['dns_search_domains']), entrypoint=dict(type='str'), env=dict(type='dict'), env_file=dict(type='list', elements='path', aliases=['env_files']), @@ -193,6 +201,55 @@ volumes_from=dict(type='list', elements='str'), workdir=dict(type='str', aliases=['working_dir']) ) +NON_PODMAN_ARGS = [ + 'state', + 'podman_socket', + 'executable', 'debug', + 'force_restart', + 'image_strict', + 'recreate' +] +API_TRANSLATION = { + 'annotation': 'annotations', + 'conmon_pidfile': 'conmon_pid_file', + 'etc_hosts': 'hostadd', + 'add_hosts': 'hostadd', + 'http_proxy': 'httpproxy', + 'label': 'labels', + 'publish_all': 'publish_image_ports', + 'rm': 'remove', + 'auto_remove': 'remove', + 'volume': 'volumes', + 'mount': 'mounts', + 'workdir': 'work_dir', + 'working_dir': 'work_dir', + 'dns_search_domains': 'dns_search', + 'dns': 'dns_server', + 'dns_opts': 'dns_option', + 'publish': 'portmappings', + 'published': 'portmappings', + 'published_ports': 'portmappings', + 'ports': 'portmappings', + 'pids_mode': 'pidns', + 'pid': 'pidns', + 'ipc_mode': 'ipcns', + 'ipc': 'ipcns', + 'uts': 'utsns', + 'userns_mode': 'userns', + 'tty': 'terminal', + 'device': 'devices', + 'exposed': 'expose', + 'exposed_ports': 'expose', + 'group_add': 'groups', + 'ulimit': 'r_limits', + 'ulimits': 'r_limits', + 'read_only': 'read_only_filesystem', + 'ip': 'static_ip', + 'mac_address': 'static_mac', + 'no_hosts': 'use_image_hosts', + 'log_opt': 'log_configuration', + 'log_driver': 'log_configuration', +} def init_options(): @@ -239,6 +296,218 @@ def set_container_opts(input_vars): return options_dict +class PodmanModuleParamsAPI: + """Creates Podman API call. + + Arguments: + action {str} -- action type from 'run', 'stop', 'create', 'delete', + 'start' + params {dict} -- dictionary of module parameters + + """ + def __init__(self, params, podman_version, module): + self.params = params + self.podman_version = podman_version + self.module = module + self.new_params = {} + + def translate(self): + self.new_params = { + k: v for k, v in self.params.items() + if v is not None and k not in NON_PODMAN_ARGS + } + if self.new_params.get('command') and not isinstance( + self.new_params.get('command'), list): + self.new_params['command'] = shlex.split(self.new_params['command']) + transformed = {} + mounts = [] + for k in self.new_params: + key = API_TRANSLATION.get(k, k) + transformed[key] = self.new_params[k] + if transformed.get('env'): + for k, v in transformed['env'].items(): + transformed['env'][k] = str(v) + if transformed.get('labels'): + for k, v in transformed['labels'].items(): + transformed['labels'][k] = str(v) + if transformed.get('entrypoint') is not None: + transformed['entrypoint'] = shlex.split(transformed['entrypoint']) + if transformed.get('hostadd') is not None: + hosts = [] + for k, v in transformed['hostadd'].items(): + hosts.append(":".join((k, v))) + transformed['hostadd'] = hosts + if transformed.get('volumes'): + volumes = [] + for v in transformed['volumes']: + vols = v.split(":") + if len(vols) < 2 or "/" not in vols[0]: + name = vols[0] if len(vols) > 1 else "" + volumes.append( + { + "Name": name, + "Dest": vols[1] if len(vols) > 1 else v, + } + ) + continue + source = vols[0] + dest = vols[1].split(",")[0] # remove options + options = [] + if len(vols) > 2: + opts = vols[2].split(",") + # work on options + for opt in opts: + if opt.lower() == 'ro': + options.append('ro') + elif opt.lower().lstrip("r") in ( + 'shared', 'slave', 'private', 'unbindable'): + options.append(opt) + mounts.append( + {'destination': dest, + 'source': source, + 'type': 'bind', + 'options': options, + } + ) + transformed['volumes'] = volumes + if transformed.get('mounts'): + n_mounts = [] + for m in transformed['mounts']: + if not isinstance(m, str): + continue + mlist = m.split(",") + mdict = {} + for m1 in mlist: + if '=' in m1: + mkey, mval = m1.split("=") + else: + continue + if mkey.lower() == 'type': + mdict['Type'] = mval + if mval.lower() == 'devpts': + mdict['Source'] = 'devpts' + elif mkey.lower() in ('source', 'src'): + mdict['Source'] = mval + elif mkey.lower() in ('destination', 'dst', 'target'): + mdict['Destination'] = mval + elif mkey.lower() == 'bind-propagation': + if 'BindOptions' not in mdict: + mdict['BindOptions'] = {} + mdict['BindOptions']['Propagation'] = mval + elif mkey.lower() == 'bind-nonrecursive': + if 'BindOptions' not in mdict: + mdict['BindOptions'] = {} + mdict['BindOptions']['NonRecursive'] = mval + elif mkey.lower() == 'ro': + mdict['ReadOnly'] = mval + elif mkey.lower() == 'tmpfs-mode': + if 'TmpfsOptions' not in mdict: + mdict['TmpfsOptions'] = {} + mdict['TmpfsOptions']['Mode'] = mval + elif mkey.lower() == 'tmpfs-size': + if 'TmpfsOptions' not in mdict: + mdict['TmpfsOptions'] = {} + mdict['TmpfsOptions']['SizeBytes'] = mval + n_mounts.append(mdict) + transformed['mounts'] = n_mounts + mounts + else: + transformed['mounts'] = mounts + if transformed.get('portmappings') is not None: + total_ports = [] + for p in transformed.get('portmappings'): + parts = p.split(":") + if len(parts) == 1: + c_port, protocol = (parts[0].split("/") + ["tcp"])[:2] + total_ports.append({ + "container_port": int(p), + "protocol": protocol if 'udp' not in p else 'udp', + # "host_port": int(parts[0].split("/")[0]) + }) + elif len(parts) == 2: + c_port, protocol = (parts[1].split("/") + ["tcp"])[:2] + total_ports.append( + { + "container_port": int(c_port), + "host_port": int(parts[0].split("/")[0]), + "protocol": protocol if 'udp' not in p else 'udp', + }) + elif len(parts) == 3: + c_port, protocol = (parts[1].split("/") + ["tcp"])[:2] + total_ports.append( + { + "host_port": int(c_port), + "container_port": int(parts[2].split("/")[0]), + "protocol": protocol if 'udp' not in p else 'udp', + "host_ip": parts[0], + }) + transformed['portmappings'] = total_ports + if transformed.get('pod'): + # API doesn't support creating Pod + transformed['pod'] = transformed['pod'].replace("new:", "") + if transformed.get('pidns'): + transformed['pidns'] = {"nsmode": transformed['pidns']} + if transformed.get('ipcns'): + transformed['ipcns'] = {"nsmode": transformed['ipcns']} + if transformed.get('utsns'): + transformed['utsns'] = {"nsmode": transformed['utsns']} + if transformed.get('userns'): + transformed['userns'] = {"nsmode": transformed['userns']} + if transformed.get('cgroupns'): + transformed['cgroupns'] = {"nsmode": transformed['cgroupns']} + if transformed.get('network'): + if (len(transformed['network']) > 1 + or len(transformed['network'][0].split(",")) > 1 + and transformed['network'][0] not in ('none', 'host', 'bridge', 'private') + and 'container:' not in transformed['network'][0] + and 'ns:' not in transformed['network'][0] + and 'slirp4netns:' not in transformed['network'][0]): + if "," in transformed['network'][0]: + transformed['Networks'] = {k: {} for k in transformed['network'][0].split(",")} + else: + transformed['Networks'] = {k: {} for k in transformed['network']} + transformed['netns'] = {"nsmode": 'bridge'} + elif (len(transformed['network']) == 1 + and transformed['network'][0] not in ('none', 'host', 'bridge', 'private') + and 'container:' not in transformed['network'][0] + and 'ns:' not in transformed['network'][0] + and 'slirp4netns:' not in transformed['network'][0]): + transformed['Networks'] = {k: {} for k in transformed['network']} + elif 'slirp4netns:' in transformed['network'][0] or 'bridge:' in transformed['network'][0]: + transformed['netns'] = {"nsmode": transformed['network'][0].split(":")[0]} + netopts = {k: [v] for k, v in [i.split("=") + for i in transformed['network'][0].split(":")[1].split(",")]} + transformed['network_options'] = netopts + else: + transformed['netns'] = {"nsmode": transformed['network'][0]} + if transformed.get('r_limits'): + rlimits = [] + for rlim in transformed['r_limits']: + tmp_rlim = rlim.split("=") + typ = tmp_rlim[0] + soft = tmp_rlim[1].split(":")[0] + if len(tmp_rlim[1].split(":")) > 1: + hard = tmp_rlim[1].split(":")[1] + else: + hard = soft + rlimits.append( + {"type": typ, "soft": int(soft), "hard": int(hard)}) + transformed['r_limits'] = rlimits + if transformed.get('rootfs'): + transformed["rootfs"] = transformed["image"] + transformed.pop("image") + if transformed.get('log_configuration'): + transformed['log_configuration'] = {} + if self.params['log_opt'] is not None: + transformed['log_configuration']['options'] = self.params['log_opt'] + if self.params['log_driver'] is not None: + transformed['log_configuration']['driver'] = self.params['log_driver'] + if transformed.get('devices'): + transformed['devices'] = [ + {'path': d.split(":")[0]} for d in transformed['devices']] + self.module.log("PODMAN-DEBUG-API: %s" % transformed) + return transformed + + class PodmanModuleParams: """Creates list of arguments for podman CLI command. @@ -456,7 +725,7 @@ def addparam_dns_option(self, c): return c + ['--dns-option', self.params['dns_option']] def addparam_dns_search(self, c): - return c + ['--dns-search', self.params['dns_search']] + return c + ['--dns-search', ','.join(self.params['dns_search'])] def addparam_entrypoint(self, c): return c + ['--entrypoint', self.params['entrypoint']] @@ -1169,7 +1438,10 @@ def diffparam_http_proxy(self): def diffparam_image(self): before_id = self.info['image'] or self.info['rootfs'] - after_id = self.image_info['id'] + if self.params['rootfs']: + after_id = self.params['image'] + else: + after_id = self.image_info['id'] if before_id == after_id: return self._diff_update_and_compare('image', before_id, after_id) is_rootfs = self.info['rootfs'] != '' or self.params['rootfs'] @@ -1478,7 +1750,7 @@ def is_different(self): return different -def ensure_image_exists(module, image, module_params): +def ensure_image_exists(module, image, module_params, client): """If image is passed, ensure it exists, if not - pull it or fail. Arguments: @@ -1498,13 +1770,25 @@ def ensure_image_exists(module, image, module_params): return image_actions if not image: return image_actions - rc, out, err = module.run_command([module_exec, 'image', 'exists', image]) - if rc == 0: - return image_actions - rc, out, err = module.run_command([module_exec, 'image', 'pull', image]) - if rc != 0: - module.fail_json(msg="Can't pull image %s" % image, stdout=out, - stderr=err) + if USE_API: + if client.images.exists(image): + return image_actions + else: + rc, out, err = module.run_command( + [module_exec, 'image', 'exists', image]) + if rc == 0: + return image_actions + if USE_API: + img = client.images.pull(image) + if not img.get('id'): + module.fail_json(msg="Can't find and pull image %s: %s" % ( + image, img['text'])) + else: + rc, out, err = module.run_command( + [module_exec, 'image', 'pull', image]) + if rc != 0: + module.fail_json(msg="Can't pull image %s" % image, stdout=out, + stderr=err) image_actions.append("pulled image %s" % image) return image_actions @@ -1515,7 +1799,7 @@ class PodmanContainer: Manages podman container, inspects it and checks its current state """ - def __init__(self, module, name, module_params): + def __init__(self, module, name, module_params, client): """Initialize PodmanContainer class. Arguments: @@ -1524,6 +1808,7 @@ def __init__(self, module, name, module_params): """ self.module = module + self.client = client self.module_params = module_params self.name = name self.stdout, self.stderr = '', '' @@ -1570,6 +1855,12 @@ def stopped(self): def get_info(self): """Inspect container and gather info about it.""" # pylint: disable=unused-variable + if USE_API: + try: + container = self.client.containers.get(self.name) + return container + except Exception: + return {} rc, out, err = self.module.run_command( [self.module_params['executable'], b'container', b'inspect', self.name]) return json.loads(out)[0] if rc == 0 else {} @@ -1577,15 +1868,24 @@ def get_info(self): def get_image_info(self): """Inspect container image and gather info about it.""" # pylint: disable=unused-variable - is_rootfs = self.module_params['rootfs'] - if is_rootfs: - return {'Id': self.module_params['image']} - rc, out, err = self.module.run_command( - [self.module_params['executable'], b'image', b'inspect', self.module_params['image']]) - return json.loads(out)[0] if rc == 0 else {} + if USE_API: + try: + img = self.client.images.get(self.module_params['image']) + return img + except Exception: + return {} + else: + is_rootfs = self.module_params['rootfs'] + if is_rootfs: + return {'Id': self.module_params['image']} + rc, out, err = self.module.run_command( + [self.module_params['executable'], b'image', b'inspect', self.module_params['image']]) + return json.loads(out)[0] if rc == 0 else {} def _get_podman_version(self): # pylint: disable=unused-variable + if USE_API: + return self.client.version()['Version'] rc, out, err = self.module.run_command( [self.module_params['executable'], b'--version']) if rc != 0 or not out or "version" not in out: @@ -1600,32 +1900,67 @@ def _perform_action(self, action): action {str} -- action to perform - start, create, stop, run, delete, restart """ - b_command = PodmanModuleParams(action, - self.module_params, - self.version, - self.module, - ).construct_command_from_params() - full_cmd = " ".join([self.module_params['executable']] - + [to_native(i) for i in b_command]) - self.actions.append(full_cmd) - if self.module.check_mode: - self.module.log( - "PODMAN-CONTAINER-DEBUG (check_mode): %s" % full_cmd) + if USE_API: + new_params = PodmanModuleParamsAPI(self.module_params, + self.version, + self.module, + ).translate() + + if action in ('start', 'stop', 'delete', 'restart'): + container = self.client.containers.get(self.name) + if not container: + self.module.fail_json(msg="Container %s doesn't exist") + if action == 'start': + self.client.containers.start(self.name) + elif action == 'stop': + self.client.containers.stop(self.name) + elif action == 'restart': + self.client.containers.restart(self.name) + elif action == 'delete': + self.client.containers.remove(self.name, force=True) + elif action == 'create': + new_params.pop('detach') + try: + container = self.client.containers.create( + **new_params + ) + except Exception as e: + self.module.fail_json(msg=str(e)) + elif action == 'run': + try: + container = self.client.containers.run( + **new_params + ) + except Exception as e: + self.module.fail_json(msg=str(e)) + self.actions.append({action: new_params}) else: - rc, out, err = self.module.run_command( - [self.module_params['executable'], b'container'] + b_command, - expand_user_and_vars=False) - self.module.log("PODMAN-CONTAINER-DEBUG: %s" % full_cmd) - if self.module_params['debug']: - self.module.log("PODMAN-CONTAINER-DEBUG STDOUT: %s" % out) - self.module.log("PODMAN-CONTAINER-DEBUG STDERR: %s" % err) - self.module.log("PODMAN-CONTAINER-DEBUG RC: %s" % rc) - self.stdout = out - self.stderr = err - if rc != 0: - self.module.fail_json( - msg="Container %s exited with code %s when %sed" % (self.name, rc, action), - stdout=out, stderr=err) + b_command = PodmanModuleParams(action, + self.module_params, + self.version, + self.module, + ).construct_command_from_params() + full_cmd = " ".join([self.module_params['executable']] + + [to_native(i) for i in b_command]) + self.actions.append(full_cmd) + if self.module.check_mode: + self.module.log( + "PODMAN-CONTAINER-DEBUG (check_mode): %s" % full_cmd) + else: + rc, out, err = self.module.run_command( + [self.module_params['executable'], b'container'] + b_command, + expand_user_and_vars=False) + self.module.log("PODMAN-CONTAINER-DEBUG: %s" % full_cmd) + if self.module_params['debug']: + self.module.log("PODMAN-CONTAINER-DEBUG STDOUT: %s" % out) + self.module.log("PODMAN-CONTAINER-DEBUG STDERR: %s" % err) + self.module.log("PODMAN-CONTAINER-DEBUG RC: %s" % rc) + self.stdout = out + self.stderr = err + if rc != 0: + self.module.fail_json( + msg="Can't %s container %s" % (action, self.name), + stdout=out, stderr=err) def run(self): """Run the container.""" @@ -1689,12 +2024,19 @@ def __init__(self, module, params): } self.module_params = params self.name = self.module_params['name'] - self.executable = \ - self.module.get_bin_path(self.module_params['executable'], - required=True) + self.client = None + if self.module_params['podman_socket']: + global USE_API + USE_API = True + api = PodmanAPI(self.module, self.module_params) + self.client = api.client + else: + self.executable = \ + self.module.get_bin_path(self.module_params['executable'], + required=True) self.image = self.module_params['image'] image_actions = ensure_image_exists( - self.module, self.image, self.module_params) + self.module, self.image, self.module_params, self.client) self.results['actions'] += image_actions self.state = self.module_params['state'] self.restart = self.module_params['force_restart'] @@ -1704,7 +2046,23 @@ def __init__(self, module, params): self.module_params['rm'] = True self.container = PodmanContainer( - self.module, self.name, self.module_params) + self.module, self.name, self.module_params, self.client) + + def api_wait(self): + """In case of detach=False and API call, wait until container + is finished. + """ + if (self.container.module_params.get("detach") is None + or self.container.module_params.get("detach")): + return + status = True + time.sleep(2) # Give time to container to start + while status: + info = self.container.get_info() + if not info: + return + status = info['State']['Running'] + time.sleep(2) def update_container_result(self, changed=True): """Inspect the current container, update results with last info, exit. @@ -1713,6 +2071,8 @@ def update_container_result(self, changed=True): changed {bool} -- whether any action was performed (default: {True}) """ + if USE_API: + self.api_wait() facts = self.container.get_info() if changed else self.container.info out, err = self.container.stdout, self.container.stderr self.results.update({'changed': changed, 'container': facts, diff --git a/plugins/modules/podman_container.py b/plugins/modules/podman_container.py index b06c9ae9..4faa6e00 100644 --- a/plugins/modules/podman_container.py +++ b/plugins/modules/podman_container.py @@ -32,6 +32,11 @@ machine running C(podman) default: 'podman' type: str + podman_socket: + description: + - Unix socket address for API connection. If API is not available, the + module will fail. + type: str state: description: - I(absent) - A container matching the specified name will be stopped and @@ -298,7 +303,8 @@ description: - Set custom DNS search domains (Use dns_search with '' if you don't wish to set the search domain) - type: str + type: list + elements: str aliases: - dns_search_domains entrypoint: diff --git a/plugins/modules/podman_container_info.py b/plugins/modules/podman_container_info.py index dd361c44..6af86c18 100644 --- a/plugins/modules/podman_container_info.py +++ b/plugins/modules/podman_container_info.py @@ -31,6 +31,11 @@ machine running C(podman) default: 'podman' type: str + podman_socket: + description: + - Unix socket address for API connection. If API is not available, the + module will fail. + type: str ''' EXAMPLES = r""" @@ -316,8 +321,12 @@ import json import time + +from ..module_utils.podman.common import PodmanAPI from ansible.module_utils.basic import AnsibleModule +USE_API = False + def get_containers_facts(module, executable, name): """Collect containers facts for all containers or for specified in 'name'. @@ -332,6 +341,24 @@ def get_containers_facts(module, executable, name): """ retry = 0 retry_limit = 4 + if module.params['podman_socket']: + global USE_API + USE_API = True + api = PodmanAPI(module, module.params) + client = api.client + all_names = client.containers.list(all_=True) + all_data = [] + cycle = name or [j['Id'] for j in all_names] + for c in cycle: + try: + container_attrs = client.containers.get(c) + if container_attrs: + all_data.append(container_attrs) + except Exception: + if name: + module.fail_json(msg="Container %s can't be found!" % c) + continue + return all_data, '', '' if not name: all_names = [executable, 'container', 'ls', '-q', '-a'] rc, out, err = module.run_command(all_names) @@ -394,12 +421,16 @@ def main(): argument_spec={ 'executable': {'type': 'str', 'default': 'podman'}, 'name': {'type': 'list', 'elements': 'str'}, + 'podman_socket': {'type': 'str'} }, supports_check_mode=True, ) name = module.params['name'] - executable = module.get_bin_path(module.params['executable'], required=True) + executable = None + if not module.params['podman_socket']: + executable = module.get_bin_path( + module.params['executable'], required=True) # pylint: disable=unused-variable inspect_results, out, err = get_containers_facts(module, executable, name) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..ba07d192 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests==2.28.2 diff --git a/tests/integration/targets/podman_container/tasks/main.yml b/tests/integration/targets/podman_container/tasks/main.yml index 02d664af..62a8e376 100644 --- a/tests/integration/targets/podman_container/tasks/main.yml +++ b/tests/integration/targets/podman_container/tasks/main.yml @@ -25,6 +25,7 @@ executable: "{{ test_executable | default('podman') }}" name: "{{ item }}" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" loop: - "alpine:3.7" - "container" @@ -37,6 +38,7 @@ containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" name: container + podman_socket: "{{ podman_socket | default(omit) }}" ignore_errors: true register: no_image @@ -45,6 +47,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: created + podman_socket: "{{ podman_socket | default(omit) }}" ignore_errors: true register: no_image1 @@ -53,6 +56,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: present + podman_socket: "{{ podman_socket | default(omit) }}" ignore_errors: true register: no_image2 @@ -81,6 +85,7 @@ image: alpine:3.7 state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: image - name: Check using already pulled image @@ -90,6 +95,7 @@ image: alpine:3.7 state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: image2 - name: Check output is correct @@ -115,6 +121,7 @@ image: ineverneverneverexist state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: imagefail ignore_errors: true @@ -122,7 +129,9 @@ assert: that: - imagefail is failed - - imagefail.msg == "Can't pull image ineverneverneverexist" + - >- + imagefail.msg == "Can't pull image ineverneverneverexist" + or "Can't find and pull image ineverneverneverexist" in imagefail.msg - name: Force container recreate containers.podman.podman_container: @@ -132,6 +141,7 @@ state: started command: sleep 1d recreate: true + podman_socket: "{{ podman_socket | default(omit) }}" register: recreated - name: Check output is correct @@ -149,6 +159,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: started + podman_socket: "{{ podman_socket | default(omit) }}" - name: Present container containers.podman.podman_container: @@ -157,6 +168,7 @@ image: alpine state: present command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: start_present - name: Check output is correct @@ -169,6 +181,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: stopped + podman_socket: "{{ podman_socket | default(omit) }}" register: stopped - name: Stop the same container again (idempotency) @@ -176,6 +189,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: stopped + podman_socket: "{{ podman_socket | default(omit) }}" register: stopped_again - name: Check output is correct @@ -197,6 +211,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: absent + podman_socket: "{{ podman_socket | default(omit) }}" register: deleted - name: Delete again container (idempotency) @@ -204,6 +219,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: absent + podman_socket: "{{ podman_socket | default(omit) }}" register: deleted_again - name: Check output is correct @@ -227,6 +243,7 @@ image: alpine:3.7 state: stopped command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: created - name: Check output is correct @@ -265,6 +282,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Create container in 'created' state containers.podman.podman_container: @@ -273,6 +291,7 @@ image: alpine:3.7 state: created command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: created - name: Check output is correct @@ -294,6 +313,7 @@ state: created command: sleep 1d recreate: true + podman_socket: "{{ podman_socket | default(omit) }}" register: recreated - name: Check output is correct @@ -310,6 +330,7 @@ executable: "{{ test_executable | default('podman') }}" name: container restart: true + podman_socket: "{{ podman_socket | default(omit) }}" register: restarted - name: Check output is correct @@ -326,6 +347,7 @@ executable: "{{ test_executable | default('podman') }}" name: container restart: true + podman_socket: "{{ podman_socket | default(omit) }}" register: restarted - name: Check output is correct @@ -342,6 +364,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Start container that was deleted containers.podman.podman_container: @@ -350,6 +373,7 @@ image: alpine:3.7 state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: started - name: Check output is correct @@ -365,6 +389,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: absent + podman_socket: "{{ podman_socket | default(omit) }}" register: deleted - name: Delete again container (idempotency) @@ -372,6 +397,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: absent + podman_socket: "{{ podman_socket | default(omit) }}" register: deleted_again - name: Check output is correct @@ -466,6 +492,7 @@ - /tmp:/data mounts: - type=devpts,destination=/dev/pts + podman_socket: "{{ podman_socket | default(omit) }}" register: test - name: Check output is correct @@ -532,6 +559,7 @@ image: docker.io/alpine state: started command: sleep 20m + podman_socket: "{{ podman_socket | default(omit) }}" - name: Check basic idempotency of running container - run it again containers.podman.podman_container: @@ -540,6 +568,7 @@ image: alpine:latest state: started command: sleep 20m + podman_socket: "{{ podman_socket | default(omit) }}" register: idem - name: Check that nothing was changed @@ -555,6 +584,7 @@ state: started command: sleep 20m force_restart: true + podman_socket: "{{ podman_socket | default(omit) }}" register: idem_r - name: Check that task was changed @@ -569,6 +599,7 @@ image: alpine:latest state: started command: sleep 20m + podman_socket: "{{ podman_socket | default(omit) }}" register: idem_r1 - name: Check that task was not changed @@ -584,6 +615,7 @@ state: started command: sleep 20m tty: true + podman_socket: "{{ podman_socket | default(omit) }}" register: idem1 - name: Check that container is recreated when changed @@ -598,6 +630,7 @@ image: alpine state: started command: sleep 20m + podman_socket: "{{ podman_socket | default(omit) }}" register: idem2 - name: Check that container is recreated when changed to default value @@ -610,15 +643,21 @@ executable: "{{ test_executable | default('podman') }}" name: testidem state: absent + podman_socket: "{{ podman_socket | default(omit) }}" register: remove - name: Check podman_actions assert: that: - "'podman rm --force testidem' in remove.podman_actions" + when: podman_socket is not defined - # - name: Create a pod - # shell: podman pod create --name testidempod + - name: Check basic idempotency of pod container + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: testidempod + state: started + when: podman_socket is defined - name: Check basic idempotency of pod container containers.podman.podman_container: @@ -628,6 +667,7 @@ state: started command: sleep 20m pod: "new:testidempod" + podman_socket: "{{ podman_socket | default(omit) }}" - name: Check basic idempotency of pod container - run it again containers.podman.podman_container: @@ -637,6 +677,7 @@ state: started command: sleep 20m pod: testidempod + podman_socket: "{{ podman_socket | default(omit) }}" register: idem3 - name: Check that nothing was changed in pod containers @@ -653,6 +694,7 @@ command: sleep 20m tty: true pod: testidempod + podman_socket: "{{ podman_socket | default(omit) }}" register: idem4 - name: Check that container is recreated when changed @@ -669,6 +711,7 @@ image: alpine state: started command: sleep 20m + podman_socket: "{{ podman_socket | default(omit) }}" generate_systemd: path: /tmp/ restart_policy: always @@ -690,6 +733,7 @@ image: alpine state: started command: sleep 20m + podman_socket: "{{ podman_socket | default(omit) }}" generate_systemd: path: /tmp/ time: 120 @@ -761,6 +805,7 @@ image: alpine state: absent command: sleep 20m + podman_socket: "{{ podman_socket | default(omit) }}" generate_systemd: path: /tmp/ restart_policy: always @@ -814,6 +859,7 @@ - stdout - stderr env_file: /tmp/envfile + podman_socket: "{{ podman_socket | default(omit) }}" register: envfile - name: Check output is correct for env file @@ -837,6 +883,7 @@ env_file: - /tmp/envfile - /tmp/envfile2 + podman_socket: "{{ podman_socket | default(omit) }}" register: envfile2 - name: Check output is correct for multiple env files @@ -849,6 +896,7 @@ executable: "{{ test_executable | default('podman') }}" name: container1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Create temporary rootfs directory ansible.builtin.tempfile: @@ -861,22 +909,29 @@ - name: Download alpine releases file ansible.builtin.get_url: - url: "https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/{{ ansible_architecture }}/latest-releases.yaml" + url: "https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/{{ ansible_architecture | default('x86_64') }}/latest-releases.yaml" dest: "{{ container_tempdir.path }}/latest-releases.yaml" register: alpine_releases_file - - name: Get content of alpine releases file - ansible.builtin.slurp: + - name: Get content of galaxy.yml + slurp: src: "{{ container_tempdir.path }}/latest-releases.yaml" - register: latest_releases_file + register: release_vars + + - name: Parse yaml into temporary variable + set_fact: + release_yaml_t: "{{ release_vars['content'] | b64decode | from_yaml }}" + + - name: Parse yaml into variable + set_fact: + release_yaml: "{{ release_yaml_t | from_yaml }}" - name: Download alpine latest rootfs vars: - latest_releases: "{{ latest_releases_file.content | b64decode }}" - latest_version: "{{ (latest_releases | from_yaml)[0].version }}" - latest_branch: "{{ (latest_releases | from_yaml)[0].branch }}" + latest_version: "{{ release_yaml[0].version }}" + latest_branch: "{{ release_yaml[0].branch }}" ansible.builtin.unarchive: - src: "https://dl-cdn.alpinelinux.org/alpine/{{ latest_branch }}/releases/{{ ansible_architecture }}/alpine-minirootfs-{{ latest_version }}-{{ ansible_architecture }}.tar.gz" + src: "https://dl-cdn.alpinelinux.org/alpine/{{ latest_branch }}/releases/{{ ansible_architecture | default('x86_64') }}/alpine-minirootfs-{{ latest_version }}-{{ ansible_architecture | default('x86_64') }}.tar.gz" dest: "{{ container_tempdir.path }}" remote_src: true @@ -888,6 +943,7 @@ rootfs: true state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: imagerootfsfail ignore_errors: true @@ -905,6 +961,7 @@ rootfs: true state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: image - name: Check output is correct @@ -927,6 +984,7 @@ rootfs: true state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: idem - name: Check that nothing was changed @@ -941,6 +999,7 @@ image: alpine:3.7 state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: image - name: Debug image @@ -967,6 +1026,7 @@ rootfs: true state: started command: sleep 1d + podman_socket: "{{ podman_socket | default(omit) }}" register: image - name: Check output is correct @@ -988,6 +1048,7 @@ image: alpine:3.7 state: started command: ls /nonexists + podman_socket: "{{ podman_socket | default(omit) }}" attach: - stdout - stderr @@ -1005,6 +1066,7 @@ executable: "{{ test_executable | default('podman') }}" name: container1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Create container with attaching in created state containers.podman.podman_container: @@ -1016,6 +1078,7 @@ attach: - stdout - stderr + podman_socket: "{{ podman_socket | default(omit) }}" - name: Start container with attaching from created state containers.podman.podman_container: @@ -1025,6 +1088,7 @@ attach: - stdout - stderr + podman_socket: "{{ podman_socket | default(omit) }}" register: attach2 ignore_errors: true @@ -1039,6 +1103,7 @@ executable: "{{ test_executable | default('podman') }}" name: container1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Create container without attaching in created state containers.podman.podman_container: @@ -1047,12 +1112,14 @@ image: alpine:3.7 state: created command: ls /nonexists + podman_socket: "{{ podman_socket | default(omit) }}" - name: Start container without attaching from created state containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" name: container1 state: started + podman_socket: "{{ podman_socket | default(omit) }}" register: attach21 - name: Check output is correct for container without attaching from created state @@ -1065,6 +1132,7 @@ executable: "{{ test_executable | default('podman') }}" name: container1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Create container with detach False containers.podman.podman_container: @@ -1074,6 +1142,7 @@ state: created command: ls /nonexists detach: false + podman_socket: "{{ podman_socket | default(omit) }}" - name: Start container with detach False containers.podman.podman_container: @@ -1081,6 +1150,7 @@ name: container1 state: started detach: false + podman_socket: "{{ podman_socket | default(omit) }}" register: attach3 ignore_errors: true @@ -1355,12 +1425,14 @@ executable: "{{ test_executable | default('podman') }}" name: testidem-pod state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Delete all container leftovers from tests containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" name: "{{ item }}" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" loop: - "alpine:3.7" - "container" diff --git a/tests/integration/targets/podman_container_api/files b/tests/integration/targets/podman_container_api/files new file mode 120000 index 00000000..01683cbe --- /dev/null +++ b/tests/integration/targets/podman_container_api/files @@ -0,0 +1 @@ +../podman_container_idempotency/files \ No newline at end of file diff --git a/tests/integration/targets/podman_container_api/tasks/main.yml b/tests/integration/targets/podman_container_api/tasks/main.yml new file mode 100644 index 00000000..5845d559 --- /dev/null +++ b/tests/integration/targets/podman_container_api/tasks/main.yml @@ -0,0 +1,38 @@ +--- +- name: Set podman socket var for rootless + set_fact: + podman_socket: unix:///tmp/podman.sock + podman_root_socket: unix:///tmp/root-podman.sock + +- name: Run tasks from podman container + include_tasks: ../../podman_container/tasks/main.yml + +- name: Run tasks from podman container info + include_tasks: ../../podman_container_info/tasks/main.yml + +- name: Prepare a container + include_tasks: ../../podman_container_idempotency/tasks/build_test_container.yml + +- name: Test idempotency of users + include_tasks: ../../podman_container_idempotency/tasks/idem_users.yml + +- name: Test idempotency of workdir + include_tasks: ../../podman_container_idempotency/tasks/idem_workdir.yml + +- name: Test idempotency of labels + include_tasks: ../../podman_container_idempotency/tasks/idem_labels.yml + +- name: Test idempotency of stop signal + include_tasks: ../../podman_container_idempotency/tasks/idem_stopsignal.yml + +- name: Test idempotency of ports + include_tasks: ../../podman_container_idempotency/tasks/idem_ports.yml + +- name: Test idempotency of volumes + include_tasks: ../../podman_container_idempotency/tasks/idem_volumes.yml + +- name: Test idempotency of containers in pods + include_tasks: ../../podman_container_idempotency/tasks/idem_pods.yml + +- name: Test idempotency of other settings + include_tasks: ../../podman_container_idempotency/tasks/idem_all.yml diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml index 11dbf594..12ae2db2 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml @@ -4,6 +4,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container containers.podman.podman_container: @@ -12,6 +13,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container again containers.podman.podman_container: @@ -20,6 +22,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test1 - name: Check info when running container again @@ -74,6 +77,7 @@ mykey: "amazing value" ENV1: "one=two=three" command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test2 - name: Check info with environment vars @@ -90,6 +94,7 @@ mykey: "amazing value" ENV1: "one=two=three" command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test3 - name: Check info with environment vars again @@ -106,6 +111,7 @@ mykey: "amazing value1" ENV1: "one=two=three" command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test4 - name: Check info with changed environment vars @@ -122,6 +128,7 @@ tag: nonotag log_driver: journald command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9 - name: Check info with log opt tag @@ -138,6 +145,7 @@ tag: nonotag log_driver: journald command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test10 - name: Check info with log opt tag - again @@ -152,6 +160,7 @@ state: present command: 1h log_driver: journald + podman_socket: "{{ podman_socket | default(omit) }}" register: test11 - name: Check info with default log opt tag @@ -168,6 +177,7 @@ path: /tmp/container.log log_driver: journald command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test12 - name: Check info with log opt path @@ -184,6 +194,7 @@ path: /tmp/container2.log log_driver: journald command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test13 - name: Check info with changed log opt path @@ -198,6 +209,7 @@ state: present log_driver: journald command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test14 - name: Check info with default log opt path @@ -216,6 +228,7 @@ max_size: 100mb tag: sometag command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with mounted /dev/fuse containers.podman.podman_container: @@ -226,6 +239,7 @@ command: 1h device: - /dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" register: test15 - name: Run container with mounted /dev/fuse again @@ -237,6 +251,7 @@ command: 1h device: - /dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" register: test16 - name: Run container with mounted /dev/fuse:/dev/fuse @@ -248,6 +263,7 @@ command: 1h device: - /dev/fuse:/dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" register: test17 - name: Run container with mounted /dev/fuse third time @@ -259,6 +275,7 @@ command: 1h device: - /dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" register: test18 - name: Run container without mounted device @@ -268,6 +285,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test19 - name: Check info with mounted devices @@ -289,6 +307,7 @@ host1: 127.0.0.1 host2: fd00::1 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test20 - name: Check info with etc_hosts @@ -305,6 +324,7 @@ host1: 127.0.0.1 host2: fd00::1 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test21 - name: Check info with etc_hosts again @@ -317,6 +337,7 @@ image: "{{ idem_image }}" name: idempotency state: present + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with restart policy always containers.podman.podman_container: @@ -325,6 +346,7 @@ name: idempotency state: present restart_policy: always + podman_socket: "{{ podman_socket | default(omit) }}" register: test22 - name: Check info with restart policy always @@ -338,6 +360,7 @@ name: idempotency state: present restart_policy: always + podman_socket: "{{ podman_socket | default(omit) }}" register: test23 - name: Check info with restart policy always again @@ -351,6 +374,7 @@ name: idempotency state: present restart_policy: on-failure + podman_socket: "{{ podman_socket | default(omit) }}" register: test24 - name: Check info with restart policy on-failure @@ -363,6 +387,7 @@ image: "{{ idem_image }}" name: idempotency state: present + podman_socket: "{{ podman_socket | default(omit) }}" register: test25 - name: Check info w/o restart policy @@ -375,6 +400,7 @@ image: "{{ idem_image }}" name: idempotency state: present + podman_socket: "{{ podman_socket | default(omit) }}" register: test26 - name: Check info with PID @@ -388,6 +414,7 @@ name: idempotency2 state: present pid: "container:idempotency" + podman_socket: "{{ podman_socket | default(omit) }}" register: test27 - name: Check info of second container with PID @@ -401,6 +428,7 @@ name: idempotency2 state: present pid: "container:idempotency" + podman_socket: "{{ podman_socket | default(omit) }}" register: test28 - name: Check info of second container with PID again @@ -414,6 +442,7 @@ name: idempotency2 state: present pid: "container:{{ test26.container.Id }}" + podman_socket: "{{ podman_socket | default(omit) }}" register: test29 - name: Check info of second container with PID of container ID again @@ -425,9 +454,11 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency2 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Remove test container containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_labels.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_labels.yml index 5d08d450..1eaf5549 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_labels.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_labels.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -10,6 +11,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -17,6 +19,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test1 - name: check test1 @@ -32,6 +35,7 @@ key: "amazing value" nobody: "cares" command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test2 - name: check test2 @@ -44,6 +48,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test3 - name: check test3 @@ -61,6 +66,7 @@ OEIWIOP: eufslsa ieui4: KDJSL4D command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test4 - name: check test4 @@ -78,6 +84,7 @@ OEIWIOP: eufslsa ieui4: KDJSL4D command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test5 - name: check test5 @@ -90,6 +97,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test6 - name: check test6 @@ -104,6 +112,7 @@ label: test: notest command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test7 - name: check test7 @@ -119,6 +128,7 @@ key: "amazing value" nobody: "cares" command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test8 - name: check test8 @@ -131,6 +141,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9 - name: check test9 @@ -141,6 +152,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -148,6 +160,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -155,6 +168,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test10 - name: check test10 @@ -169,6 +183,7 @@ label: razraz: dva command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test11 - name: check test11 @@ -181,6 +196,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test12 - name: check test12 @@ -193,6 +209,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test13 - name: check test13 diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_networks.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_networks.yml index 0eedfda6..900ce7e2 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_networks.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_networks.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: netcontainer state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with {{ item.first_net }} containers.podman.podman_container: @@ -12,6 +13,7 @@ command: 1h state: started network: "{{ item.first_net }}" + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container again with {{ item.first_net }} containers.podman.podman_container: @@ -21,6 +23,7 @@ command: 1h state: present network: "{{ item.first_net }}" + podman_socket: "{{ podman_socket | default(omit) }}" register: info - name: Check info for 2 runs of {{ item.first_net }} @@ -36,6 +39,7 @@ command: 1h state: present network: "{{ item.next_net }}" + podman_socket: "{{ podman_socket | default(omit) }}" register: info1 - name: Check info diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_pods.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_pods.yml index 56e1e95d..06597be8 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_pods.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_pods.yml @@ -9,6 +9,7 @@ executable: "{{ test_executable | default('podman') }}" name: testpod_container1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Create pod containers.podman.podman_pod: @@ -30,6 +31,7 @@ test: test2 volumes: - /tmp:/data + podman_socket: "{{ podman_socket | default(omit) }}" - name: Start test container again containers.podman.podman_container: @@ -44,6 +46,7 @@ test: test2 volumes: - /tmp:/data + podman_socket: "{{ podman_socket | default(omit) }}" register: info - name: Check starting container @@ -57,6 +60,7 @@ name: testpod_container1 pod: testpod state: started + podman_socket: "{{ podman_socket | default(omit) }}" register: info1 - name: Check starting container changed @@ -70,6 +74,7 @@ name: testpod_container1 pod: testpod state: started + podman_socket: "{{ podman_socket | default(omit) }}" register: info2 - name: Check starting container again diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_ports.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_ports.yml index 29ad10c6..999d97b9 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_ports.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_ports.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -10,6 +11,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -17,6 +19,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test1 - name: check test1 @@ -45,6 +48,7 @@ - 0.0.0.0:20000-20010:20000-20010/tcp - "10000-10010:10000-10010/udp" - "[::1]:3001-3003:3001-3003" + podman_socket: "{{ podman_socket | default(omit) }}" register: test2 - name: check test2 @@ -73,6 +77,7 @@ - 0.0.0.0:20000-20010:20000-20010/tcp - "10000-10010:10000-10010/udp" - "[::1]:3001-3003:3001-3003" + podman_socket: "{{ podman_socket | default(omit) }}" register: test3 - name: check test3 @@ -86,6 +91,7 @@ state: present publish_all: true command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test4 - name: check test4 @@ -99,6 +105,7 @@ state: present publish_all: true command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test5 - name: check test5 @@ -111,6 +118,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test6 - name: check test6 @@ -125,6 +133,7 @@ ports: - 10000:8080 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test7 - name: check test7 @@ -139,6 +148,7 @@ ports: - 10001:8080 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test8 - name: check test8 @@ -153,6 +163,7 @@ ports: - 10001:8080/tcp command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9 - name: check test9 @@ -168,6 +179,7 @@ - 10001:8080/tcp publish_all: false command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9a - name: check test9a @@ -180,6 +192,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9b - name: check test9b @@ -190,6 +203,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -197,6 +211,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -204,6 +219,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test10 - name: check test10 @@ -217,6 +233,7 @@ state: present publish_all: false command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test11 - name: check test11 @@ -230,6 +247,7 @@ state: present publish_all: true command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test11a - name: check test11a @@ -244,6 +262,7 @@ ports: - 10000:8080 command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test12 - name: check test12 @@ -256,6 +275,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test13 - name: check test13 @@ -268,6 +288,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test14 - name: check test14 diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_stopsignal.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_stopsignal.yml index b806120d..be156a24 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_stopsignal.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_stopsignal.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -10,6 +11,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -17,6 +19,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test1 - name: check test1 @@ -30,6 +33,7 @@ state: present stop_signal: 9 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test2 - name: check test2 @@ -55,6 +59,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test3 - name: check test3 @@ -68,6 +73,7 @@ state: present stop_signal: 10 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test4 - name: check test4 @@ -81,6 +87,7 @@ state: present stop_signal: 10 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test5 - name: check test5 @@ -93,6 +100,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test6 - name: check test6 @@ -106,6 +114,7 @@ state: present stop_signal: 15 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test7 - name: check test7 @@ -119,6 +128,7 @@ state: present stop_signal: 9 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test8 - name: check test8 @@ -131,6 +141,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9 - name: check test9 @@ -144,6 +155,7 @@ state: present stop_signal: 15 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9a - name: check test9a @@ -156,6 +168,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9b - name: check test9b @@ -166,6 +179,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -173,6 +187,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -180,6 +195,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test10 - name: check test10 @@ -193,6 +209,7 @@ state: present stop_signal: 15 command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test11 - name: check test11 @@ -206,6 +223,7 @@ state: present stop_signal: 10 command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test12 - name: check test12 @@ -218,6 +236,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test13 - name: check test13 @@ -230,6 +249,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test14 - name: check test14 diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_users.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_users.yml index 9b82ae33..6e97add5 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_users.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_users.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -10,6 +11,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -17,6 +19,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test1 - name: check test1 @@ -30,6 +33,7 @@ state: present user: user command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test2 - name: check test2 @@ -42,6 +46,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test3 - name: check test3 @@ -55,6 +60,7 @@ state: present user: user2 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test4 - name: check test4 @@ -68,6 +74,7 @@ state: present user: user2 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test5 - name: check test5 @@ -80,6 +87,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test6 - name: check test6 @@ -93,6 +101,7 @@ state: present user: user2 command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test7 - name: check test7 @@ -106,6 +115,7 @@ state: present user: user command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test8 - name: check test8 @@ -118,6 +128,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9 - name: check test9 @@ -128,6 +139,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -142,6 +154,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test10 - name: check test10 @@ -155,6 +168,7 @@ state: present user: nobody command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test11 - name: check test11 @@ -167,6 +181,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test12 - name: check test12 @@ -179,6 +194,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test13 - name: check test13 diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_volumes.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_volumes.yml index 26e7040f..60f870b9 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_volumes.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_volumes.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -10,6 +11,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -17,6 +19,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test1 - name: check test1 @@ -29,6 +32,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test2 - name: check test2 @@ -41,6 +45,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test3 - name: check test3 @@ -55,6 +60,7 @@ volumes: - /opt:/somedir/ command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test4 - name: check test4 @@ -69,6 +75,7 @@ volumes: - /opt/://somedir/ command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test5 - name: check test5 @@ -81,6 +88,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test6 - name: check test6 @@ -96,6 +104,7 @@ - /opt:/somedir - /data command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test7 - name: check test7 @@ -110,6 +119,7 @@ volumes: - /data command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test8 - name: check test8 @@ -122,6 +132,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9 - name: check test9 @@ -142,6 +153,7 @@ volumes: - "/opt:/anotherdir" - "local_volume1:/data" + podman_socket: "{{ podman_socket | default(omit) }}" register: test10 - name: check test10 @@ -157,6 +169,7 @@ volumes: - "/opt//:/anotherdir" - "local_volume1:/data/" + podman_socket: "{{ podman_socket | default(omit) }}" register: test11 - name: check test11 @@ -172,6 +185,7 @@ volumes: - "/opt:/anotherdir" - "local_volume2:/data" + podman_socket: "{{ podman_socket | default(omit) }}" register: test12 - name: check test12 @@ -186,6 +200,7 @@ command: 1h volumes: - "/opt:/anotherdir" + podman_socket: "{{ podman_socket | default(omit) }}" register: test13 - name: check test13 @@ -196,6 +211,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -203,6 +219,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -210,6 +227,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test14 - name: check test14 @@ -224,6 +242,7 @@ volumes: - /opt:/data command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test15 - name: check test15 @@ -236,6 +255,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test16 - name: check test16 @@ -248,6 +268,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test17 - name: check test17 diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_workdir.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_workdir.yml index f413090c..076de166 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_workdir.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_workdir.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -10,6 +11,7 @@ name: idempotency state: started command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -17,6 +19,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test1 - name: check test1 @@ -30,6 +33,7 @@ state: present workdir: /work command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test2 - name: check test2 @@ -43,6 +47,7 @@ state: present workdir: /work command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test3 - name: check test3 @@ -56,6 +61,7 @@ state: present workdir: /var command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test4 - name: check test4 @@ -69,6 +75,7 @@ state: present workdir: /var command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test5 - name: check test5 @@ -81,6 +88,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test6 - name: check test6 @@ -94,6 +102,7 @@ state: present workdir: /var command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test7 - name: check test7 @@ -107,6 +116,7 @@ state: present workdir: /work command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test8 - name: check test8 @@ -119,6 +129,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9 - name: check test9 @@ -132,6 +143,7 @@ state: present workdir: / command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9a - name: check test9a @@ -144,6 +156,7 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test9b - name: check test9b @@ -154,6 +167,7 @@ executable: "{{ test_executable | default('podman') }}" name: idempotency1 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -161,6 +175,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" - containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" @@ -168,6 +183,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test10 - name: check test10 @@ -181,6 +197,7 @@ state: present workdir: / command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test11 - name: check test11 @@ -194,6 +211,7 @@ state: present workdir: /var command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test12 - name: check test12 @@ -206,6 +224,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test13 - name: check test13 @@ -218,6 +237,7 @@ name: idempotency1 state: present command: sleep 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test14 - name: check test14 diff --git a/tests/integration/targets/podman_container_idempotency/tasks/root-podman-network.yml b/tests/integration/targets/podman_container_idempotency/tasks/root-podman-network.yml index 6d5b7bb0..79d7b955 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/root-podman-network.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/root-podman-network.yml @@ -6,12 +6,13 @@ executable: "{{ test_executable | default('podman') }}" name: netcontainer state: absent + podman_socket: "{{ podman_root_socket | default(omit) }}" - name: Create network testnet - command: podman network create testnet --subnet 10.92.92.0/24 + shell: podman network exists testnet || podman network create testnet --subnet 10.92.92.0/24 - name: Create network anothernet - command: podman network create anothernet --subnet 10.72.72.0/24 + shell: podman network exists anothernet || podman network create anothernet --subnet 10.72.72.0/24 - name: List current networks command: podman network ls @@ -64,6 +65,7 @@ executable: "{{ test_executable | default('podman') }}" name: netcontainer state: absent + podman_socket: "{{ podman_root_socket | default(omit) }}" - name: Delete all network leftovers from tests shell: | diff --git a/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml b/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml index 0d903275..1b93c474 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml @@ -5,6 +5,7 @@ executable: "{{ test_executable | default('podman') }}" name: root-idempotency state: absent + podman_socket: "{{ podman_root_socket | default(omit) }}" - name: Run container as is containers.podman.podman_container: @@ -13,6 +14,7 @@ name: root-idempotency state: started command: 1h + podman_socket: "{{ podman_root_socket | default(omit) }}" - name: Run container as is again containers.podman.podman_container: @@ -21,6 +23,7 @@ name: root-idempotency state: present command: 1h + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info_a - name: Check that it is not recreated @@ -38,6 +41,7 @@ ulimit: - 'nofile=55535:55535' - 'memlock=-1:-1' + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info - name: Check that it is recreated @@ -55,6 +59,7 @@ ulimit: - 'nofile=55535:55535' - 'memlock=-1:-1' + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info1 - name: Check that it is recreated @@ -72,6 +77,7 @@ ulimit: - 'nofile=55535:65535' - 'memlock=-1:-1' + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info2 - name: Check that it is recreated @@ -89,6 +95,7 @@ ulimit: - 'nofile=55535:65535' - 'memlock=-1:-1' + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info3 - name: Check that it is recreated @@ -103,6 +110,7 @@ name: root-idempotency state: started command: 1h + podman_socket: "{{ podman_root_socket | default(omit) }}" - name: Run containers with MAC address containers.podman.podman_container: @@ -112,6 +120,7 @@ state: started command: 1h mac_address: 44:55:66:77:88:99 + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info4 - name: Check that it is not recreated @@ -128,6 +137,7 @@ state: present command: 1h mac_address: 44:55:66:77:88:99 + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info5 - name: Check that it is not recreated @@ -143,6 +153,7 @@ state: present command: 1h mac_address: 44:55:66:77:88:33 + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info6 - name: Check that it is recreated @@ -157,6 +168,7 @@ name: root-idempotency state: present command: 1h + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info7 - name: Check that it is recreated @@ -179,6 +191,7 @@ - "127.0.0.3:43423:8872" - "[::1]:34523:35425" - "40001-40010" + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info8 - name: Check that it is recreated @@ -201,6 +214,7 @@ - "127.0.0.3:43423:8872" - "[::1]:34523:35425" - "40001-40010" + podman_socket: "{{ podman_root_socket | default(omit) }}" register: info9 - name: Check that it is recreated @@ -208,8 +222,76 @@ that: - info9 is not changed +- name: Run container with mounted /dev/fuse + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + image: "{{ idem_image }}" + name: idempotency + state: started + command: 1h + device: + - /dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" + register: test15 + +- name: Run container with mounted /dev/fuse again + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + image: "{{ idem_image }}" + name: idempotency + state: started + command: 1h + device: + - /dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" + register: test16 + +- name: Run container with mounted /dev/fuse:/dev/fuse + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + image: "{{ idem_image }}" + name: idempotency + state: started + command: 1h + device: + - /dev/fuse:/dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" + register: test17 + +- name: Run container with mounted /dev/fuse third time + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + image: "{{ idem_image }}" + name: idempotency + state: started + command: 1h + device: + - /dev/fuse + podman_socket: "{{ podman_socket | default(omit) }}" + register: test18 + +- name: Run container without mounted device + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + image: "{{ idem_image }}" + name: idempotency + state: started + command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" + register: test19 + +- name: Check info with mounted devices + assert: + that: + - test15 is changed + - test16 is not changed + - test17 is not changed + - test18 is not changed + - test19 is changed + - name: Make sure container doesn't exist containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" name: root-idempotency state: absent + podman_socket: "{{ podman_root_socket | default(omit) }}" diff --git a/tests/integration/targets/podman_container_idempotency/tasks/rootless-podman-network.yml b/tests/integration/targets/podman_container_idempotency/tasks/rootless-podman-network.yml index 74c21ff4..09069a60 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/rootless-podman-network.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/rootless-podman-network.yml @@ -6,12 +6,14 @@ executable: "{{ test_executable | default('podman') }}" name: rootlessnet2 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Remove container rootlessnet containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" name: rootlessnet state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with no specified networks containers.podman.podman_container: @@ -20,6 +22,7 @@ image: "{{ idem_image }}" command: 1h state: started + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container again with no specified networks containers.podman.podman_container: @@ -28,6 +31,7 @@ image: "{{ idem_image }}" command: 1h state: present + podman_socket: "{{ podman_socket | default(omit) }}" register: info - name: Check info for no specified networks @@ -43,6 +47,7 @@ command: 1h state: present network: host + podman_socket: "{{ podman_socket | default(omit) }}" register: info1 - name: Check info with network mode host @@ -58,6 +63,7 @@ command: 1h state: present network: host + podman_socket: "{{ podman_socket | default(omit) }}" register: info2 - name: Check info with network mode host again @@ -73,6 +79,7 @@ command: 1h state: present network: none + podman_socket: "{{ podman_socket | default(omit) }}" register: info3 - name: Check info without network at all @@ -88,6 +95,7 @@ command: 1h state: present network: none + podman_socket: "{{ podman_socket | default(omit) }}" register: info4 - name: Check info without network at all again @@ -102,6 +110,7 @@ image: "{{ idem_image }}" command: 1h state: present + podman_socket: "{{ podman_socket | default(omit) }}" register: info5 - name: Check info with default network mode @@ -121,12 +130,14 @@ state: present network: - slirp4netns:allow_host_loopback=true,cidr=10.0.3.0/24 + podman_socket: "{{ podman_socket | default(omit) }}" register: info6 - name: Check info with slirp4netns options assert: that: - info6 is changed + when: podman_socket is not defined - name: Run container with slirp4netns options - again containers.podman.podman_container: @@ -137,6 +148,7 @@ state: present network: - slirp4netns:allow_host_loopback=true,cidr=10.0.3.0/24 + podman_socket: "{{ podman_socket | default(omit) }}" register: info7 - name: Check info with slirp4netns options - again @@ -153,12 +165,14 @@ state: present network: - slirp4netns:allow_host_loopback=true,cidr=10.0.4.0/24 + podman_socket: "{{ podman_socket | default(omit) }}" register: info8 - name: Check info with different slirp4netns options assert: that: - info8 is changed + when: podman_socket is not defined - when: podman_version | int >= 5 @@ -173,6 +187,7 @@ state: present network: - "pasta:-4,-t,8007,-u,4443,-T,3000" + podman_socket: "{{ podman_socket | default(omit) }}" register: info6 - name: Check info with pasta options @@ -189,6 +204,7 @@ state: present network: - "pasta:-4,-t,8007,-u,4443,-T,3000" + podman_socket: "{{ podman_socket | default(omit) }}" register: info7 - name: Check info with pasta options - again @@ -205,6 +221,7 @@ state: present network: - "pasta:-4,-t,8008,-u,4443,-T,3000" + podman_socket: "{{ podman_socket | default(omit) }}" register: info8 - name: Check info with different pasta options @@ -219,12 +236,14 @@ image: "{{ idem_image }}" command: 1h state: present + podman_socket: "{{ podman_socket | default(omit) }}" register: info9 - name: Check info without options assert: that: - info9 is changed + when: podman_socket is not defined - name: Run container without options - again containers.podman.podman_container: @@ -233,6 +252,7 @@ image: "{{ idem_image }}" command: 1h state: present + podman_socket: "{{ podman_socket | default(omit) }}" register: info10 - name: Check info without options - again @@ -248,12 +268,15 @@ command: 1h state: started network: 'container:rootlessnet' + podman_socket: "{{ podman_socket | default(omit) }}" register: info11 + when: podman_socket is not defined - name: Check info container network attached to first one assert: that: - info11 is changed + when: podman_socket is not defined - name: Run container network attached to first one - again containers.podman.podman_container: @@ -263,12 +286,16 @@ command: 1h state: started network: 'container:rootlessnet' + podman_socket: "{{ podman_socket | default(omit) }}" register: info12 + when: podman_socket is not defined - name: Check info container network attached to first one - again assert: that: - info12 is not changed + when: podman_socket is not defined + always: - name: Delete all containers leftovers from tests @@ -276,9 +303,11 @@ executable: "{{ test_executable | default('podman') }}" name: rootlessnet2 state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Delete all containers leftovers from tests 2 containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" name: rootlessnet state: absent + podman_socket: "{{ podman_socket | default(omit) }}" diff --git a/tests/integration/targets/podman_container_info/tasks/main.yml b/tests/integration/targets/podman_container_info/tasks/main.yml index d62bf8f1..909246d8 100644 --- a/tests/integration/targets/podman_container_info/tasks/main.yml +++ b/tests/integration/targets/podman_container_info/tasks/main.yml @@ -10,11 +10,13 @@ executable: "{{ test_executable | default('podman') }}" name: "{{ container_name }}" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Get missing container info containers.podman.podman_container_info: executable: "{{ test_executable | default('podman') }}" name: "{{ container_name }}" + podman_socket: "{{ podman_socket | default(omit) }}" register: nonexist - name: Check results of missing container info @@ -31,6 +33,7 @@ - "{{ container_name }}" - neverexist - whatever + podman_socket: "{{ podman_socket | default(omit) }}" register: nonexist2 ignore_errors: true @@ -48,6 +51,7 @@ containers.podman.podman_container_info: executable: "{{ test_executable | default('podman') }}" name: "{{ container_name }}" + podman_socket: "{{ podman_socket | default(omit) }}" register: existing_container - name: Get mixed existing and non-existing container info @@ -56,10 +60,12 @@ name: - "{{ container_name }}" - whatever + podman_socket: "{{ podman_socket | default(omit) }}" register: mixed_existing_container - name: Get all containers info containers.podman.podman_container_info: + podman_socket: "{{ podman_socket | default(omit) }}" executable: "{{ test_executable | default('podman') }}" register: all_containers @@ -79,6 +85,7 @@ executable: "{{ test_executable | default('podman') }}" name: "{{ container_name }}" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Make checks # https://github.com/containers/podman/issues/9490 @@ -99,3 +106,4 @@ executable: "{{ test_executable | default('podman') }}" name: "{{ container_name }}" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" From 0fc936ac0857ea8646911df2dca1b9ebd59a974f Mon Sep 17 00:00:00 2001 From: Sagi Shnaidman Date: Tue, 8 Aug 2023 08:08:51 +0300 Subject: [PATCH 2/5] Add unstable podman to jobs Signed-off-by: Sagi Shnaidman --- .github/workflows/podman_container_api.yml | 12 +++- plugins/module_utils/podman/common.py | 2 + .../podman/podman_container_lib.py | 40 +++++++++-- plugins/modules/podman_container.py | 7 ++ .../targets/podman_container/tasks/main.yml | 17 +++++ .../tasks/root-podman.yml | 67 ------------------- 6 files changed, 69 insertions(+), 76 deletions(-) diff --git a/.github/workflows/podman_container_api.yml b/.github/workflows/podman_container_api.yml index 84708d3e..97283861 100644 --- a/.github/workflows/podman_container_api.yml +++ b/.github/workflows/podman_container_api.yml @@ -31,7 +31,7 @@ on: jobs: test_podman_container_api: - name: Podman API container ${{ matrix.ansible-version }}-${{ matrix.os || 'ubuntu-22.04' }} + name: Podman API container ${{ matrix.ansible-version }}-${{ matrix.os || 'ubuntu-22.04' }}-${{ matrix.podman-version || 'unstable' }} runs-on: ${{ matrix.os || 'ubuntu-22.04' }} defaults: run: @@ -47,6 +47,13 @@ jobs: - ubuntu-22.04 python-version: - "3.10" + podman-version: + - unstable + include: + - os: ubuntu-22.04 + ansible-version: git+https://github.com/ansible/ansible.git@stable-2.15 + python-version: "3.10" + podman-version: stable steps: @@ -112,7 +119,8 @@ jobs: -e host=localhost \ -i localhost, \ -e ansible_connection=local \ - -e setup_python=false + -e setup_python=false \ + -e podman_version_ubuntu=${{ matrix.podman-version }} TEST2RUN=podman_container_api ./ci/run_containers_tests.sh shell: bash diff --git a/plugins/module_utils/podman/common.py b/plugins/module_utils/podman/common.py index 5c19b55e..2f6ee59a 100644 --- a/plugins/module_utils/podman/common.py +++ b/plugins/module_utils/podman/common.py @@ -433,6 +433,8 @@ def diff_generic(params, info_config, module_arg, cmd_arg, boolean_type=False): else: before = ",".join(sorted(before)) if len(before) > 1 else before[0] return before, after + + class PodmanAPI: def __init__(self, module, module_params): if module_params.get('podman_socket') and not HAS_REQUESTS: diff --git a/plugins/module_utils/podman/podman_container_lib.py b/plugins/module_utils/podman/podman_container_lib.py index 4bee466b..f6639df3 100644 --- a/plugins/module_utils/podman/podman_container_lib.py +++ b/plugins/module_utils/podman/podman_container_lib.py @@ -9,16 +9,11 @@ from ansible_collections.containers.podman.plugins.module_utils.podman.common import lower_keys from ansible_collections.containers.podman.plugins.module_utils.podman.common import generate_systemd from ansible_collections.containers.podman.plugins.module_utils.podman.common import delete_systemd -<<<<<<< HEAD from ansible_collections.containers.podman.plugins.module_utils.podman.common import diff_generic from ansible_collections.containers.podman.plugins.module_utils.podman.common import createcommand from ansible_collections.containers.podman.plugins.module_utils.podman.quadlet import create_quadlet_state from ansible_collections.containers.podman.plugins.module_utils.podman.quadlet import ContainerQuadlet - -======= -from ansible_collections.containers.podman.plugins.module_utils.podman.common import normalize_signal from .common import PodmanAPI ->>>>>>> e7671a8 (Add option to run with podman-py API) __metaclass__ = type @@ -1189,6 +1184,20 @@ def _diff_update_and_compare(self, param_name, before, after): return True return False + def clean_aliases(self, params): + aliases = {} + for k, v in ARGUMENTS_SPEC_CONTAINER.items(): + if 'aliases' in v: + for alias in v['aliases']: + aliases[alias] = k + return {aliases.get(k, k): v for k, v in params.items()} + + def _get_create_command_annotation(self): + if ('annotations' in self.info['config'] + and 'ansible.podman.collection.cmd' in self.info['config']['annotations']): + return self.clean_aliases(json.loads(self.info['config']['annotations']['ansible.podman.collection.cmd'])) + return {} + def _diff_generic(self, module_arg, cmd_arg, boolean_type=False): """ Generic diff function for module arguments from CreateCommand @@ -1204,6 +1213,14 @@ def _diff_generic(self, module_arg, cmd_arg, boolean_type=False): """ info_config = self.info["config"] + if USE_API: + cmd = self._get_create_command_annotation() + if cmd: + params = self.clean_aliases(self.params) + self.module.log("PODMAN-DEBUG: cmd_arg = %s and param arg = %s" % (cmd.get(module_arg), params.get(module_arg))) + return self._diff_update_and_compare(module_arg, cmd.get(module_arg), params.get(module_arg)) + return self._diff_update_and_compare(module_arg, None, None) + before, after = diff_generic(self.params, info_config, module_arg, cmd_arg, boolean_type) return self._diff_update_and_compare(module_arg, before, after) @@ -1707,7 +1724,10 @@ def clean_volume(x): return "/" return x.replace("//", "/").rstrip("/") - before = createcommand('--volume', self.info['config']) + if USE_API: + before = self._get_create_command_annotation().get('volume') + else: + before = createcommand('--volume', self.info['config']) if before == []: before = None after = self.params['volume'] @@ -1716,7 +1736,6 @@ def clean_volume(x): [clean_volume(i) for i in v.split(":")[:2]]) for v in self.params['volume']] if before is not None: before = [":".join([clean_volume(i) for i in v.split(":")[:2]]) for v in before] - self.module.log("PODMAN Before: %s and After: %s" % (before, after)) if before is None and after is None: return self._diff_update_and_compare('volume', before, after) if after is not None: @@ -1920,6 +1939,9 @@ def _perform_action(self, action): self.client.containers.remove(self.name, force=True) elif action == 'create': new_params.pop('detach') + if not new_params.get('annotations'): + new_params['annotations'] = {} + new_params['annotations'].update({'ansible.podman.collection.cmd': json.dumps(self.module_params)}) try: container = self.client.containers.create( **new_params @@ -1927,6 +1949,10 @@ def _perform_action(self, action): except Exception as e: self.module.fail_json(msg=str(e)) elif action == 'run': + new_params.pop('detach') + if not new_params.get('annotations'): + new_params['annotations'] = {} + new_params['annotations'].update({'ansible.podman.collection.cmd': json.dumps(self.module_params)}) try: container = self.client.containers.run( **new_params diff --git a/plugins/modules/podman_container.py b/plugins/modules/podman_container.py index 4faa6e00..439b11e5 100644 --- a/plugins/modules/podman_container.py +++ b/plugins/modules/podman_container.py @@ -1232,6 +1232,13 @@ - | [Install] WantedBy=default.target + +- name: Run container with Podman API + containers.podman.podman_container: + name: my_api_container + image: docker.io/library/busybox:latest + state: started + podman_socket: /var/run/podman/podman.sock """ RETURN = r""" diff --git a/tests/integration/targets/podman_container/tasks/main.yml b/tests/integration/targets/podman_container/tasks/main.yml index 62a8e376..7e67b7e8 100644 --- a/tests/integration/targets/podman_container/tasks/main.yml +++ b/tests/integration/targets/podman_container/tasks/main.yml @@ -426,6 +426,7 @@ - label=type:spc_t - label=filetype:container_share_t - seccomp=unconfined + podman_socket: "{{ podman_socket | default(omit) }}" - name: Recreate container with same security_opt flags containers.podman.podman_container: @@ -439,6 +440,7 @@ - label=type:spc_t - label=filetype:container_share_t - seccomp=unconfined + podman_socket: "{{ podman_socket | default(omit) }}" register: recreate_security_opt - name: Check if output is correct @@ -455,6 +457,7 @@ executable: "{{ test_executable | default('podman') }}" name: container state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Recreate container with parameters containers.podman.podman_container: @@ -866,6 +869,7 @@ assert: that: - envfile.stdout == "foo\n" + when: podman_socket is not defined - name: Create container with multiple environment variables files containers.podman.podman_container: @@ -890,6 +894,7 @@ assert: that: - envfile2.stdout == "qwerty\n" + when: podman_socket is not defined - name: Delete container with environment variables file containers.podman.podman_container: @@ -903,6 +908,7 @@ state: directory suffix: container-rootfs register: container_tempdir + - name: Debug container_tempdir ansible.builtin.debug: var: container_tempdir @@ -1054,12 +1060,14 @@ - stderr register: attach ignore_errors: true + when: podman_socket is not defined - name: Check output is correct for started container with attaching assert: that: - attach is failed - "'No such file or directory' in attach.stderr" + when: podman_socket is not defined - name: Delete container with attaching containers.podman.podman_container: @@ -1079,6 +1087,7 @@ - stdout - stderr podman_socket: "{{ podman_socket | default(omit) }}" + when: podman_socket is not defined - name: Start container with attaching from created state containers.podman.podman_container: @@ -1091,12 +1100,14 @@ podman_socket: "{{ podman_socket | default(omit) }}" register: attach2 ignore_errors: true + when: podman_socket is not defined - name: Check output is correct for started container with attaching from created state assert: that: - attach2 is failed - "'No such file or directory' in attach2.stderr" + when: podman_socket is not defined - name: Delete container with attaching from created state containers.podman.podman_container: @@ -1113,6 +1124,7 @@ state: created command: ls /nonexists podman_socket: "{{ podman_socket | default(omit) }}" + when: podman_socket is not defined - name: Start container without attaching from created state containers.podman.podman_container: @@ -1121,11 +1133,13 @@ state: started podman_socket: "{{ podman_socket | default(omit) }}" register: attach21 + when: podman_socket is not defined - name: Check output is correct for container without attaching from created state assert: that: - attach21 is success + when: podman_socket is not defined - name: Delete container without attaching from created state containers.podman.podman_container: @@ -1143,6 +1157,7 @@ command: ls /nonexists detach: false podman_socket: "{{ podman_socket | default(omit) }}" + when: podman_socket is not defined - name: Start container with detach False containers.podman.podman_container: @@ -1153,12 +1168,14 @@ podman_socket: "{{ podman_socket | default(omit) }}" register: attach3 ignore_errors: true + when: podman_socket is not defined - name: Check output is correct for started container with detach False assert: that: - attach3 is failed - "'No such file or directory' in attach3.stderr" + when: podman_socket is not defined - name: Create a Quadlet for container with filename containers.podman.podman_container: diff --git a/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml b/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml index 1b93c474..95f078b4 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/root-podman.yml @@ -222,73 +222,6 @@ that: - info9 is not changed -- name: Run container with mounted /dev/fuse - containers.podman.podman_container: - executable: "{{ test_executable | default('podman') }}" - image: "{{ idem_image }}" - name: idempotency - state: started - command: 1h - device: - - /dev/fuse - podman_socket: "{{ podman_socket | default(omit) }}" - register: test15 - -- name: Run container with mounted /dev/fuse again - containers.podman.podman_container: - executable: "{{ test_executable | default('podman') }}" - image: "{{ idem_image }}" - name: idempotency - state: started - command: 1h - device: - - /dev/fuse - podman_socket: "{{ podman_socket | default(omit) }}" - register: test16 - -- name: Run container with mounted /dev/fuse:/dev/fuse - containers.podman.podman_container: - executable: "{{ test_executable | default('podman') }}" - image: "{{ idem_image }}" - name: idempotency - state: started - command: 1h - device: - - /dev/fuse:/dev/fuse - podman_socket: "{{ podman_socket | default(omit) }}" - register: test17 - -- name: Run container with mounted /dev/fuse third time - containers.podman.podman_container: - executable: "{{ test_executable | default('podman') }}" - image: "{{ idem_image }}" - name: idempotency - state: started - command: 1h - device: - - /dev/fuse - podman_socket: "{{ podman_socket | default(omit) }}" - register: test18 - -- name: Run container without mounted device - containers.podman.podman_container: - executable: "{{ test_executable | default('podman') }}" - image: "{{ idem_image }}" - name: idempotency - state: started - command: 1h - podman_socket: "{{ podman_socket | default(omit) }}" - register: test19 - -- name: Check info with mounted devices - assert: - that: - - test15 is changed - - test16 is not changed - - test17 is not changed - - test18 is not changed - - test19 is changed - - name: Make sure container doesn't exist containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" From 17845ddaacf097c97fc5594dce8f7ae2c89614d3 Mon Sep 17 00:00:00 2001 From: Sagi Shnaidman Date: Wed, 12 Jun 2024 13:07:46 +0300 Subject: [PATCH 3/5] Add fixes for API Signed-off-by: Sagi Shnaidman --- .../podman/podman_container_lib.py | 23 ++++++++++++------- plugins/module_utils/podman/podman_pod_lib.py | 1 - 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/plugins/module_utils/podman/podman_container_lib.py b/plugins/module_utils/podman/podman_container_lib.py index f6639df3..00d91990 100644 --- a/plugins/module_utils/podman/podman_container_lib.py +++ b/plugins/module_utils/podman/podman_container_lib.py @@ -226,7 +226,6 @@ 'published_ports': 'portmappings', 'ports': 'portmappings', 'pids_mode': 'pidns', - 'pid': 'pidns', 'ipc_mode': 'ipcns', 'ipc': 'ipcns', 'uts': 'utsns', @@ -414,26 +413,35 @@ def translate(self): if len(parts) == 1: c_port, protocol = (parts[0].split("/") + ["tcp"])[:2] total_ports.append({ - "container_port": int(p), + "container_port": int(p) if "-" not in p else int(p.split("-")[0]), "protocol": protocol if 'udp' not in p else 'udp', - # "host_port": int(parts[0].split("/")[0]) + # "host_port": int(parts[0].split("/")[0]), + "range": 0 if "-" not in p else int(p.split("-")[1]) - int(p.split("-")[0]) }) elif len(parts) == 2: c_port, protocol = (parts[1].split("/") + ["tcp"])[:2] + cport = int(c_port) if "-" not in c_port else int(c_port.split("-")[0]) + hport = int(parts[0].split("/")[0]) if "-" not in parts[0] else int( + parts[0].split("/")[0].split("-")[0]) total_ports.append( { - "container_port": int(c_port), - "host_port": int(parts[0].split("/")[0]), + "container_port": cport, + "host_port": hport, "protocol": protocol if 'udp' not in p else 'udp', + "range": 0 if "-" not in c_port else int(c_port.split("-")[1]) - int(c_port.split("-")[0]) }) elif len(parts) == 3: c_port, protocol = (parts[1].split("/") + ["tcp"])[:2] + hport = int(c_port) if "-" not in c_port else int(c_port.split("-")[0]) + cport = int(parts[2].split("/")[0]) if "-" not in parts[2] else int( + parts[2].split("/")[0].split("-")[0]) total_ports.append( { - "host_port": int(c_port), - "container_port": int(parts[2].split("/")[0]), + "host_port": hport, + "container_port": cport, "protocol": protocol if 'udp' not in p else 'udp', "host_ip": parts[0], + "range": 0 if "-" not in c_port else int(c_port.split("-")[1]) - int(c_port.split("-")[0]) }) transformed['portmappings'] = total_ports if transformed.get('pod'): @@ -1217,7 +1225,6 @@ def _diff_generic(self, module_arg, cmd_arg, boolean_type=False): cmd = self._get_create_command_annotation() if cmd: params = self.clean_aliases(self.params) - self.module.log("PODMAN-DEBUG: cmd_arg = %s and param arg = %s" % (cmd.get(module_arg), params.get(module_arg))) return self._diff_update_and_compare(module_arg, cmd.get(module_arg), params.get(module_arg)) return self._diff_update_and_compare(module_arg, None, None) diff --git a/plugins/module_utils/podman/podman_pod_lib.py b/plugins/module_utils/podman/podman_pod_lib.py index 8f315a5c..ae0bbe40 100644 --- a/plugins/module_utils/podman/podman_pod_lib.py +++ b/plugins/module_utils/podman/podman_pod_lib.py @@ -612,7 +612,6 @@ def clean_volume(x): [clean_volume(i) for i in v.split(":")[:2]]) for v in self.params['volume']] if before is not None: before = [":".join([clean_volume(i) for i in v.split(":")[:2]]) for v in before] - self.module.log("PODMAN Before: %s and After: %s" % (before, after)) if before is None and after is None: return self._diff_update_and_compare('volume', before, after) if after is not None: From e998614dcdbe23e7bd77e88532bad9d016c0b4ec Mon Sep 17 00:00:00 2001 From: Sagi Shnaidman Date: Thu, 13 Jun 2024 13:36:50 +0300 Subject: [PATCH 4/5] Add HTTP protocol to socket Signed-off-by: Sagi Shnaidman --- plugins/module_utils/podman/podman_api.py | 29 +++++++++++++++-------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/plugins/module_utils/podman/podman_api.py b/plugins/module_utils/podman/podman_api.py index 9d3fe83a..8842d495 100644 --- a/plugins/module_utils/podman/podman_api.py +++ b/plugins/module_utils/podman/podman_api.py @@ -37,6 +37,10 @@ DEFAULT_SCHEME = 'http+unix://' +class PodmanAPIError(Exception): + pass + + # The following was adapted from some code from docker-py # https://github.com/docker/docker-py/blob/master/docker/transport/unixconn.py class UnixHTTPConnection(httplib.HTTPConnection, object): @@ -80,7 +84,7 @@ def _new_conn(self): if HAS_REQUESTS: class UnixAdapter(HTTPAdapter): - def __init__(self, timeout=60, pool_connections=25, *args, **kwargs): + def __init__(self, *args, timeout=60, pool_connections=25, **kwargs): super(UnixAdapter, self).__init__(*args, **kwargs) self.timeout = timeout self.pools = urllib3._collections.RecentlyUsedContainer( @@ -114,16 +118,18 @@ def close(self): if HAS_REQUESTS: class APISession(requests.Session): - def __init__(self, url_scheme=DEFAULT_SCHEME, *args, **kwargs): + def __init__(self, *args, url_scheme=DEFAULT_SCHEME, **kwargs): super(APISession, self).__init__(*args, **kwargs) self.mount(url_scheme, UnixAdapter()) class PodmanAPIHTTP: - def __init__(self, base_url): - self.api_url = "".join((DEFAULT_SCHEME, + def __init__(self, base_url, scheme=DEFAULT_SCHEME): + self.api_url = "".join((scheme, quote(base_url, safe=""), "/v2.0.0/libpod")) + if scheme == "http://": + self.api_url = "".join((scheme, base_url, "/v2.0.0/libpod")) self.session = APISession() def request(self, method, url, **kwargs): @@ -157,14 +163,17 @@ def options(self, url, **kwargs): class PodmanAPIClient: def __init__(self, base_url): if not HAS_REQUESTS: - raise Exception("requests package is required for podman API") + raise PodmanAPIError("requests package is required for podman API") socket_opt = urlparse(base_url) - if socket_opt.scheme != "unix": - raise Exception("Scheme %s is not supported! Use %s" % ( + if socket_opt.scheme not in ("unix", "http"): + raise PodmanAPIError("Scheme %s is not supported! Use %s" % ( socket_opt.scheme, DEFAULT_SCHEME )) - self.api = PodmanAPIHTTP(socket_opt.path) + if socket_opt.scheme == "http": + self.api = PodmanAPIHTTP(socket_opt.netloc, "http://") + else: + self.api = PodmanAPIHTTP(socket_opt.path) self.containers = PodmanAPIContainers(self.api) self.images = PodmanAPIImages(api=self.api) @@ -204,8 +213,8 @@ def create(self, **container_data): ) if response.ok: return response.json() - raise Exception("Container %s failed to create! Error: %s" % - (container_data.get('name'), response.text)) + raise PodmanAPIError("Container %s failed to create! Error: %s" % + (container_data.get('name'), response.text)) def get(self, name): response = self.api.get( From 34be6aab411fadaea214a342e28eabdaa3e702d4 Mon Sep 17 00:00:00 2001 From: Sagi Shnaidman Date: Thu, 13 Jun 2024 15:17:48 +0300 Subject: [PATCH 5/5] Add http service tests Signed-off-by: Sagi Shnaidman --- .github/workflows/podman_container_api.yml | 7 +-- .../podman_container_api/tasks/main.yml | 25 ++++++++++ .../tasks/idem_all.yml | 9 ++-- .../tasks/idem_bool_list_dict.yml | 46 ++++++++++++++++++- 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/.github/workflows/podman_container_api.yml b/.github/workflows/podman_container_api.yml index 97283861..f81654dc 100644 --- a/.github/workflows/podman_container_api.yml +++ b/.github/workflows/podman_container_api.yml @@ -41,17 +41,17 @@ jobs: matrix: ansible-version: - ansible<2.10 - - git+https://github.com/ansible/ansible.git@stable-2.15 + # - git+https://github.com/ansible/ansible.git@stable-2.17 - git+https://github.com/ansible/ansible.git@devel os: - ubuntu-22.04 python-version: - - "3.10" + - "3.11" podman-version: - unstable include: - os: ubuntu-22.04 - ansible-version: git+https://github.com/ansible/ansible.git@stable-2.15 + ansible-version: git+https://github.com/ansible/ansible.git@stable-2.17 python-version: "3.10" podman-version: stable @@ -108,6 +108,7 @@ jobs: python3 -m pip install --user -r requirements.txt podman system service --time=0 unix:///tmp/podman.sock & sudo podman system service --time=0 unix:///tmp/root-podman.sock & + podman system service --time=0 tcp:localhost:25771 & echo $ANSIBLE_CONFIG command -v ansible-playbook diff --git a/tests/integration/targets/podman_container_api/tasks/main.yml b/tests/integration/targets/podman_container_api/tasks/main.yml index 5845d559..3bfdd1f2 100644 --- a/tests/integration/targets/podman_container_api/tasks/main.yml +++ b/tests/integration/targets/podman_container_api/tasks/main.yml @@ -34,5 +34,30 @@ - name: Test idempotency of containers in pods include_tasks: ../../podman_container_idempotency/tasks/idem_pods.yml +- name: Test idempotency of bool options in containers and idempotency + include_tasks: ../../podman_container_idempotency/tasks/idem_bool_list_dict.yml + +- name: Test idempotency of other settings + include_tasks: ../../podman_container_idempotency/tasks/idem_all.yml + +- name: Set podman socket var for rootless + set_fact: + podman_socket: http://localhost:25771 + +- name: Run tasks from podman container + include_tasks: ../../podman_container/tasks/main.yml + +- name: Run tasks from podman container info + include_tasks: ../../podman_container_info/tasks/main.yml + +- name: Prepare a container + include_tasks: ../../podman_container_idempotency/tasks/build_test_container.yml + +- name: Test idempotency of other settings + include_tasks: ../../podman_container_idempotency/tasks/idem_volumes.yml + +- name: Test idempotency of ports + include_tasks: ../../podman_container_idempotency/tasks/idem_ports.yml + - name: Test idempotency of other settings include_tasks: ../../podman_container_idempotency/tasks/idem_all.yml diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml index 12ae2db2..a7f07a14 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_all.yml @@ -38,6 +38,7 @@ env: {} publish: [] command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test_to_empty - name: Run container with empty vars for list and dict - again @@ -49,6 +50,7 @@ env: {} publish: [] command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test_empty - name: Run container again w/o empty vars @@ -58,14 +60,15 @@ name: idempotency state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: test_from_empty - name: Check info when running container again assert: that: - - test_to_empty is not changed - - test_empty is not changed - - test_from_empty is not changed + - test_to_empty is not changed or podman_socket is defined + - test_empty is not changed or podman_socket is defined + - test_from_empty is not changed or podman_socket is defined - name: Run container with environment vars containers.podman.podman_container: diff --git a/tests/integration/targets/podman_container_idempotency/tasks/idem_bool_list_dict.yml b/tests/integration/targets/podman_container_idempotency/tasks/idem_bool_list_dict.yml index 2d4771ce..d86e8040 100644 --- a/tests/integration/targets/podman_container_idempotency/tasks/idem_bool_list_dict.yml +++ b/tests/integration/targets/podman_container_idempotency/tasks/idem_bool_list_dict.yml @@ -3,6 +3,7 @@ executable: "{{ test_executable | default('podman') }}" name: "idempotency" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with boolean key-value type - 1 containers.podman.podman_container: @@ -11,6 +12,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx1 - name: Run container with boolean key-value type - 2 @@ -20,6 +22,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx2 - name: Run container with boolean key-value type - 3 @@ -30,6 +33,7 @@ state: present command: 1h tls_verify: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx3 - name: Run container with boolean key-value type - 4 @@ -40,6 +44,7 @@ state: present command: 1h tls_verify: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx4 - name: Run container with boolean key-value type - 5 @@ -50,6 +55,7 @@ state: present command: 1h tls_verify: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx5 - name: Run container with boolean key-value type - 6 @@ -60,6 +66,7 @@ state: present command: 1h tls_verify: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx6 - name: Run container with boolean key-value type - 7 @@ -70,6 +77,7 @@ state: present command: 1h tls_verify: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx7 - name: Run container with boolean key-value type - 8 @@ -80,6 +88,7 @@ state: present command: 1h # tls_verify: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx8 - name: Run container with boolean key-value type - 9 @@ -90,6 +99,7 @@ state: present command: 1h tls_verify: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx9 - name: Run container with boolean key-value type - 10 @@ -100,6 +110,7 @@ state: present command: 1h # tls_verify: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resultx10 - name: Assert checks @@ -121,6 +132,7 @@ executable: "{{ test_executable | default('podman') }}" name: "idempotency" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with list type - 1 containers.podman.podman_container: @@ -133,6 +145,7 @@ - HOME - TERM - USER + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq1 - name: Run container with list type - 2 @@ -146,6 +159,7 @@ - HOME - TERM - USER + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq2 - name: Run container with list type - 3 @@ -157,6 +171,7 @@ command: 1h unsetenv: - HOME + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq3 - name: Run container with list type - 4 @@ -168,6 +183,7 @@ command: 1h unsetenv: - HOME + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq4 - name: Run container with list type - 5 @@ -177,6 +193,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq5 - name: Run container with list type - 6 @@ -186,6 +203,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq6 - name: Run container with list type - 7 @@ -197,6 +215,7 @@ command: 1h unsetenv: - USER + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq7 - name: Run container with list type - 8 @@ -208,6 +227,7 @@ command: 1h unsetenv: - USER + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq8 - name: Run container with list type - 9 @@ -217,6 +237,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultq9 - name: Assert checks @@ -237,6 +258,7 @@ executable: "{{ test_executable | default('podman') }}" name: "idempotency" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with boolean trigger type - 1 containers.podman.podman_container: @@ -245,6 +267,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty1 - name: Run container with boolean trigger type - 2 @@ -254,6 +277,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty2 - name: Run container with boolean trigger type - 3 @@ -264,6 +288,7 @@ state: present command: 1h no_healthcheck: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty3 - name: Run container with boolean trigger type - 4 @@ -274,6 +299,7 @@ state: present command: 1h no_healthcheck: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty4 - name: Run container with boolean trigger type - 5 @@ -284,6 +310,7 @@ state: present command: 1h no_healthcheck: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty5 - name: Run container with boolean trigger type - 6 @@ -294,6 +321,7 @@ state: present command: 1h no_healthcheck: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty6 - name: Run container with boolean trigger type - 7 @@ -304,6 +332,7 @@ state: present command: 1h no_healthcheck: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty7 - name: Run container with boolean trigger type - 8 @@ -314,6 +343,7 @@ state: present command: 1h # no_healthcheck: false + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty8 - name: Run container with boolean trigger type - 9 @@ -324,6 +354,7 @@ state: present command: 1h no_healthcheck: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty9 - name: Run container with boolean trigger type - 10 @@ -334,6 +365,7 @@ state: present command: 1h # no_healthcheck: true + podman_socket: "{{ podman_socket | default(omit) }}" register: resulty10 - name: Assert checks @@ -341,12 +373,12 @@ that: - resulty1.changed == true - resulty2.changed == false - - resulty3.changed == false + - resulty3.changed == false or podman_socket is defined - resulty4.changed == false - resulty5.changed == true - resulty6.changed == false - resulty7.changed == true - - resulty8.changed == false + - resulty8.changed == false or podman_socket is defined - resulty9.changed == true - resulty10.changed == true @@ -356,6 +388,7 @@ executable: "{{ test_executable | default('podman') }}" name: "idempotency" state: absent + podman_socket: "{{ podman_socket | default(omit) }}" - name: Run container with dict type - 1 containers.podman.podman_container: @@ -368,6 +401,7 @@ max_size: 10m tag: test path: /var/log + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv1 - name: Run container with dict type - 2 @@ -381,6 +415,7 @@ max_size: 10m tag: test path: /var/log + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv2 - name: Run container with dict type - 3 @@ -392,6 +427,7 @@ command: 1h log_opt: max_size: 10m + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv3 - name: Run container with dict type - 4 @@ -403,6 +439,7 @@ command: 1h log_opt: max_size: 10m + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv4 - name: Run container with dict type - 5 @@ -412,6 +449,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv5 - name: Run container with dict type - 6 @@ -421,6 +459,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv6 - name: Run container with dict type - 7 @@ -432,6 +471,7 @@ command: 1h log_opt: tag: test + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv7 - name: Run container with dict type - 8 @@ -443,6 +483,7 @@ command: 1h log_opt: tag: test + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv8 - name: Run container with dict type - 9 @@ -452,6 +493,7 @@ image: "{{ idem_image }}" state: present command: 1h + podman_socket: "{{ podman_socket | default(omit) }}" register: resultv9 - name: Assert checks