Skip to content

Commit 924d943

Browse files
committed
fix: ensure user linger is enabled and disabled correctly
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]>
1 parent 852c0a4 commit 924d943

10 files changed

+137
-89
lines changed

tasks/cancel_linger.yml

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
# Input:
3+
# * __podman_linger_user - username
4+
- name: Get user information
5+
getent:
6+
database: passwd
7+
key: "{{ __podman_linger_user }}"
8+
fail_key: true
9+
when: "'getent_passwd' not in ansible_facts or
10+
__podman_linger_user not in ansible_facts['getent_passwd']"
11+
12+
- name: Set cancel linger vars
13+
set_fact:
14+
__podman_xdg_runtime_dir: >-
15+
/run/user/{{ ansible_facts["getent_passwd"][__podman_linger_user][1] }}
16+
17+
- name: Gather facts for containers
18+
containers.podman.podman_container_info:
19+
environment:
20+
XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}"
21+
become: true
22+
become_user: "{{ __podman_linger_user }}"
23+
register: __podman_container_info
24+
25+
- name: Gather facts for networks
26+
command: podman network ls -q
27+
register: __podman_networks
28+
changed_when: false
29+
environment:
30+
XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}"
31+
become: true
32+
become_user: "{{ __podman_linger_user }}"
33+
34+
- name: Gather secrets
35+
command: podman secret ls -n -q
36+
register: __podman_linger_secrets
37+
changed_when: false
38+
environment:
39+
XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}"
40+
become: true
41+
become_user: "{{ __podman_linger_user }}"
42+
43+
- name: Cancel linger if no more resources are in use
44+
command: loginctl disable-linger {{ __podman_linger_user }}
45+
when:
46+
- __podman_container_info.containers | length == 0
47+
- __podman_networks.stdout_lines | reject("match", "^podman$") |
48+
reject("match", "^podman-default-kube-network$") |
49+
list | length == 0
50+
- __podman_linger_secrets.stdout == ""
51+
changed_when: true

tasks/cleanup_kube_spec.yml

+4-14
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,7 @@
3939
when: __podman_removed is changed # noqa no-handler
4040
changed_when: true
4141

42-
- name: Gather facts for all containers
43-
containers.podman.podman_container_info:
44-
environment:
45-
XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}"
46-
become: "{{ __podman_rootless | ternary(true, omit) }}"
47-
become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}"
48-
register: __podman_container_info
49-
50-
- name: Cancel linger if no more containers are running
51-
command: loginctl disable-linger {{ __podman_user }}
52-
when:
53-
- __podman_rootless | bool
54-
- __podman_container_info.containers | length == 0
55-
changed_when: true
42+
- name: Manage linger
43+
include_tasks: manage_linger.yml
44+
vars:
45+
__podman_item_state: absent

tasks/cleanup_quadlet_spec.yml

+5-27
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
state: absent
2626
register: __podman_file_removed
2727

28+
- name: Manage linger
29+
include_tasks: manage_linger.yml
30+
vars:
31+
__podman_item_state: absent
32+
2833
- name: Cleanup container resources
2934
when: __podman_file_removed is changed # noqa no-handler
3035
block:
@@ -53,30 +58,3 @@
5358
XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}"
5459
become: "{{ __podman_rootless | ternary(true, omit) }}"
5560
become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}"
56-
57-
- name: Gather facts for all containers
58-
containers.podman.podman_container_info:
59-
environment:
60-
XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}"
61-
become: "{{ __podman_rootless | ternary(true, omit) }}"
62-
become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}"
63-
register: __podman_container_info
64-
no_log: true
65-
66-
- name: Gather facts for networks
67-
command: podman network ls -q
68-
register: __podman_networks
69-
changed_when: false
70-
environment:
71-
XDG_RUNTIME_DIR: "{{ __podman_xdg_runtime_dir }}"
72-
become: "{{ __podman_rootless | ternary(true, omit) }}"
73-
become_user: "{{ __podman_rootless | ternary(__podman_user, omit) }}"
74-
75-
- name: Cancel linger if no more resources are in use
76-
command: loginctl disable-linger {{ __podman_user }}
77-
when:
78-
- __podman_rootless | bool
79-
- __podman_container_info.containers | length == 0
80-
- __podman_networks.stdout_lines | reject('match', '^podman$') |
81-
list | length == 0
82-
changed_when: true

