From d94f81238efc61f098d42ef3a86bc14c0128b208 Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Mon, 16 Jan 2023 14:49:01 +0100 Subject: [PATCH 1/9] added podman-prune module Signed-off-by: Roberto Alfieri --- plugins/modules/podman_prune.py | 293 ++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 plugins/modules/podman_prune.py diff --git a/plugins/modules/podman_prune.py b/plugins/modules/podman_prune.py new file mode 100644 index 00000000..0dd10e38 --- /dev/null +++ b/plugins/modules/podman_prune.py @@ -0,0 +1,293 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# Copyright (c) 2023, Roberto Alfieri + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = r""" +module: podman_prune +author: + - "Roberto Alfieri (@rebtoor)" +version_added: '1.10.0' +short_description: Allows to prune various podman objects +notes: [] +description: + - Allows to run C(podman container prune), C(podman image prune), C(podman network prune), C(podman volume prune) and C(podman system prune) +requirements: + - "Podman installed on host" +options: + executable: + description: + - Podman binary. + type: str + default: podman + container: + description: + - Whether to prune containers. + type: bool + default: false + container_filters: + description: + - A dictionary of filter values used for selecting containers to delete. + - "For example, C(until: 24h)." + - See L(the podman documentation, https://docs.podman.io/en/latest/markdown/podman-container-prune.1.html#filter-filters) + for more information on possible filters. + type: dict + image: + description: + - Whether to prune images. + type: bool + default: false + image_filters: + description: + - A dictionary of filter values used for selecting images to delete. + - "For example, C(dangling: true)." + - See L(the podman documentation,https://docs.podman.io/en/latest/markdown/podman-image-prune.1.html#filter-filters) + for more information on possible filters. + type: dict + network: + description: + - Whether to prune networks. + type: bool + default: false + network_filters: + description: + - A dictionary of filter values used for selecting networks to delete. + - See L(the podman documentation,https://docs.podman.io/en/latest/markdown/podman-network-prune.1.html#filter) + for more information on possible filters. + type: dict + system: + description: + - Wheter to prune unused pods, containers, image, networks and volume data + type: bool + default: false + system_all: + description: + - Wheter to prune all unused images, not only dangling images. + type: bool + default: false + system_volumes: + description: + - Wheter to prune volumes currently unused by any container. + type: bool + default: false + volume: + description: + - Whether to prune volumes. + type: bool + default: false + volume_filters: + description: + - A dictionary of filter values used for selecting volumes to delete. + - See L(the podman documentation,https://docs.podman.io/en/latest/markdown/podman-volume-prune.1.html#filter) + for more information on possible filters. + type: dict +""" + +EXAMPLES = r""" +- name: Prune containers older than 24h + containers.podman.podman_prune: + containers: true + containers_filters: + # only consider containers created more than 24 hours ago + until: 24h + +- name: Prune everything + containers.podman.podman_prune: + system: true + +- name: Prune everything (including non-dangling images) + containers.podman.podman_prune: + system: true + system_all: true + system_volumes: true +""" + +RETURN = r""" +# containers +containers: + description: + - List of IDs of deleted containers. + returned: I(containers) is C(true) + type: list + elements: str + sample: [] + +# images +images: + description: + - List of IDs of deleted images. + returned: I(images) is C(true) + type: list + elements: str + sample: [] + +# networks +networks: + description: + - List of IDs of deleted networks. + returned: I(networks) is C(true) + type: list + elements: str + sample: [] + +# volumes +volumes: + description: + - List of IDs of deleted volumes. + returned: I(volumes) is C(true) + type: list + elements: str + sample: [] + +# system +system: + description: + - List of ID of deleted containers, volumes, images, network and total reclaimed space + returned: I(system) is C(true) + type: list + elements: str + sample: [] +""" + + +from ansible.module_utils.basic import AnsibleModule + + +def podmanExec(module, target, filters, executable): + changed = False + command = [executable, target, 'prune', '--force'] + if filters != "" and target != "system": + command.append("--filter=") + command.append(filters) + if filters != "" and target == "system": + split_filters = filters.strip().split(" ") + for filter in split_filters: + if filter: + command.append(filter) + rc, out, err = module.run_command(command) + if out: + changed = True + if rc != 0: + module.fail_json( + msg="Error executing prune on {}: {}".format(target, err)) + return changed, out, err + + +def run_module(): + module_args = dict( + container=dict(type='bool', default=False), + container_filters=dict(type='dict'), + image=dict(type='bool', default=False), + image_filters=dict(type='dict'), + network=dict(type='bool', default=False), + network_filters=dict(type='dict'), + volume=dict(type='bool', default=False), + volume_filters=dict(type='dict'), + system=dict(type='bool', default=False), + system_all=dict(type='bool', default=False), + system_volumes=dict(type='bool', default=False), + executable=dict(type='str', default='podman') + ) + + module = AnsibleModule( + argument_spec=module_args + ) + + executable = module.get_bin_path( + module.params['executable'], required=True) + + if module.params["container"]: + target = "container" + if not module.params["container_filters"]: + filters = "" + else: + filters = module.params["container_filters"] + changed, out, err = podmanExec(module, target, filters, executable) + if not out: + containers = [] + else: + containers = out.rstrip().split("\n") + results = dict( + changed=changed, + containers=containers, + stderr=err + ) + + if module.params["network"]: + target = "network" + if not module.params["network_filters"]: + filters = "" + else: + filters = module.params["network_filters"] + changed, out, err = podmanExec(module, target, filters, executable) + if not out: + networks = [] + else: + networks = out.rstrip().split("\n") + results = dict( + changed=changed, + networks=networks, + stderr=err + ) + + if module.params["image"]: + target = "image" + if not module.params["image_filters"]: + filters = "" + else: + filters = module.params["image_filters"] + changed, out, err = podmanExec(module, target, filters, executable) + results = dict( + changed=changed, + stdout=out, + stderr=err + ) + + if module.params["volume"]: + target = "volume" + if not module.params["volume_filters"]: + filters = "" + else: + filters = module.params["volume_filters"] + changed, out, err = podmanExec(module, target, filters, executable) + if not out: + volumes = [] + else: + volumes = out.rstrip().split("\n") + results = dict( + changed=changed, + volumes=volumes, + stderr=err + ) + + if module.params["system"]: + target = "system" + filters = str() + + if module.params["system_all"]: + filters = " ".join([filters, "--all"]) + + if module.params["system_volumes"]: + filters = " ".join([filters, "--volumes"]) + + changed, out, err = podmanExec(module, target, filters, executable) + + results = dict( + changed=changed, + stdout=out, + stderr=err + ) + + module.exit_json(**results) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() From 017d40c7f23c21037b9a57c14ca047c5431df72f Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Mon, 16 Jan 2023 16:19:33 +0100 Subject: [PATCH 2/9] fix ansible-format-automatic-specification following PEP-3101 specs Signed-off-by: Roberto Alfieri --- plugins/modules/podman_prune.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/podman_prune.py b/plugins/modules/podman_prune.py index 0dd10e38..30b5919c 100644 --- a/plugins/modules/podman_prune.py +++ b/plugins/modules/podman_prune.py @@ -173,7 +173,7 @@ def podmanExec(module, target, filters, executable): changed = True if rc != 0: module.fail_json( - msg="Error executing prune on {}: {}".format(target, err)) + msg="Error executing prune on {0}: {1}".format(target, err)) return changed, out, err From 04ba1dd1fc84b7d4279feaca531915895571eca2 Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Mon, 16 Jan 2023 16:24:40 +0100 Subject: [PATCH 3/9] fix ansible-format-automatic-specification following PEP-3101 specs Signed-off-by: Roberto Alfieri --- plugins/modules/podman_prune.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/podman_prune.py b/plugins/modules/podman_prune.py index 30b5919c..bef19b68 100644 --- a/plugins/modules/podman_prune.py +++ b/plugins/modules/podman_prune.py @@ -173,7 +173,7 @@ def podmanExec(module, target, filters, executable): changed = True if rc != 0: module.fail_json( - msg="Error executing prune on {0}: {1}".format(target, err)) + msg="Error executing prune on {target}: {err}".format(target=target, err=err)) return changed, out, err From 971750501059e7a3b0ba1c2b39962d7b70352743 Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Sat, 21 Jan 2023 11:40:38 +0100 Subject: [PATCH 4/9] Removed useless run_module function Signed-off-by: Roberto Alfieri --- plugins/modules/podman_prune.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/plugins/modules/podman_prune.py b/plugins/modules/podman_prune.py index bef19b68..9e20f5e7 100644 --- a/plugins/modules/podman_prune.py +++ b/plugins/modules/podman_prune.py @@ -15,7 +15,8 @@ short_description: Allows to prune various podman objects notes: [] description: - - Allows to run C(podman container prune), C(podman image prune), C(podman network prune), C(podman volume prune) and C(podman system prune) + - Allows to run C(podman container prune), C(podman image prune), C(podman network prune), + C(podman volume prune) and C(podman system prune) requirements: - "Podman installed on host" options: @@ -33,7 +34,8 @@ description: - A dictionary of filter values used for selecting containers to delete. - "For example, C(until: 24h)." - - See L(the podman documentation, https://docs.podman.io/en/latest/markdown/podman-container-prune.1.html#filter-filters) + - See L(the podman documentation, + https://docs.podman.io/en/latest/markdown/podman-container-prune.1.html#filter-filters) for more information on possible filters. type: dict image: @@ -45,7 +47,8 @@ description: - A dictionary of filter values used for selecting images to delete. - "For example, C(dangling: true)." - - See L(the podman documentation,https://docs.podman.io/en/latest/markdown/podman-image-prune.1.html#filter-filters) + - See L(the podman documentation, + https://docs.podman.io/en/latest/markdown/podman-image-prune.1.html#filter-filters) for more information on possible filters. type: dict network: @@ -56,7 +59,8 @@ network_filters: description: - A dictionary of filter values used for selecting networks to delete. - - See L(the podman documentation,https://docs.podman.io/en/latest/markdown/podman-network-prune.1.html#filter) + - See L(the podman documentation, + https://docs.podman.io/en/latest/markdown/podman-network-prune.1.html#filter) for more information on possible filters. type: dict system: @@ -82,7 +86,8 @@ volume_filters: description: - A dictionary of filter values used for selecting volumes to delete. - - See L(the podman documentation,https://docs.podman.io/en/latest/markdown/podman-volume-prune.1.html#filter) + - See L(the podman documentation, + https://docs.podman.io/en/latest/markdown/podman-volume-prune.1.html#filter) for more information on possible filters. type: dict """ @@ -177,7 +182,7 @@ def podmanExec(module, target, filters, executable): return changed, out, err -def run_module(): +def main(): module_args = dict( container=dict(type='bool', default=False), container_filters=dict(type='dict'), @@ -285,9 +290,5 @@ def run_module(): module.exit_json(**results) -def main(): - run_module() - - if __name__ == '__main__': main() From 57aaf66e879cf52a225b44ece156f1c2e1e662bd Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Sun, 22 Jan 2023 15:48:36 +0100 Subject: [PATCH 5/9] optimized loops and command execution Signed-off-by: Roberto Alfieri --- plugins/modules/podman_prune.py | 161 +++++++++++--------------------- 1 file changed, 57 insertions(+), 104 deletions(-) diff --git a/plugins/modules/podman_prune.py b/plugins/modules/podman_prune.py index 9e20f5e7..b161fc35 100644 --- a/plugins/modules/podman_prune.py +++ b/plugins/modules/podman_prune.py @@ -7,18 +7,18 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = r""" +DOCUMENTATION = r''' module: podman_prune author: - - "Roberto Alfieri (@rebtoor)" + - 'Roberto Alfieri (@rebtoor)' version_added: '1.10.0' short_description: Allows to prune various podman objects notes: [] description: - - Allows to run C(podman container prune), C(podman image prune), C(podman network prune), + - Allows to run C(podman container prune), C(podman image prune), C(podman network prune), C(podman volume prune) and C(podman system prune) requirements: - - "Podman installed on host" + - 'Podman installed on host' options: executable: description: @@ -33,8 +33,8 @@ container_filters: description: - A dictionary of filter values used for selecting containers to delete. - - "For example, C(until: 24h)." - - See L(the podman documentation, + - 'For example, C(until: 24h).' + - See L(the podman documentation, https://docs.podman.io/en/latest/markdown/podman-container-prune.1.html#filter-filters) for more information on possible filters. type: dict @@ -46,7 +46,8 @@ image_filters: description: - A dictionary of filter values used for selecting images to delete. - - "For example, C(dangling: true)." + - 'You can also use C(dangling_only: false) to delete dangling and non-dangling images or C(external: true) + to delete images even when they are used by external containers.' - See L(the podman documentation, https://docs.podman.io/en/latest/markdown/podman-image-prune.1.html#filter-filters) for more information on possible filters. @@ -90,9 +91,9 @@ https://docs.podman.io/en/latest/markdown/podman-volume-prune.1.html#filter) for more information on possible filters. type: dict -""" +''' -EXAMPLES = r""" +EXAMPLES = r''' - name: Prune containers older than 24h containers.podman.podman_prune: containers: true @@ -109,9 +110,9 @@ system: true system_all: true system_volumes: true -""" +''' -RETURN = r""" +RETURN = r''' # containers containers: description: @@ -156,30 +157,49 @@ type: list elements: str sample: [] -""" +''' from ansible.module_utils.basic import AnsibleModule def podmanExec(module, target, filters, executable): - changed = False command = [executable, target, 'prune', '--force'] - if filters != "" and target != "system": - command.append("--filter=") - command.append(filters) - if filters != "" and target == "system": - split_filters = filters.strip().split(" ") - for filter in split_filters: - if filter: - command.append(filter) + if filters: + if target != 'system': + for common_filter in filters: + if isinstance(filters[common_filter], dict): + dict_filters = filters[common_filter] + for single_filter in dict_filters: + command.append('--filter={label}={key}={value}'.format(label=common_filter, key=single_filter, + value=dict_filters[single_filter])) + else: + if target == 'image' and (common_filter in ('dangling_only', 'external')): + if common_filter == 'dangling_only' and not filters['dangling_only']: + command.append('-a') + if common_filter == 'external' and filters['external']: + command.append('--external') + else: + command.append('--filter={label}={value}'.format(label=common_filter, + value=filters[common_filter])) + else: + for system_filter in filters: + command.append(filters[system_filter]) + rc, out, err = module.run_command(command) if out: changed = True + else: + changed = False if rc != 0: module.fail_json( - msg="Error executing prune on {target}: {err}".format(target=target, err=err)) - return changed, out, err + msg='Error executing prune on {target}: {err}'.format(target=target, err=err)) + + return { + "changed": changed, + "stdout": out, + "stderr": err + } def main(): @@ -205,87 +225,20 @@ def main(): executable = module.get_bin_path( module.params['executable'], required=True) - if module.params["container"]: - target = "container" - if not module.params["container_filters"]: - filters = "" - else: - filters = module.params["container_filters"] - changed, out, err = podmanExec(module, target, filters, executable) - if not out: - containers = [] - else: - containers = out.rstrip().split("\n") - results = dict( - changed=changed, - containers=containers, - stderr=err - ) - - if module.params["network"]: - target = "network" - if not module.params["network_filters"]: - filters = "" - else: - filters = module.params["network_filters"] - changed, out, err = podmanExec(module, target, filters, executable) - if not out: - networks = [] - else: - networks = out.rstrip().split("\n") - results = dict( - changed=changed, - networks=networks, - stderr=err - ) - - if module.params["image"]: - target = "image" - if not module.params["image_filters"]: - filters = "" - else: - filters = module.params["image_filters"] - changed, out, err = podmanExec(module, target, filters, executable) - results = dict( - changed=changed, - stdout=out, - stderr=err - ) - - if module.params["volume"]: - target = "volume" - if not module.params["volume_filters"]: - filters = "" - else: - filters = module.params["volume_filters"] - changed, out, err = podmanExec(module, target, filters, executable) - if not out: - volumes = [] - else: - volumes = out.rstrip().split("\n") - results = dict( - changed=changed, - volumes=volumes, - stderr=err - ) - - if module.params["system"]: - target = "system" - filters = str() - - if module.params["system_all"]: - filters = " ".join([filters, "--all"]) - - if module.params["system_volumes"]: - filters = " ".join([filters, "--volumes"]) - - changed, out, err = podmanExec(module, target, filters, executable) - - results = dict( - changed=changed, - stdout=out, - stderr=err - ) + for target, filters in ( + ('container', 'container_filters'), ('image', 'image_filters'), ('network', 'network_filters'), + ('volume', 'volume_filters')): + if module.params[target]: + results = podmanExec(module, target, module.params[filters], executable) + + if module.params['system']: + target = 'system' + system_filters = {} + if module.params['system_all']: + system_filters['system_all'] = '--all' + if module.params['system_volumes']: + system_filters['system_volumes'] = '--volumes' + results = podmanExec(module, target, system_filters, executable) module.exit_json(**results) From 6493cb4988c8f2ebc42a685ba0a42e4d0e7c3595 Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Sun, 29 Jan 2023 18:25:23 +0100 Subject: [PATCH 6/9] created filtersPrepare function Signed-off-by: Roberto Alfieri --- plugins/modules/podman_prune.py | 54 ++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/plugins/modules/podman_prune.py b/plugins/modules/podman_prune.py index b161fc35..0ff4bbea 100644 --- a/plugins/modules/podman_prune.py +++ b/plugins/modules/podman_prune.py @@ -163,34 +163,38 @@ from ansible.module_utils.basic import AnsibleModule -def podmanExec(module, target, filters, executable): - command = [executable, target, 'prune', '--force'] - if filters: - if target != 'system': - for common_filter in filters: - if isinstance(filters[common_filter], dict): - dict_filters = filters[common_filter] - for single_filter in dict_filters: - command.append('--filter={label}={key}={value}'.format(label=common_filter, key=single_filter, - value=dict_filters[single_filter])) +def filtersPrepare(target, filters): + filter_out = [] + if target == 'system': + for system_filter in filters: + filter_out.append(filters[system_filter]) + else: + for common_filter in filters: + if isinstance(filters[common_filter], dict): + dict_filters = filters[common_filter] + for single_filter in dict_filters: + filter_out.append('--filter={label}={key}={value}'.format(label=common_filter, key=single_filter, + value=dict_filters[single_filter])) + else: + if target == 'image' and (common_filter in ('dangling_only', 'external')): + if common_filter == 'dangling_only' and not filters['dangling_only']: + filter_out.append('-a') + if common_filter == 'external' and filters['external']: + filter_out.append('--external') else: - if target == 'image' and (common_filter in ('dangling_only', 'external')): - if common_filter == 'dangling_only' and not filters['dangling_only']: - command.append('-a') - if common_filter == 'external' and filters['external']: - command.append('--external') - else: - command.append('--filter={label}={value}'.format(label=common_filter, - value=filters[common_filter])) - else: - for system_filter in filters: - command.append(filters[system_filter]) + filter_out.append('--filter={label}={value}'.format(label=common_filter, + value=filters[common_filter])) + + return filter_out + +def podmanExec(module, target, filters, executable): + command = [executable, target, 'prune', '--force'] + if filters is not None: + command.extend(filtersPrepare(target, filters)) rc, out, err = module.run_command(command) - if out: - changed = True - else: - changed = False + changed = bool(out) + if rc != 0: module.fail_json( msg='Error executing prune on {target}: {err}'.format(target=target, err=err)) From f85000650390860e63333620979557d72fae2c5e Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Sun, 29 Jan 2023 23:44:50 +0100 Subject: [PATCH 7/9] managing output if multiple modules are invoked at once Signed-off-by: Roberto Alfieri --- plugins/modules/podman_prune.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/modules/podman_prune.py b/plugins/modules/podman_prune.py index 0ff4bbea..ee4c68a9 100644 --- a/plugins/modules/podman_prune.py +++ b/plugins/modules/podman_prune.py @@ -201,12 +201,13 @@ def podmanExec(module, target, filters, executable): return { "changed": changed, - "stdout": out, - "stderr": err + target: list(filter(None, out.split('\n'))), + "errors": err } def main(): + results = dict() module_args = dict( container=dict(type='bool', default=False), container_filters=dict(type='dict'), @@ -233,7 +234,7 @@ def main(): ('container', 'container_filters'), ('image', 'image_filters'), ('network', 'network_filters'), ('volume', 'volume_filters')): if module.params[target]: - results = podmanExec(module, target, module.params[filters], executable) + results[target] = podmanExec(module, target, module.params[filters], executable) if module.params['system']: target = 'system' @@ -242,7 +243,7 @@ def main(): system_filters['system_all'] = '--all' if module.params['system_volumes']: system_filters['system_volumes'] = '--volumes' - results = podmanExec(module, target, system_filters, executable) + results[target] = podmanExec(module, target, system_filters, executable) module.exit_json(**results) From bdc40ce9cd95ecd35c26dd9272a84579fcdeaef5 Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Sun, 29 Jan 2023 23:45:06 +0100 Subject: [PATCH 8/9] added tests Signed-off-by: Roberto Alfieri --- .github/workflows/podman_prune.yml | 107 ++++++++++++++++++ ci/playbooks/containers/podman_prune.yml | 8 ++ .../targets/podman_prune/tasks/main.yml | 100 ++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 .github/workflows/podman_prune.yml create mode 100644 ci/playbooks/containers/podman_prune.yml create mode 100644 tests/integration/targets/podman_prune/tasks/main.yml diff --git a/.github/workflows/podman_prune.yml b/.github/workflows/podman_prune.yml new file mode 100644 index 00000000..8797d844 --- /dev/null +++ b/.github/workflows/podman_prune.yml @@ -0,0 +1,107 @@ +name: Podman prune + +on: + push: + paths: + - '.github/workflows/podman_prune.yml' + - 'ci/*.yml' + - 'ci/run_containers_tests.sh' + - 'ci/playbooks/containers/podman_prune.yml' + - 'plugins/modules/podman_prune.py' + - 'tests/integration/targets/podman_prune/**' + branches: + - master + pull_request: + paths: + - '.github/workflows/podman_prune.yml' + - 'ci/*.yml' + - 'ci/run_containers_tests.sh' + - 'ci/playbooks/containers/podman_prune.yml' + - 'plugins/modules/podman_prune.py' + - 'tests/integration/targets/podman_prune/**' + schedule: + - cron: 4 0 * * * # Run daily at 0:03 UTC + +jobs: + + test_podman_prune: + name: Podman prune ${{ 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.11 + - git+https://github.com/ansible/ansible.git@devel + os: + - ubuntu-22.04 + python-version: + - 3.9 + + 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: | + 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 prune + run: | + export PATH=~/.local/bin:$PATH + + echo "Run ansible version" + command -v ansible + ansible --version + + export ANSIBLE_CONFIG=$(pwd)/ci/ansible-dev.cfg + if [[ '${{ matrix.ansible-version }}' == 'ansible<2.10' ]]; then + export ANSIBLE_CONFIG=$(pwd)/ci/ansible-2.9.cfg + fi + + 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_prune ./ci/run_containers_tests.sh + shell: bash diff --git a/ci/playbooks/containers/podman_prune.yml b/ci/playbooks/containers/podman_prune.yml new file mode 100644 index 00000000..cffc19f8 --- /dev/null +++ b/ci/playbooks/containers/podman_prune.yml @@ -0,0 +1,8 @@ +--- +- hosts: all + gather_facts: true + tasks: + - include_role: + name: podman_prune + vars: + ansible_python_interpreter: "/usr/bin/python" diff --git a/tests/integration/targets/podman_prune/tasks/main.yml b/tests/integration/targets/podman_prune/tasks/main.yml new file mode 100644 index 00000000..f2847445 --- /dev/null +++ b/tests/integration/targets/podman_prune/tasks/main.yml @@ -0,0 +1,100 @@ +- name: Create random names + ansible.builtin.set_fact: + cname: "{{ 'ansible-container-%0x' % ((2**32) | random) }}" + nname: "{{ 'ansible-network-%0x' % ((2**32) | random) }}" + vname: "{{ 'ansible-volume-%0x' % ((2**32) | random) }}" + +- name: Test podman_prune module + block: + # Create objects to be pruned + - name: Create container + containers.podman.podman_container: + name: "{{ cname }}" + image: quay.io/podman/hello:latest + state: present + register: container + - name: Create network + containers.podman.podman_network: + name: "{{ nname }}" + state: present + register: network + - name: Create volume + containers.podman.podman_volume: + name: "{{ vname }}" + state: present + register: volume + + # Prune objects + - name: Prune objects + containers.podman.podman_prune: + container: true + network: true + volume: true + register: result + + # Analyze result + - name: Show results + ansible.builtin.debug: + var: result + + - name: Verify assertions for network, container and volume + ansible.builtin.assert: + that: + # containers + - container.container.Id in result.container.container + # networks + - network.network.name in result.network.network + # volumes + - volume.volume.Name in result.volume.volume + + # Test with filters + - name: Prune objects with filters + containers.podman.podman_prune: + image: true + image_filters: + dangling_only: false + external: true + register: image_filters + + - name: Verify assertions for image (with filters) + ansible.builtin.assert: + that: + - image_filters.image.image | length > 0 + + - name: Create container + containers.podman.podman_container: + name: "{{ cname }}" + image: quay.io/podman/hello:latest + state: present + register: container + - name: Create network + containers.podman.podman_network: + name: "{{ nname }}" + state: present + register: network + - name: Create volume + containers.podman.podman_volume: + name: "{{ vname }}" + state: present + register: volume + + - name: System prune + containers.podman.podman_prune: + system: true + system_all: true + system_volumes: true + register: system_result + + - name: Show results + ansible.builtin.debug: + var: system_result + + - name: Verify assertions for system + ansible.builtin.assert: + that: + - system_result.system.system is search("Total reclaimed space") + + always: + - name: Cleanup + ansible.builtin.command: podman system prune -a -f --volumes + ignore_errors: true From 343dfdf0b0260b44d71408e53a749ff729cf52fe Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Mon, 30 Jan 2023 22:50:27 +0100 Subject: [PATCH 9/9] optimize tests and assertions for CI Signed-off-by: Roberto Alfieri --- .../targets/podman_prune/tasks/main.yml | 67 ++++++++++++++----- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/tests/integration/targets/podman_prune/tasks/main.yml b/tests/integration/targets/podman_prune/tasks/main.yml index f2847445..804543fe 100644 --- a/tests/integration/targets/podman_prune/tasks/main.yml +++ b/tests/integration/targets/podman_prune/tasks/main.yml @@ -13,11 +13,13 @@ image: quay.io/podman/hello:latest state: present register: container + - name: Create network containers.podman.podman_network: name: "{{ nname }}" state: present register: network + - name: Create volume containers.podman.podman_volume: name: "{{ vname }}" @@ -30,22 +32,28 @@ container: true network: true volume: true - register: result - # Analyze result - - name: Show results - ansible.builtin.debug: - var: result + - name: Check if container exists + containers.podman.podman_container_info: + register: container_exists + + - name: Check if podman network exists + containers.podman.podman_network_info: + register: network_exists + + - name: Check if podman volume exists + containers.podman.podman_volume_info: + register: volume_exists - name: Verify assertions for network, container and volume ansible.builtin.assert: that: # containers - - container.container.Id in result.container.container + - container.container.Id not in container_exists.containers | map(attribute='Name') | list | flatten # networks - - network.network.name in result.network.network + - network.network.name not in network_exists.networks | map(attribute='id') | list | flatten # volumes - - volume.volume.Name in result.volume.volume + - volume.volume.Name not in volume_exists.volumes | map(attribute='Name') | list | flatten # Test with filters - name: Prune objects with filters @@ -54,45 +62,68 @@ image_filters: dangling_only: false external: true - register: image_filters + + - name: Check if image exists + containers.podman.podman_image_info: + register: image_exists - name: Verify assertions for image (with filters) ansible.builtin.assert: that: - - image_filters.image.image | length > 0 + - image_exists.images | length == 0 - name: Create container containers.podman.podman_container: name: "{{ cname }}" image: quay.io/podman/hello:latest state: present - register: container + register: container_system + - name: Create network containers.podman.podman_network: name: "{{ nname }}" state: present - register: network + register: network_system + - name: Create volume containers.podman.podman_volume: name: "{{ vname }}" state: present - register: volume + register: volume_system - name: System prune containers.podman.podman_prune: system: true system_all: true system_volumes: true - register: system_result - - name: Show results - ansible.builtin.debug: - var: system_result + - name: Check if container exists + containers.podman.podman_container_info: + register: container_system_exists + + - name: Check if podman network exists + containers.podman.podman_network_info: + register: network_system_exists + + - name: Check if podman volume exists + containers.podman.podman_volume_info: + register: volume_system_exists + + - name: Check if image exists + containers.podman.podman_image_info: + register: image_system_exists - name: Verify assertions for system ansible.builtin.assert: that: - - system_result.system.system is search("Total reclaimed space") + # container + - container_system.container.Id not in container_system_exists.containers | map(attribute='Name') | list | flatten + # networks + - network_system.network.name not in network_system_exists.networks | map(attribute='id') | list | flatten + # volumes + - volume_system.volume.Name not in volume_system_exists.volumes | map(attribute='Name') | list | flatten + # images + - image_system_exists.images | length == 0 always: - name: Cleanup