diff --git a/.github/workflows/podman_load.yml b/.github/workflows/podman_load.yml new file mode 100644 index 0000000..0d6837f --- /dev/null +++ b/.github/workflows/podman_load.yml @@ -0,0 +1,108 @@ +name: Podman load + +on: + push: + paths: + - '.github/workflows/podman_load.yml' + - 'ci/*.yml' + - 'ci/run_containers_tests.sh' + - 'ci/playbooks/containers/podman_load.yml' + - 'plugins/modules/podman_load.py' + - 'tests/integration/targets/podman_load/**' + branches: + - master + pull_request: + paths: + - '.github/workflows/podman_load.yml' + - 'ci/*.yml' + - 'ci/run_containers_tests.sh' + - 'ci/playbooks/containers/podman_load.yml' + - 'plugins/modules/podman_load.py' + - 'tests/integration/targets/podman_load/**' + schedule: + - cron: 4 0 * * * # Run daily at 0:03 UTC + +jobs: + + test_podman_load: + name: Podman load ${{ matrix.ansible-version }}-${{ matrix.os || 'ubuntu-latest' }} + runs-on: ${{ matrix.os || 'ubuntu-latest' }} + 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-20.04 + python-version: + - 3.7 + + steps: + + - name: Check out repository + uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + 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@v1 + 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 load + run: | + export PATH=~/.local/bin:$PATH + + echo "Run ansible version" + command -v ansible + ansible --version + + 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 + + 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_load ./ci/run_containers_tests.sh + shell: bash diff --git a/ci/playbooks/containers/podman_load.yml b/ci/playbooks/containers/podman_load.yml new file mode 100644 index 0000000..77be246 --- /dev/null +++ b/ci/playbooks/containers/podman_load.yml @@ -0,0 +1,8 @@ +--- +- hosts: all + gather_facts: true + tasks: + - include_role: + name: podman_load + vars: + ansible_python_interpreter: "{{ _ansible_python_interpreter }}" diff --git a/plugins/modules/podman_load.py b/plugins/modules/podman_load.py new file mode 100644 index 0000000..be561af --- /dev/null +++ b/plugins/modules/podman_load.py @@ -0,0 +1,190 @@ +#!/usr/bin/python +# coding: utf-8 -*- + +# Copyright (c) 2020, Sagi Shnaidman +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r''' +module: podman_load +short_description: Load image from a tar file. +author: Sagi Shnaidman (@sshnaidm) +description: + - podman load loads an image from either an oci-archive or a docker-archive stored + on the local machine into container storage. + podman load is used for loading from the archive generated by podman save, + that includes the image parent layers. +options: + input: + description: + - Path to image file to load. + type: str + required: true + executable: + description: + - Path to C(podman) executable if it is not in the C($PATH) on the + machine running C(podman) + default: 'podman' + type: str +requirements: + - "Podman installed on host" +''' + +RETURN = ''' +image: + description: info from loaded image + returned: always + type: dict + sample: [ + { + "Annotations": {}, + "Architecture": "amd64", + "Author": "", + "Comment": "from Bitnami with love", + "ContainerConfig": { + "Cmd": [ + "nami", + "start", + "--foreground", + "wildfly" + ], + "Entrypoint": [ + "/app-entrypoint.sh" + ], + "Env": [ + "PATH=/opt/bitnami/java/bin:/opt/bitnami/wildfly/bin:/opt/bitnami/nami/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "IMAGE_OS=debian-9", + "NAMI_VERSION=0.0.9-0", + "GPG_KEY_SERVERS_LIST=ha.pool.sks-keyservers.net \ +hkp://p80.pool.sks-keyservers.net:80 keyserver.ubuntu.com hkp://keyserver.ubuntu.com:80 pgp.mit.edu", + "TINI_VERSION=v0.13.2", + "TINI_GPG_KEY=595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7", + "GOSU_VERSION=1.10", + "GOSU_GPG_KEY=B42F6819007F00F88E364FD4036A9C25BF357DD4", + "BITNAMI_IMAGE_VERSION=14.0.1-debian-9-r12", + "BITNAMI_APP_NAME=wildfly", + "WILDFLY_JAVA_HOME=", + "WILDFLY_JAVA_OPTS=", + "WILDFLY_MANAGEMENT_HTTP_PORT_NUMBER=9990", + "WILDFLY_PASSWORD=bitnami", + "WILDFLY_PUBLIC_CONSOLE=true", + "WILDFLY_SERVER_AJP_PORT_NUMBER=8009", + "WILDFLY_SERVER_HTTP_PORT_NUMBER=8080", + "WILDFLY_SERVER_INTERFACE=0.0.0.0", + "WILDFLY_USERNAME=user", + "WILDFLY_WILDFLY_HOME=/home/wildfly", + "WILDFLY_WILDFLY_OPTS=-Dwildfly.as.deployment.ondemand=false" + ], + "ExposedPorts": { + "8080/tcp": {}, + "9990/tcp": {} + }, + "Labels": { + "maintainer": "Bitnami " + } + }, + "Created": "2018-09-25T04:07:45.934395523Z", + "Digest": "sha256:5c7d8e2dd66dcf4a152a4032a1d3c5a33458c67e1c1335edd8d18d738892356b", + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/containers/storage/overlay/a9dbf5616cc16919a8ac0dfc60aff87a72b5be52994c4649fcc91a089a12931\ +f/diff:/var/lib/containers/storage/overlay/67129bd46022122a7d8b7acb490092af6c7ce244ce4fbd7d9e2d2b7f5979e090/diff:/var/lib/containers/storage/overlay/7c51242c\ +4c5db5c74afda76d7fdbeab6965d8b21804bb3fc597dee09c770b0ca/diff:/var/lib/containers/storage/overlay/f97315dc58a9c002ba0cabccb9933d4b0d2113733d204188c88d72f75569b57b/diff:/var/lib/containers/storage/overlay/1dbde2dd497ddde2b467727125b900958a051a72561e58d29abe3d660dcaa9a7/diff:/var/lib/containers/storage/overlay/4aad9d80f30c3f0608f58173558b7554d84dee4dc4479672926eca29f75e6e33/diff:/var/lib/containers/storage/overlay/6751fc9b6868254870c062d75a511543fc8cfda2ce6262f4945f107449219632/diff:/var/lib/containers/storage/overlay/a27034d79081347421dd24d7e9e776c18271cd9a6e51053cb39af4d3d9c400e8/diff:/var/lib/containers/storage/overlay/537cf0045ed9cd7989f7944e7393019c81b16c1799a2198d8348cd182665397f/diff:/var/lib/containers/storage/overlay/27578615c5ae352af4e8449862d61aaf5c11b105a7d5905af55bd01b0c656d6e/diff:/var/lib/containers/storage/overlay/566542742840fe3034b3596f7cb9e62a6274c95a69f368f9e713746f8712c0b6/diff", + "MergedDir": "/var/lib/containers/storage/overlay/72bb96d6\ +c53ad57a0b1e44cab226a6251598accbead40b23fac89c19ad8c25ca/merged", + "UpperDir": "/var/lib/containers/storage/overlay/72bb96d6c53ad57a0b1e44cab226a6251598accbead40b23fac89c19ad8c25ca/diff", + "WorkDir": "/var/lib/containers/storage/overlay/72bb96d6c53ad57a0b1e44cab226a6251598accbead40b23fac89c19ad8c25ca/work" + }, + "Name": "overlay" + }, + "Id": "bcacbdf7a119c0fa934661ca8af839e625ce6540d9ceb6827cdd389f823d49e0", + "Labels": { + "maintainer": "Bitnami " + }, + "ManifestType": "application/vnd.docker.distribution.manifest.v1+prettyjws", + "Os": "linux", + "Parent": "", + "RepoDigests": [ + "quay.io/bitnami/wildfly@sha256:5c7d8e2dd66dcf4a152a4032a1d3c5a33458c67e1c1335edd8d18d738892356b" + ], + "RepoTags": [ + "quay.io/bitnami/wildfly:latest" + ], + "RootFS": { + "Layers": [ + "sha256:75391df2c87e076b0c2f72d20c95c57dc8be7ee684cc07273416cce622b43367", + "sha256:7dd303f041039bfe8f0833092673ac35f93137d10e0fbc4302021ea65ad57731", + "sha256:720d9edf0cd2a9bb56b88b80be9070dbfaad359514c70094c65066963fed485d", + "sha256:6a567ecbf97725501a634fcb486271999aa4591b633b4ae9932a46b40f5aaf47", + "sha256:59e9a6db8f178f3da868614564faabb2820cdfb69be32e63a4405d6f7772f68c", + "sha256:310a82ccb092cd650215ab375da8943d235a263af9a029b8ac26a281446c04db", + "sha256:36cb91cf4513543a8f0953fed785747ea18b675bc2677f3839889cfca0aac79e" + ], + "Type": "layers" + }, + "Size": 569919342, + "User": "", + "Version": "17.06.0-ce", + "VirtualSize": 569919342 + } + ] +''' + +EXAMPLES = ''' +# What modules does for example +- containers.podman.podman_load: + input: /path/to/tar/file +''' + +import json # noqa: E402 +from ansible.module_utils.basic import AnsibleModule # noqa: E402 + + +def load(module, executable): + changed = False + command = [executable, 'load', '--input'] + command.append(module.params['input']) + changed = True + if module.check_mode: + return changed, '', '', '' + rc, out, err = module.run_command(command) + if rc != 0: + module.fail_json(msg="Image loading failed: %s" % (err)) + image_name_line = [i for i in out.splitlines() if 'Loaded image' in i][0] + image_name = image_name_line.split(":", maxsplit=1)[1].strip() + rc, out2, err2 = module.run_command([executable, 'image', 'inspect', image_name]) + if rc != 0: + module.fail_json(msg="Image %s inspection failed: %s" % (image_name, err2)) + try: + info = json.loads(out2)[0] + except Exception as e: + module.fail_json(msg="Could not parse JSON from image %s: %s" % (image_name, e)) + return changed, out, err, info + + +def main(): + module = AnsibleModule( + argument_spec=dict( + input=dict(type='str', required=True), + executable=dict(type='str', default='podman') + ), + supports_check_mode=True, + ) + + executable = module.get_bin_path(module.params['executable'], required=True) + changed, out, err, image_info = load(module, executable) + + results = { + "changed": changed, + "stdout": out, + "stderr": err, + "image": image_info, + } + + module.exit_json(**results) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/podman_load/tasks/main.yml b/tests/integration/targets/podman_load/tasks/main.yml new file mode 100644 index 0000000..f7cae8d --- /dev/null +++ b/tests/integration/targets/podman_load/tasks/main.yml @@ -0,0 +1,54 @@ +--- +- name: Pull image + containers.podman.podman_image: + name: k8s.gcr.io/pause + +- name: Save image + containers.podman.podman_save: + image: k8s.gcr.io/pause + dest: /tmp/image.tar + +- name: Load image + containers.podman.podman_load: + input: /tmp/image.tar + register: image + +- name: Check it's loaded + assert: + that: + - image.image != {} + - image.image.NamesHistory.0 == "k8s.gcr.io/pause:latest" + +- name: Save image + containers.podman.podman_save: + image: k8s.gcr.io/pause + dest: /tmp/imagedir + format: oci-dir + +- name: Load image from oci-dir + containers.podman.podman_load: + input: /tmp/imagedir + register: image + +- name: Check it's loaded + assert: + that: + - image.image != {} + - image.image.NamesHistory.0 == "localhost/tmp/imagedir:latest" + +- name: Save image with multi image archive + containers.podman.podman_save: + image: k8s.gcr.io/pause + dest: /tmp/image2.tar + multi_image_archive: true + +- name: Load image from oci-dir multi image archive + containers.podman.podman_load: + input: /tmp/image2.tar + register: image + +- name: Check it's loaded + assert: + that: + - image.image != {} + - image.image.NamesHistory.0 == "k8s.gcr.io/pause:latest"