tasks/create_update_kube_spec.yml

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
---
2-
- name: Enable lingering if needed
3-
command: loginctl enable-linger {{ __podman_user }}
4-
when: __podman_rootless | bool
5-
args:
6-
creates: /var/lib/systemd/linger/{{ __podman_user }}
2+
- name: Manage linger
3+
include_tasks: manage_linger.yml
4+
vars:
5+
__podman_item_state: present
76

87
- name: Get the host mount volumes
98
set_fact:

tasks/create_update_quadlet_spec.yml

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
---
2-
- name: Enable lingering if needed
3-
command: loginctl enable-linger {{ __podman_user }}
4-
when: __podman_rootless | bool
5-
args:
6-
creates: /var/lib/systemd/linger/{{ __podman_user }}
2+
- name: Manage linger
3+
include_tasks: manage_linger.yml
4+
vars:
5+
__podman_item_state: present
76

87
- name: Create host directories
98
file: "{{ __defaults | combine(podman_host_directories[__hostitem])

tasks/handle_secret.yml

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
__podman_xdg_runtime_dir: >-
2121
/run/user/{{ ansible_facts["getent_passwd"][__podman_user][1] }}
2222
23+
- name: Manage linger
24+
include_tasks: manage_linger.yml
25+
vars:
26+
__podman_item_state: "{{ __podman_secret.state | d('present') }}"
27+
2328
- name: Manage each secret
2429
containers.podman.podman_secret:
2530
data: "{{ __podman_secret.data | string

tasks/main.yml

+10
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@
106106
selinux_ports: "{{ podman_selinux_ports }}"
107107
when: podman_selinux_ports | length > 0
108108

109+
- name: Keep track of users that need to cancel linger
110+
set_fact:
111+
__podman_cancel_user_linger: []
112+
109113
- name: Handle secrets
110114
include_tasks: handle_secret.yml
111115
loop: "{{ podman_secrets }}"
@@ -124,3 +128,9 @@
124128
loop: "{{ podman_quadlet_specs }}"
125129
loop_control:
126130
loop_var: __podman_quadlet_spec_item
131+
132+
- name: Cancel linger
133+
include_tasks: cancel_linger.yml
134+
loop: "{{ __podman_cancel_user_linger }}"
135+
loop_control:
136+
loop_var: __podman_linger_user

tasks/manage_linger.yml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
# Input:
3+
# * __podman_rootless - true or false
4+
# * __podman_user - name of user
5+
# * __podman_item_state - present or absent
6+
# Globals: __podman_cancel_user_linger
7+
- name: Enable linger if needed
8+
when:
9+
- __podman_rootless | bool
10+
- __podman_item_state | d('present') != 'absent'
11+
block:
12+
- name: Enable linger if needed
13+
command: loginctl enable-linger {{ __podman_user }}
14+
when: __podman_rootless | bool
15+
args:
16+
creates: /var/lib/systemd/linger/{{ __podman_user }}
17+
18+
- name: Mark user as not yet needing to cancel linger
19+
set_fact:
20+
__podman_cancel_user_linger: "{{ __podman_cancel_user_linger | difference([__podman_user]) }}"
21+
22+
- name: Mark user for possible linger cancel
23+
set_fact:
24+
__podman_cancel_user_linger: "{{ __podman_cancel_user_linger | union([__podman_user]) }}"
25+
when:
26+
- __podman_rootless | bool
27+
- __podman_item_state | d('present') == 'absent'

tests/tests_basic.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@
234234
spec:
235235
containers:
236236
- name: bogus
237-
image: this_is_a_bogus_image
237+
image: >-
238+
quay.io/linux-system-roles/this_is_a_bogus_image:latest
238239
239240
rescue:
240241
- name: Verify image not pulled

tests/tests_quadlet_basic.yml

