1
#!/usr/bin/env bats -*- bats -*-
14
skip_if_remote "systemd tests are meaningless over remote"
17
SNAME_FILE=${PODMAN_TMPDIR}/services
21
if [[ -e $SNAME_FILE ]]; then
23
if [[ "$line" =~ "podman-auto-update" ]]; then
24
echo "Stop timer: $line.timer"
25
systemctl stop $line.timer
26
systemctl disable $line.timer
30
rm -f $UNIT_DIR/$line.{service,timer}
38
quay.io/libpod/alpine:latest \
39
quay.io/libpod/busybox:latest \
40
quay.io/libpod/localtest:latest \
41
quay.io/libpod/autoupdatebroken:latest \
42
quay.io/libpod/test:latest
46
run_podman image prune -f
59
function generate_service() {
60
local target_img_basename=$1
68
if [[ -z "$command" ]]; then
74
cname=c_${autoupdate//\'/}_$(random_string)
75
target_img="quay.io/libpod/$target_img_basename:latest"
76
if [[ -n "$7" ]]; then
80
if [[ -z "$noTag" ]]; then
81
run_podman tag $IMAGE $target_img
84
if [[ -n "$autoupdate" ]]; then
85
label="--label io.containers.autoupdate=$autoupdate"
90
if [[ -n "$requires" ]]; then
91
requires="--requires=$requires"
94
run_podman create $extraArgs --name $cname $label $target_img $command
96
(cd $UNIT_DIR; run_podman generate systemd --new --files --name $requires $cname)
97
echo "container-$cname" >> $SNAME_FILE
98
run_podman rm -t 0 -f $cname
100
systemctl daemon-reload
101
systemctl_start container-$cname
102
systemctl status container-$cname
106
run_podman inspect --format "{{.Image}}" $cname
110
function _wait_service_ready() {
114
while [[ $timeout -gt 1 ]]; do
115
if systemctl -q is-active $sname; then
119
let timeout=$timeout-1
123
systemctl status $sname
124
die "Timed out waiting for $sname to start"
128
function _confirm_update() {
134
while [[ $timeout -gt 0 ]]; do
136
run_podman '?' inspect --format "{{.Image}}" $cname
137
if [[ $status != 0 ]]; then
138
if [[ $output =~ (no such object|does not exist in database): ]]; then
142
die "podman inspect $cname failed unexpectedly"
144
elif [[ $output != $old_iid ]]; then
147
timeout=$((timeout - 1))
150
die "Timed out waiting for $cname to update; old IID=$old_iid"
153
@test "podman auto-update - validate input" {
155
run_podman create --label io.containers.autoupdate=registry $IMAGE
156
run_podman rm -f "$output"
159
shortname="shortname:latest"
160
run_podman image tag $IMAGE $shortname
161
run_podman 125 create --label io.containers.autoupdate=registry $shortname
162
is "$output" "Error: short name: auto updates require fully-qualified image reference: \"$shortname\""
165
archive=$PODMAN_TMPDIR/archive.tar
166
run_podman save -o $archive $IMAGE
167
run_podman 125 create --label io.containers.autoupdate=registry docker-archive:$archive
168
is "$output" ".*Error: auto updates require the docker image transport but image is of transport \"docker-archive\""
170
run_podman rmi $shortname
175
@test "podman auto-update - label io.containers.autoupdate=image" {
176
since=$(date --iso-8601=seconds)
177
run_podman auto-update
179
run_podman events --filter type=system --since $since --stream=false
185
generate_service alpine image
187
_wait_service_ready container-$ctr_parent.service
189
generate_service alpine image "" "" "" "container-$ctr_parent.service"
191
_wait_service_ready container-$ctr_child.service
192
run_podman container inspect --format "{{.ID}}" $ctr_child
195
since=$(date --iso-8601=seconds)
196
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
197
is "$output" ".*container-$ctr_parent.service,quay.io/libpod/alpine:latest,pending,registry.*" "Image update is pending."
198
run_podman events --filter type=system --since $since --stream=false
199
is "$output" ".* system auto-update"
201
since=$(date --iso-8601=seconds)
202
run_podman auto-update --rollback=false --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
203
is "$output" "Trying to pull.*" "Image is updated."
204
is "$output" ".*container-$ctr_parent.service,quay.io/libpod/alpine:latest,true,registry.*" "Image is updated."
205
run_podman events --filter type=system --since $since --stream=false
206
is "$output" ".* system auto-update"
210
_confirm_update $ctr_parent $ori_image
211
run_podman container inspect --format "{{.ID}}" $ctr_child
212
assert "$output" != "$old_child_id" \
213
"child container/unit has not been restarted during update"
214
run_podman container inspect --format "{{.ID}}" $ctr_child
215
run_podman container inspect --format "{{.State.Status}}" $ctr_child
216
is "$output" "running" "child container is in running state"
219
@test "podman auto-update - label io.containers.autoupdate=image with rollback" {
226
image=quay.io/libpod/autoupdatebroken
228
run_podman tag $IMAGE $image
229
generate_service autoupdatebroken image
231
_wait_service_ready container-$cname.service
232
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
233
is "$output" ".*container-$cname.service,$image:latest,pending,registry.*" "Image update is pending."
235
run_podman container inspect --format "{{.Image}}" $cname
238
run_podman inspect --format "{{.ID}}" $cname
239
containerID="$output"
241
run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
242
is "$output" "Trying to pull.*" "Image is updated."
243
is "$output" ".*container-$cname.service,$image:latest,rolled back,registry.*" "Image has been rolled back."
245
run_podman container inspect --format "{{.Image}}" $cname
246
is "$output" "$oldID" "container rolled back to previous image"
248
run_podman container inspect --format "{{.ID}}" $cname
249
assert "$output" != "$containerID" \
250
"container has not been restarted during rollback"
253
@test "podman auto-update - label io.containers.autoupdate=disabled" {
254
generate_service alpine disabled
256
_wait_service_ready container-$cname.service
257
run_podman auto-update
258
is "$output" "" "Image is not updated when autoupdate=disabled."
260
run_podman inspect --format "{{.Image}}" $cname
261
is "$output" "$ori_image" "Image ID should not change"
264
@test "podman auto-update - label io.containers.autoupdate=fakevalue" {
265
fakevalue=fake_$(random_string)
266
generate_service alpine $fakevalue
268
_wait_service_ready container-$cname.service
269
run_podman 125 auto-update
270
is "$output" ".*invalid auto-update policy.*" "invalid policy setup"
272
run_podman inspect --format "{{.Image}}" $cname
273
is "$output" "$ori_image" "Image ID should not change"
276
@test "podman auto-update - label io.containers.autoupdate=local" {
277
generate_service localtest local
278
_wait_service_ready container-$cname.service
280
image=quay.io/libpod/localtest:latest
281
run_podman commit --change CMD=/bin/bash $cname $image
282
run_podman image inspect --format "{{.ID}}" $image
284
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
285
is "$output" ".*container-$cname.service,quay.io/libpod/localtest:latest,pending,local.*" "Image update is pending."
287
run_podman auto-update --rollback=false --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
288
is "$output" ".*container-$cname.service,quay.io/libpod/localtest:latest,true,local.*" "Image is updated."
290
_confirm_update $cname $ori_image
295
@test "podman auto-update - label io.containers.autoupdate=local with rollback" {
299
runtime=$(podman_runtime)
300
if [[ "$runtime" != "crun" ]]; then
301
skip "this test only works with crun, not $runtime"
304
_prefetch $SYSTEMD_IMAGE
306
dockerfile1=$PODMAN_TMPDIR/Dockerfile.1
307
cat >$dockerfile1 <<EOF
309
RUN echo -e "#!/bin/sh\n\
310
printenv NOTIFY_SOCKET; echo READY; systemd-notify --ready;\n\
311
trap 'echo Received SIGTERM, finishing; exit' SIGTERM; echo WAITING; while :; do sleep 0.1; done" \
316
dockerfile2=$PODMAN_TMPDIR/Dockerfile.2
317
cat >$dockerfile2 <<EOF
319
RUN echo -e "#!/bin/sh\n\
326
run_podman build -t quay.io/libpod/$image -f $dockerfile1
328
generate_service $image local /runme --sdnotify=container noTag
329
_wait_service_ready container-$cname.service
331
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
332
is "$output" ".*container-$cname.service,quay.io/libpod/$image:latest,false,local.*" "No update available"
335
run_podman build -t quay.io/libpod/$image -f $dockerfile2
336
run_podman image inspect --format "{{.ID}}" $image
339
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
340
is "$output" ".*container-$cname.service,quay.io/libpod/$image:latest,pending,local.*" "Image updated is pending"
343
run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
344
is "$output" ".*container-$cname.service,quay.io/libpod/$image:latest,rolled back,local.*" "Rolled back to old image"
347
_confirm_update $cname $newID
350
@test "podman auto-update with multiple services" {
352
run_podman inspect --format "{{.Id}}" $IMAGE
353
local img_id="$output"
356
local -A expect_update
357
local -A will_update=([image]=1 [registry]=1 [local]=1)
359
local fakevalue=fake_$(random_string)
360
for auto_update in image registry "" disabled "''" $fakevalue local
362
local img_base="alpine"
363
if [[ $auto_update == "registry" ]]; then
365
elif [[ $auto_update == "local" ]]; then
368
generate_service $img_base $auto_update
370
if [[ $auto_update == "local" ]]; then
374
if [[ -n "$auto_update" && -n "${will_update[$auto_update]}" ]]; then
375
expect_update[$cname]=1
380
for cname in "${cnames[@]}"; do
381
_wait_service_ready container-$cname.service
383
run_podman commit --change CMD=/bin/bash $local_cname quay.io/libpod/localtest:latest
385
run_podman 125 auto-update --rollback=false
387
is "$update_log" ".*invalid auto-update policy.*" "invalid policy setup"
388
is "$update_log" ".*Error: invalid auto-update policy.*" "invalid policy setup"
390
local n_updated=$(grep -c 'Trying to pull' <<<"$update_log")
391
is "$n_updated" "2" "Number of images updated from registry."
393
for cname in "${!expect_update[@]}"; do
394
is "$update_log" ".*$cname.*" "container with auto-update policy image updated"
396
_confirm_update $cname $img_id
400
for cname in "${cnames[@]}"; do
401
run_podman inspect --format "{{.Image}}" $cname
402
if [[ -n "${expect_update[$cname]}" ]]; then
403
assert "$output" != "$img_id" "$cname: image ID did not change"
405
assert "$output" = "$img_id" "Image ID should not be changed."
410
@test "podman auto-update using systemd" {
411
skip_if_journald_unavailable
413
generate_service alpine image
415
cat >$UNIT_DIR/podman-auto-update-$cname.timer <<EOF
417
Description=Podman auto-update testing timer
420
OnCalendar=*-*-* *:*:0/2
424
WantedBy=timers.target
426
cat >$UNIT_DIR/podman-auto-update-$cname.service <<EOF
428
Description=Podman auto-update testing service
429
Documentation=man:podman-auto-update(1)
430
Wants=network-online.target
431
After=network-online.target
435
ExecStart=$PODMAN auto-update
436
Environment="http_proxy=${http_proxy}"
437
Environment="HTTP_PROXY=${HTTP_PROXY}"
438
Environment="https_proxy=${https_proxy}"
439
Environment="HTTPS_PROXY=${HTTPS_PROXY}"
440
Environment="no_proxy=${no_proxy}"
441
Environment="NO_PROXY=${NO_PROXY}"
444
WantedBy=default.target
447
echo "podman-auto-update-$cname" >> $SNAME_FILE
448
systemctl enable --now podman-auto-update-$cname.timer
449
systemctl list-timers --all
454
local expect='(Started|Finished.*) Podman auto-update testing service'
455
local failed_start=failed
457
while [ $count -lt 120 ]; do
458
run journalctl -n 15 -u podman-auto-update-$cname.service
459
if [[ "$output" =~ $expect ]]; then
467
if [[ -n "$failed_start" ]]; then
468
echo "journalctl output:"
469
sed -e 's/^/ /' <<<"$output"
470
die "Did not find expected string '$expect' in journalctl output for $cname"
473
_confirm_update $cname $ori_image
476
@test "podman-kube@.service template with rollback" {
480
runtime=$(podman_runtime)
481
if [[ "$runtime" != "crun" ]]; then
482
skip "this test only works with crun, not $runtime"
485
_prefetch $SYSTEMD_IMAGE
486
install_kube_template
488
dockerfile1=$PODMAN_TMPDIR/Dockerfile.1
489
cat >$dockerfile1 <<EOF
491
RUN echo -e "#!/bin/sh\n\
492
printenv NOTIFY_SOCKET; echo READY; systemd-notify --ready;\n\
493
trap 'echo Received SIGTERM, finishing; exit' SIGTERM; echo WAITING; while :; do sleep 0.1; done" \
498
dockerfile2=$PODMAN_TMPDIR/Dockerfile.2
499
cat >$dockerfile2 <<EOF
501
RUN echo -e "#!/bin/sh\n\
505
local_image=localhost/image:$(random_string 10)
508
run_podman build -t $local_image -f $dockerfile1
509
run_podman image inspect --format "{{.ID}}" $local_image
513
yaml_source="$PODMAN_TMPDIR/test.yaml"
514
cat >$yaml_source <<EOF
519
io.containers.autoupdate: "registry"
520
io.containers.autoupdate/b: "local"
521
io.containers.sdnotify/b: "container"
538
service_name="podman-kube@$(systemd-escape $yaml_source).service"
539
systemctl_start $service_name
540
systemctl is-active $service_name
543
run_podman auto-update --dry-run --format "{{.Unit}},{{.Container}},{{.Image}},{{.Updated}},{{.Policy}}"
544
is "$output" ".*$service_name,.* (test_pod-a),$IMAGE,false,registry.*" "global auto-update policy gets applied"
545
is "$output" ".*$service_name,.* (test_pod-b),$local_image,false,local.*" "container-specified auto-update policy gets applied"
548
run_podman build -t $local_image -f $dockerfile2
549
run_podman image inspect --format "{{.ID}}" $local_image
552
assert "$oldID" != "$newID" "broken image really is a new one"
555
run_podman auto-update --dry-run --format "{{.Unit}},{{.Container}},{{.Image}},{{.Updated}},{{.Policy}}"
556
is "$output" ".*$service_name,.* (test_pod-a),$IMAGE,false,registry.*" "global auto-update policy gets applied"
557
is "$output" ".*$service_name,.* (test_pod-b),$local_image,pending,local.*" "container b sees the new image"
560
run_podman auto-update --format "{{.Unit}},{{.Container}},{{.Image}},{{.Updated}},{{.Policy}}"
561
is "$output" ".*$service_name,.* (test_pod-a),$IMAGE,rolled back,registry.*" "container a was rolled back as the update of b failed"
562
is "$output" ".*$service_name,.* (test_pod-b),$local_image,rolled back,local.*" "container b was rolled back as its update has failed"
565
systemctl stop $service_name
566
run_podman rmi -f $(pause_image) $local_image $newID $oldID
567
rm -f $UNIT_DIR/$unit_name
570
@test "podman auto-update - pod" {
571
dockerfile=$PODMAN_TMPDIR/Dockerfile
572
cat >$dockerfile <<EOF
577
podname=$(random_string)
578
ctrname=$(random_string)
579
podunit="$UNIT_DIR/pod-$podname.service.*"
580
ctrunit="$UNIT_DIR/container-$ctrname.service.*"
581
local_image=localhost/image:$(random_string 10)
583
run_podman tag $IMAGE $local_image
585
run_podman pod create --name=$podname
586
run_podman create --label "io.containers.autoupdate=local" --pod=$podname --name=$ctrname $local_image top
590
run_podman generate systemd --name --new --files $podname
591
is "$output" ".*$podunit.*"
592
is "$output" ".*$ctrunit.*"
595
systemctl daemon-reload
597
systemctl_start pod-$podname.service
598
_wait_service_ready container-$ctrname.service
600
run_podman pod inspect --format "{{.State}}" $podname
601
is "$output" "Running" "pod is in running state"
602
run_podman container inspect --format "{{.State.Status}}" $ctrname
603
is "$output" "running" "container is in running state"
605
run_podman pod inspect --format "{{.ID}}" $podname
607
run_podman container inspect --format "{{.ID}}" $ctrname
611
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
612
is "$output" ".*pod-$podname.service,$local_image,false,local.*" "No update available"
614
run_podman build -t $local_image -f $dockerfile
616
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
617
is "$output" ".*pod-$podname.service,$local_image,pending,local.*" "Image updated is pending"
619
run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
620
is "$output" ".*pod-$podname.service,$local_image,true,local.*" "Service has been restarted"
621
_wait_service_ready container-$ctrname.service
623
run_podman pod inspect --format "{{.ID}}" $podname
624
assert "$output" != "$podid" "pod has been recreated"
625
run_podman container inspect --format "{{.ID}}" $ctrname
626
assert "$output" != "$ctrid" "container has been recreated"
628
run systemctl stop pod-$podname.service
629
assert $status -eq 0 "Error stopping pod systemd unit: $output"
631
run_podman pod rm -f $podname
632
run_podman rmi $local_image $(pause_image)
633
rm -f $podunit $ctrunit
634
systemctl daemon-reload
637
@test "podman-auto-update --authfile" {
643
registry=localhost:${PODMAN_LOGIN_REGISTRY_PORT}
644
image_on_local_registry=$registry/name:tag
645
authfile=$PODMAN_TMPDIR/authfile.json
649
run_podman login --authfile=$authfile \
651
--username ${PODMAN_LOGIN_USER} \
652
--password ${PODMAN_LOGIN_PASS} \
657
run_podman push --tls-verify=false --creds "${PODMAN_LOGIN_USER}:${PODMAN_LOGIN_PASS}" $IMAGE $image_on_local_registry
658
run_podman pull --tls-verify=false --creds "${PODMAN_LOGIN_USER}:${PODMAN_LOGIN_PASS}" $image_on_local_registry
662
generate_service "" registry top "" "" "" $image_on_local_registry
664
_wait_service_ready container-$ctr.service
666
run_podman 125 auto-update
668
".*Error: checking image updates for container .*: x509: .*"
670
run_podman 125 auto-update --tls-verify=false
672
".*Error: checking image updates for container .*: authentication required"
675
run_podman auto-update --authfile=$authfile --tls-verify=false --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
676
is "$output" "container-$ctr.service,$image_on_local_registry,false,registry" "auto-update works with authfile"
679
REGISTRY_AUTH_FILE=$authfile run_podman auto-update --tls-verify=false --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
680
is "$output" "container-$ctr.service,$image_on_local_registry,false,registry" "auto-update works with env var"
681
systemctl stop container-$ctr.service
682
run_podman rm -f -t0 --ignore $ctr
685
generate_service "" registry top "--label io.containers.autoupdate.authfile=$authfile" "" "" $image_on_local_registry
687
_wait_service_ready container-$ctr.service
691
run_podman auto-update --authfile=/dev/null --tls-verify=false --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
692
is "$output" "container-$ctr.service,$image_on_local_registry,false,registry" "auto-update works with authfile container label"
693
run_podman rm -f -t0 --ignore $ctr
694
run_podman rmi $image_on_local_registry