Skip to content

Commit

Permalink
fix: ensure user linger is enabled and disabled correctly
Browse files Browse the repository at this point in the history
Cause: The role was not always enabling user lingering before
creating resources, and not always canceling lingering after
removing resources.

Consequence: The role would give errors if attempting to create
a secret or other resource requiring lingering, or would leave
lingering enabled after removing resources.

Fix: Centralize linger handling and keep track of users which
may need linger canceling.  Ensure linger is canceled for all
users if all of that user's resources are removed and linger is
no longer needed.

Result: Resources for rootless users are always created properly.
Lingering is always canceled when no longer needed.

Signed-off-by: Rich Megginson <[email protected]>
  • Loading branch information
richm committed Feb 2, 2024
1 parent 852c0a4 commit 924d943
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 89 deletions.
51 changes: 51 additions & 0 deletions tasks/cancel_linger.yml
Original file line number Diff line number Diff line change
@@ -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
18 changes: 4 additions & 14 deletions tasks/cleanup_kube_spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
32 changes: 5 additions & 27 deletions tasks/cleanup_quadlet_spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
9 changes: 4 additions & 5 deletions tasks/create_update_kube_spec.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
9 changes: 4 additions & 5 deletions tasks/create_update_quadlet_spec.yml
Original file line number Diff line number Diff line change
@@ -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])
Expand Down
5 changes: 5 additions & 0 deletions tasks/handle_secret.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}"
Expand All @@ -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
27 changes: 27 additions & 0 deletions tasks/manage_linger.yml
Original file line number Diff line number Diff line change
@@ -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'
3 changes: 2 additions & 1 deletion tests/tests_basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
62 changes: 25 additions & 37 deletions tests/tests_quadlet_basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
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
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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 }}
Expand All @@ -182,20 +170,20 @@
- 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
include_role:
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 }}"

0 comments on commit 924d943

Please sign in to comment.