+25-37
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77
vars:
88
podman_use_copr: false # disable copr for CI testing
99
podman_fail_if_too_old: false
10+
__json_secret_data: '{"test": "json"}'
1011
__secret_password_env: "{{ lookup('env', 'SYSTEM_ROLES_PODMAN_PASSWORD') }}"
1112
__podman_secrets:
1213
- name: mysql_container_root_password
1314
state: present
1415
skip_existing: true
1516
data: "{{ (__secret_password_env | length > 0) |
1617
ternary(__secret_password_env, mysql_container_root_password) }}"
18+
- name: json_secret
19+
state: present
20+
data: "{{ __json_secret_data | string }}"
1721
__podman_quadlet_specs:
1822
- name: quadlet-basic
1923
type: network
@@ -34,8 +38,9 @@
3438
Volume: quadlet-basic-mysql.volume:/var/lib/mysql
3539
Network: quadlet-basic.network
3640
# Once 4.5 is released change this line to use the quadlet Secret key
37-
PodmanArgs: "--secret=mysql_container_root_password,type=env,\
38-
target=MYSQL_ROOT_PASSWORD"
41+
PodmanArgs: >-
42+
--secret=mysql_container_root_password,type=env,target=MYSQL_ROOT_PASSWORD
43+
--secret=json_secret,type=mount,target=/tmp/test.json
3944
Environment:
4045
- FOO=/bin/busybox-extras
4146
- BAZ=test
@@ -120,6 +125,12 @@
120125
- quadlet-basic.network
121126
- quadlet-basic-mysql.volume
122127

128+
- name: Ensure linger
129+
stat:
130+
path: /var/lib/systemd/linger/user_quadlet_basic
131+
register: __stat
132+
failed_when: not __stat.stat.exists
133+
123134
# must clean up networks last - cannot remove a network
124135
# in use by a container
125136
- name: Cleanup user
@@ -135,41 +146,18 @@
135146
(__podman_quadlet_specs | selectattr('type', 'match', '^network$') |
136147
list)) | map('combine', __absent) | list }}"
137148

138-
- name: Set secret var for root testing
139-
set_fact:
140-
__root_podman_secrets: "{{ __podman_secrets + __json_secret }}"
141-
__root_json_data: '{"test": "json"}'
142-
vars:
143-
__json_secret:
144-
- name: json_secret
145-
state: present
146-
data: '{"test": "json"}'
147-
no_log: true
148-
149-
- name: Set container vars for root testing
150-
set_fact:
151-
__root_podman_quadlet_specs: "{{ __podman_quadlet_specs +
152-
__json_container }}"
153-
vars:
154-
__json_container:
155-
- name: json_container
156-
type: container
157-
Install:
158-
WantedBy: default.target
159-
Container:
160-
Image: "{{ mysql_image }}"
161-
ContainerName: json_container
162-
# Once 4.5 is released change this line to use the quadlet Secret
163-
PodmanArgs: "--secret=mysql_container_root_password,type=env,\
164-
target=MYSQL_ROOT_PASSWORD --secret=json_secret,type=mount,\
165-
target=/tmp/test.json"
149+
- name: Ensure no linger
150+
stat:
151+
path: /var/lib/systemd/linger/user_quadlet_basic
152+
register: __stat
153+
failed_when: __stat.stat.exists
166154

167155
- name: Run the role - root
168156
include_role:
169157
name: linux-system-roles.podman
170158
vars:
171-
podman_secrets: "{{ __root_podman_secrets }}"
172-
podman_quadlet_specs: "{{ __root_podman_quadlet_specs }}"
159+
podman_secrets: "{{ __podman_secrets }}"
160+
podman_quadlet_specs: "{{ __podman_quadlet_specs }}"
173161

174162
- name: Check files
175163
command: cat {{ __dir }}/{{ item }}
@@ -182,20 +170,20 @@
182170
- quadlet-basic-mysql.volume
183171

184172
- name: Check JSON
185-
command: podman exec json_container cat /tmp/test.json
173+
command: podman exec quadlet-basic-mysql cat /tmp/test.json
186174
register: __result
187-
failed_when: __result.stdout != __root_json_data
175+
failed_when: __result.stdout != __json_secret_data
188176
changed_when: false
189177

190178
- name: Cleanup system - root
191179
include_role:
192180
name: linux-system-roles.podman
193181
vars:
194182
__absent: {"state":"absent"}
195-
podman_secrets: "{{ __root_podman_secrets | map('combine', __absent) |
183+
podman_secrets: "{{ __podman_secrets | map('combine', __absent) |
196184
list }}"
197-
podman_quadlet_specs: "{{ ((__root_podman_quadlet_specs |
185+
podman_quadlet_specs: "{{ ((__podman_quadlet_specs |
198186
rejectattr('type', 'match', '^network$') | list) +
199-
(__root_podman_quadlet_specs |
187+
(__podman_quadlet_specs |
200188
selectattr('type', 'match', '^network$') | list)) |
201189
map('combine', __absent) | list }}"

0 commit comments

Comments
 (0)