# SPDX-License-Identifier: MIT
---
- name: Ensure that the role can manage quadlet specs
  hosts: all
  gather_facts: true  # for machine_id
  vars_files:
    - vars/test_vars.yml
  vars:
    podman_use_copr: false  # disable copr for CI testing
    podman_fail_if_too_old: false
    __json_secret_data: '{"test": "json"}'
    __secret_password_env: "{{ lookup('env', 'SYSTEM_ROLES_PODMAN_PASSWORD') }}"
    __podman_secrets:
      - name: mysql_container_root_password
        state: present
        data: "{{ (__secret_password_env | length > 0) |
          ternary(__secret_password_env, mysql_container_root_password) }}"
      - name: json_secret
        state: present
        data: "{{ __json_secret_data | string }}"
    __podman_quadlet_specs:
      - file_src: files/quadlet-basic.network
        state: started
      - name: quadlet-basic-unused-network
        type: network
        Network: {}
      - name: quadlet-basic-mysql
        type: volume
        Volume:
          VolumeName: quadlet-basic-mysql-name
      - name: quadlet-basic-unused-volume
        type: volume
        Volume: {}
      - name: quadlet-basic-mysql
        type: container
        Install:
          WantedBy: default.target
        Container:
          Image: "{{ mysql_image }}"
          ContainerName: quadlet-basic-mysql-name
          Volume: quadlet-basic-mysql.volume:/var/lib/mysql
          Network: quadlet-basic.network
          # Once 4.5 is released change this line to use the quadlet Secret key
          PodmanArgs: >-
            --secret=mysql_container_root_password,type=env,target=MYSQL_ROOT_PASSWORD
            --secret=json_secret,type=mount,target=/tmp/test.json
          Environment:
            - FOO=/bin/busybox-extras
            - BAZ=test
  tasks:
    - name: Test is only supported on x86_64
      debug:
        msg: >
          This test is only supported on x86_64 because the test images used are only
          available on that platform.
      when: ansible_facts["architecture"] != "x86_64"

    - name: End test
      meta: end_play
      when: ansible_facts["architecture"] != "x86_64"

    - name: Run test
      block:
        - name: See if not pulling images fails
          block:
            - name: Run role - do not pull images
              include_role:
                name: linux-system-roles.podman
              vars:
                podman_quadlet_specs:
                  - name: nopull
                    type: container
                    state: created
                    pull_image: false
                    activate_systemd_unit: false
                    Install:
                      WantedBy: default.target
                    Container:
                      Image: "{{ test_image }}"
                      ContainerName: nopull

            - name: Verify image not pulled
              assert:
                that: __podman_image_updated.results[0] is skipped

            - name: Run role - try to pull bogus image
              include_role:
                name: linux-system-roles.podman
              vars:
                podman_quadlet_specs:
                  - name: bogus
                    type: container
                    state: created
                    continue_if_pull_fails: true
                    activate_systemd_unit: false
                    Install:
                      WantedBy: default.target
                    Container:
                      Image: this_is_a_bogus_image
                      ContainerName: bogus

            - name: Verify image not pulled and no error
              assert:
                that:
                  - not __podman_image_updated.results[0] is changed
                  - not __podman_image_updated.results[0] is skipped

          always:
            - name: Cleanup
              include_role:
                name: linux-system-roles.podman
              vars:
                podman_quadlet_specs:
                  - state: absent
                    name: "{{ item }}"
                    type: container
              loop:
                - nopull
                - bogus

        - name: Create user for testing
          user:
            name: user_quadlet_basic
            uid: 1111

        # try to workaround the rootless containers error
        # Error:
        # mkdir /sys/fs/cgroup/devices/user.slice/runtime: permission denied
        - name: Enable EL8 system to support rootless quadlets
          when:
            - ansible_facts["os_family"] == "RedHat"
            - ansible_facts["distribution_version"] is version("9", "<")
          block:
            - name: Get local machine ID
              slurp:
                path: /etc/machine-id
              register: __local_mach_id_enc
              delegate_to: localhost

            - name: Skip test if cannot reboot
              meta: end_host
              when: ansible_facts["machine_id"] == __local_mac_id
              vars:
                __local_mac_id: "{{ __local_mach_id_enc.content | b64decode |
                  trim }}"

            - name: Enable cgroup controllers
              changed_when: true
              shell: |
                set -euxo pipefail
                cat > /etc/systemd/system/user-0.slice <<EOF
                [Unit]
                Before=systemd-logind.service
                [Slice]
                Slice=user.slice
                [Install]
                WantedBy=multi-user.target
                EOF
                if [ ! -d /etc/systemd/system/user@.service.d ]; then
                  mkdir -p /etc/systemd/system/user@.service.d
                fi
                cat > /etc/systemd/system/user@.service.d/delegate.conf <<EOF
                [Service]
                Delegate=memory pids
                EOF
                if [ ! -d /etc/systemd/system/user-.slice.d ]; then
                  mkdir -p /etc/systemd/system/user-.slice.d
                fi
                cat > /etc/systemd/system/user-.slice.d/override.conf <<EOF
                [Slice]
                Slice=user.slice
                CPUAccounting=yes
                MemoryAccounting=yes
                IOAccounting=yes
                TasksAccounting=yes
                EOF
                systemctl daemon-reload

            - name: Configure cgroups in kernel
              command: >-
                grubby --update-kernel=ALL
                --args=systemd.unified_cgroup_hierarchy=1
              changed_when: true

            - name: Reboot
              reboot:

        - name: Run the role - user
          include_role:
            name: linux-system-roles.podman
          vars:
            podman_run_as_user: user_quadlet_basic
            podman_secrets: "{{ __podman_secrets }}"
            podman_quadlet_specs: "{{ __podman_quadlet_specs }}"
            podman_pull_retry: true

        - name: Check files
          command: cat {{ __dir }}/{{ item }}
          changed_when: false
          vars:
            __dir: /home/user_quadlet_basic/.config/containers/systemd
          loop:
            - quadlet-basic-mysql.container
            - quadlet-basic.network
            - quadlet-basic-mysql.volume

        - name: Ensure linger
          stat:
            path: /var/lib/systemd/linger/user_quadlet_basic
          register: __stat
          failed_when: not __stat.stat.exists

        # must clean up in the reverse order of creating - and
        # ensure networks are removed last
        - name: Cleanup user
          include_role:
            name: linux-system-roles.podman
          vars:
            podman_prune_images: true
            __podman_test_debug: true
            podman_run_as_user: user_quadlet_basic
            __absent: {"state":"absent"}
            podman_secrets: "{{ __podman_secrets | map('combine', __absent) |
              list }}"
            podman_quadlet_specs: "{{ __podman_quadlet_specs | reverse |
              map('combine', __absent) | list }}"

        - name: Ensure no resources
          assert:
            that:
              - __podman_test_debug_images.stdout == ""
              - __podman_test_debug_networks.stdout_lines |
                reject("match", "^podman$") |
                reject("match", "^podman-default-kube-network$") |
                list | length == 0
              - __podman_test_debug_volumes.stdout == ""
              - __podman_test_debug_containers.stdout == ""
              - __podman_test_debug_secrets.stdout == ""
              - ansible_facts["services"] | dict2items |
                rejectattr("value.status", "match", "not-found") |
                selectattr("key", "match", "quadlet-demo") |
                list | length == 0

        - name: Ensure no linger
          stat:
            path: /var/lib/systemd/linger/user_quadlet_basic
          register: __stat
          failed_when: __stat.stat.exists

        - name: Run the role - root
          include_role:
            name: linux-system-roles.podman
          vars:
            podman_secrets: "{{ __podman_secrets }}"
            podman_quadlet_specs: "{{ __podman_quadlet_specs }}"

        - name: Check files
          command: cat {{ __dir }}/{{ item }}
          changed_when: false
          vars:
            __dir: /etc/containers/systemd
          loop:
            - quadlet-basic-mysql.container
            - quadlet-basic.network
            - quadlet-basic-mysql.volume

        - name: Check JSON
          command: podman exec quadlet-basic-mysql-name cat /tmp/test.json
          register: __result
          failed_when: __result.stdout != __json_secret_data
          changed_when: false

      rescue:
        - name: Debug3
          shell: |
            set -x
            set -o pipefail
            exec 1>&2
            #podman volume rm --all
            #podman network prune -f
            podman volume ls
            podman network ls
            podman secret ls
            podman container ls
            podman pod ls
            podman images
            systemctl list-units | grep quadlet
          changed_when: false

        - name: Check AVCs
          command: grep type=AVC /var/log/audit/audit.log
          changed_when: false
          failed_when: false

        - name: Dump journal
          command: journalctl -ex
          changed_when: false
          failed_when: true

      always:
        - name: Cleanup
          block:
            - name: Cleanup user
              include_role:
                name: linux-system-roles.podman
              vars:
                podman_prune_images: true
                podman_run_as_user: user_quadlet_basic
                __absent: {"state":"absent"}
                podman_secrets: "{{ __podman_secrets |
                  map('combine', __absent) | list }}"
                podman_quadlet_specs: "{{ __podman_quadlet_specs | reverse |
                  map('combine', __absent) | list }}"

            - name: Remove test user
              user:
                name: user_quadlet_basic
                uid: 1111
                state: absent

            - name: Cleanup system - root
              include_role:
                name: linux-system-roles.podman
              vars:
                podman_prune_images: true
                __podman_test_debug: true
                __absent: {"state":"absent"}
                podman_secrets: "{{ __podman_secrets |
                  map('combine', __absent) | list }}"
                podman_quadlet_specs: "{{ __podman_quadlet_specs | reverse |
                  map('combine', __absent) | list }}"

            - name: Ensure no resources
              assert:
                that:
                  - __podman_test_debug_images.stdout == ""
                  - __podman_test_debug_networks.stdout_lines |
                    reject("match", "^podman$") |
                    reject("match", "^podman-default-kube-network$") |
                    list | length == 0
                  - __podman_test_debug_volumes.stdout == ""
                  - __podman_test_debug_containers.stdout == ""
                  - __podman_test_debug_secrets.stdout == ""
                  - ansible_facts["services"] | dict2items |
                    rejectattr("value.status", "match", "not-found") |
                    selectattr("key", "match", "quadlet-demo") |
                    list | length == 0

          rescue:
            - name: Dump journal
              command: journalctl -ex
              changed_when: false
              failed_when: true
