diff --git a/tasks/cancel_linger.yml b/tasks/cancel_linger.yml new file mode 100644 index 00000000..21d71ddf --- /dev/null +++ b/tasks/cancel_linger.yml @@ -0,0 +1,51 @@ +--- +# Input: +# * __podman_linger_user - username +- name: Get user information + getent: + database: passwd + key: "{{ __podman_linger_user }}" + fail_key: true + when: "'getent_passwd' not in ansible_facts or + __podman_linger_user not in ansible_facts['getent_passwd']" + +- name: Set cancel linger vars + set_fact: + __podman_xdg_runtime_dir: >- + /run/user/{{ ansible_facts["getent_passwd"][__podman_linger_user][1] }} + +- name: Gather facts for containers + containers.podman.podman_container_info: + environment: + XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}" + become: true + become_user: "{{ __podman_linger_user }}" + register: __podman_container_info + +- name: Gather facts for networks + command: podman network ls -q + register: __podman_networks + changed_when: false + environment: + XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}" + become: true + become_user: "{{ __podman_linger_user }}" + +- name: Gather secrets + command: podman secret ls -n -q + register: __podman_linger_secrets + changed_when: false + environment: + XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}" + become: true + become_user: "{{ __podman_linger_user }}" + +- name: Cancel linger if no more resources are in use + command: loginctl disable-linger {{ __podman_linger_user }} + when: + - __podman_container_info.containers | length == 0 + - __podman_networks.stdout_lines | reject("match", "^podman$") | + reject("match", "^podman-default-kube-network$") | + list | length == 0 + - __podman_linger_secrets.stdout == "" + changed_when: true diff --git a/tasks/cleanup_kube_spec.yml b/tasks/cleanup_kube_spec.yml index 17e4705e..3d3bec70 100644 --- a/tasks/cleanup_kube_spec.yml +++ b/tasks/cleanup_kube_spec.yml @@ -39,17 +39,7 @@ when: __podman_removed is changed # noqa no-handler changed_when: true -- name: Gather facts for all containers - containers.podman.podman_container_info: - environment: - XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}" - become: "{{ __podman_rootless | ternary(true, omit) }}" - become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}" - register: __podman_container_info - -- name: Cancel linger if no more containers are running - command: loginctl disable-linger {{ __podman_user }} - when: - - __podman_rootless | bool - - __podman_container_info.containers | length == 0 - changed_when: true +- name: Manage linger + include_tasks: manage_linger.yml + vars: + __podman_item_state: absent diff --git a/tasks/cleanup_quadlet_spec.yml b/tasks/cleanup_quadlet_spec.yml index 4cbcae10..604438b8 100644 --- a/tasks/cleanup_quadlet_spec.yml +++ b/tasks/cleanup_quadlet_spec.yml @@ -25,6 +25,11 @@ state: absent register: __podman_file_removed +- name: Manage linger + include_tasks: manage_linger.yml + vars: + __podman_item_state: absent + - name: Cleanup container resources when: __podman_file_removed is changed # noqa no-handler block: @@ -53,30 +58,3 @@ XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}" become: "{{ __podman_rootless | ternary(true, omit) }}" become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}" - - - name: Gather facts for all containers - containers.podman.podman_container_info: - environment: - XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}" - become: "{{ __podman_rootless | ternary(true, omit) }}" - become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}" - register: __podman_container_info - no_log: true - - - name: Gather facts for networks - command: podman network ls -q - register: __podman_networks - changed_when: false - environment: - XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}" - become: "{{ __podman_rootless | ternary(true, omit) }}" - become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}" - - - name: Cancel linger if no more resources are in use - command: loginctl disable-linger {{ __podman_user }} - when: - - __podman_rootless | bool - - __podman_container_info.containers | length == 0 - - __podman_networks.stdout_lines | reject('match', '^podman$') | - list | length == 0 - changed_when: true diff --git a/tasks/create_update_kube_spec.yml b/tasks/create_update_kube_spec.yml index fca64981..93054202 100644 --- a/tasks/create_update_kube_spec.yml +++ b/tasks/create_update_kube_spec.yml @@ -1,9 +1,8 @@ --- -- name: Enable lingering if needed - command: loginctl enable-linger {{ __podman_user }} - when: __podman_rootless | bool - args: - creates: /var/lib/systemd/linger/{{ __podman_user }} +- name: Manage linger + include_tasks: manage_linger.yml + vars: + __podman_item_state: present - name: Get the host mount volumes set_fact: diff --git a/tasks/create_update_quadlet_spec.yml b/tasks/create_update_quadlet_spec.yml index f76f232c..6cb4b444 100644 --- a/tasks/create_update_quadlet_spec.yml +++ b/tasks/create_update_quadlet_spec.yml @@ -1,9 +1,8 @@ --- -- name: Enable lingering if needed - command: loginctl enable-linger {{ __podman_user }} - when: __podman_rootless | bool - args: - creates: /var/lib/systemd/linger/{{ __podman_user }} +- name: Manage linger + include_tasks: manage_linger.yml + vars: + __podman_item_state: present - name: Create host directories file: "{{ __defaults | combine(podman_host_directories[__hostitem]) diff --git a/tasks/handle_secret.yml b/tasks/handle_secret.yml index ecbe604f..14aa9a11 100644 --- a/tasks/handle_secret.yml +++ b/tasks/handle_secret.yml @@ -20,6 +20,11 @@ __podman_xdg_runtime_dir: >- /run/user/{{ ansible_facts["getent_passwd"][__podman_user][1] }} +- name: Manage linger + include_tasks: manage_linger.yml + vars: + __podman_item_state: "{{ __podman_secret.state | d('present') }}" + - name: Manage each secret containers.podman.podman_secret: data: "{{ __podman_secret.data | string diff --git a/tasks/main.yml b/tasks/main.yml index a34068f7..1b9ca4ab 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -106,6 +106,10 @@ selinux_ports: "{{ podman_selinux_ports }}" when: podman_selinux_ports | length > 0 +- name: Keep track of users that need to cancel linger + set_fact: + __podman_cancel_user_linger: [] + - name: Handle secrets include_tasks: handle_secret.yml loop: "{{ podman_secrets }}" @@ -124,3 +128,9 @@ loop: "{{ podman_quadlet_specs }}" loop_control: loop_var: __podman_quadlet_spec_item + +- name: Cancel linger + include_tasks: cancel_linger.yml + loop: "{{ __podman_cancel_user_linger }}" + loop_control: + loop_var: __podman_linger_user diff --git a/tasks/manage_linger.yml b/tasks/manage_linger.yml new file mode 100644 index 00000000..1690f288 --- /dev/null +++ b/tasks/manage_linger.yml @@ -0,0 +1,27 @@ +--- +# Input: +# * __podman_rootless - true or false +# * __podman_user - name of user +# * __podman_item_state - present or absent +# Globals: __podman_cancel_user_linger +- name: Enable linger if needed + when: + - __podman_rootless | bool + - __podman_item_state | d('present') != 'absent' + block: + - name: Enable linger if needed + command: loginctl enable-linger {{ __podman_user }} + when: __podman_rootless | bool + args: + creates: /var/lib/systemd/linger/{{ __podman_user }} + + - name: Mark user as not yet needing to cancel linger + set_fact: + __podman_cancel_user_linger: "{{ __podman_cancel_user_linger | difference([__podman_user]) }}" + +- name: Mark user for possible linger cancel + set_fact: + __podman_cancel_user_linger: "{{ __podman_cancel_user_linger | union([__podman_user]) }}" + when: + - __podman_rootless | bool + - __podman_item_state | d('present') == 'absent' diff --git a/tests/tests_basic.yml b/tests/tests_basic.yml index acc01c08..f2cf7101 100644 --- a/tests/tests_basic.yml +++ b/tests/tests_basic.yml @@ -234,7 +234,8 @@ spec: containers: - name: bogus - image: this_is_a_bogus_image + image: >- + quay.io/linux-system-roles/this_is_a_bogus_image:latest rescue: - name: Verify image not pulled diff --git a/tests/tests_quadlet_basic.yml b/tests/tests_quadlet_basic.yml index 94c1b66c..025497fa 100644 --- a/tests/tests_quadlet_basic.yml +++ b/tests/tests_quadlet_basic.yml @@ -7,6 +7,7 @@ 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 @@ -14,6 +15,9 @@ skip_existing: true 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: - name: quadlet-basic type: network @@ -34,8 +38,9 @@ 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" + 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 @@ -120,6 +125,12 @@ - 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 networks last - cannot remove a network # in use by a container - name: Cleanup user @@ -135,41 +146,18 @@ (__podman_quadlet_specs | selectattr('type', 'match', '^network$') | list)) | map('combine', __absent) | list }}" - - name: Set secret var for root testing - set_fact: - __root_podman_secrets: "{{ __podman_secrets + __json_secret }}" - __root_json_data: '{"test": "json"}' - vars: - __json_secret: - - name: json_secret - state: present - data: '{"test": "json"}' - no_log: true - - - name: Set container vars for root testing - set_fact: - __root_podman_quadlet_specs: "{{ __podman_quadlet_specs + - __json_container }}" - vars: - __json_container: - - name: json_container - type: container - Install: - WantedBy: default.target - Container: - Image: "{{ mysql_image }}" - ContainerName: json_container - # Once 4.5 is released change this line to use the quadlet Secret - PodmanArgs: "--secret=mysql_container_root_password,type=env,\ - target=MYSQL_ROOT_PASSWORD --secret=json_secret,type=mount,\ - target=/tmp/test.json" + - 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: "{{ __root_podman_secrets }}" - podman_quadlet_specs: "{{ __root_podman_quadlet_specs }}" + podman_secrets: "{{ __podman_secrets }}" + podman_quadlet_specs: "{{ __podman_quadlet_specs }}" - name: Check files command: cat {{ __dir }}/{{ item }} @@ -182,9 +170,9 @@ - quadlet-basic-mysql.volume - name: Check JSON - command: podman exec json_container cat /tmp/test.json + command: podman exec quadlet-basic-mysql cat /tmp/test.json register: __result - failed_when: __result.stdout != __root_json_data + failed_when: __result.stdout != __json_secret_data changed_when: false - name: Cleanup system - root @@ -192,10 +180,10 @@ name: linux-system-roles.podman vars: __absent: {"state":"absent"} - podman_secrets: "{{ __root_podman_secrets | map('combine', __absent) | + podman_secrets: "{{ __podman_secrets | map('combine', __absent) | list }}" - podman_quadlet_specs: "{{ ((__root_podman_quadlet_specs | + podman_quadlet_specs: "{{ ((__podman_quadlet_specs | rejectattr('type', 'match', '^network$') | list) + - (__root_podman_quadlet_specs | + (__podman_quadlet_specs | selectattr('type', 'match', '^network$') | list)) | map('combine', __absent) | list }}"