diff --git a/pkg/api/handlers/libpod/quadlets.go b/pkg/api/handlers/libpod/quadlets.go index a54054ea15e..dd9467d489f 100644 --- a/pkg/api/handlers/libpod/quadlets.go +++ b/pkg/api/handlers/libpod/quadlets.go @@ -236,6 +236,16 @@ func InstallQuadlets(w http.ResponseWriter, r *http.Request) { return } + // QuadletInstall expects the quadlet file to be first in the list. + // filepath.Walk returns files in lexicographic order, so a non-quadlet + // file (e.g. "Containerfile") may sort before the ".container" file. + for i, filePath := range filePaths { + if quadlet.IsExtSupported(filePath) { + filePaths[0], filePaths[i] = filePaths[i], filePaths[0] + break + } + } + containerEngine := abi.ContainerEngine{Libpod: runtime} installOptions := entities.QuadletInstallOptions{ Replace: query.Replace, diff --git a/test/apiv2/36-quadlets.at b/test/apiv2/36-quadlets.at index 90646deda5d..edddde4e32e 100644 --- a/test/apiv2/36-quadlets.at +++ b/test/apiv2/36-quadlets.at @@ -213,7 +213,8 @@ t POST "libpod/quadlets" "$TMPD/$quadlet_3_4.tar" 400 \ # Scenario: install tar that contains one quadlet file and a non-quadlet file will succeed # then update the quadlet file, and the non-quadlet file, and verify the update is successful quadlet_5=quadlet-test-5-$(cat /proc/sys/kernel/random/uuid).container -containerfile_1=quadlet-test-containerfile-1-$(cat /proc/sys/kernel/random/uuid).Containerfile +containerfile_1=quadlet-test-containerfile-1-$(cat /proc/sys/kernel/random/uuid) +configfile_1=quadlet-test-configfile-1-$(cat /proc/sys/kernel/random/uuid).conf containerfile_1_content=$(cat << EOF FROM quay.io/podman/hello @@ -241,17 +242,25 @@ CMD ["echo", "Updated"] EOF ) +configfile_1_content=$(cat << EOF +[ini] +foo=bar +EOF +) + echo "$quadlet_5_content" > "$TMPD/$quadlet_5" echo "$containerfile_1_content" > "$TMPD/$containerfile_1" -tar --format=posix -C "$TMPD" -cvf "$TMPD/$quadlet_5$containerfile_1.tar" "$quadlet_5" "$containerfile_1" &> /dev/null +echo "$configfile_1_content" > "$TMPD/$configfile_1" +tar --format=posix -C "$TMPD" -cvf "$TMPD/$quadlet_5$containerfile_1.tar" "$quadlet_5" "$containerfile_1" "$configfile_1" &> /dev/null t POST "libpod/quadlets" "$TMPD/$quadlet_5$containerfile_1.tar" 200 \ - '.InstalledQuadlets|length=2' \ + '.InstalledQuadlets|length=3' \ '.QuadletErrors|length=0' t GET "libpod/quadlets/$quadlet_5/file" 200 is "$output" "$quadlet_5_content" "quadlet-5 should be installed" is "$(cat "$quadlet_install_dir/$containerfile_1")" "$containerfile_1_content" "containerfile_1 should be installed" +is "$(cat "$quadlet_install_dir/$configfile_1")" "$configfile_1_content" "configfile_1 should be installed" echo "$quadlet_5_updated_content" > "$TMPD/$quadlet_5" echo "$containerfile_1_updated_content" > "$TMPD/$containerfile_1" @@ -273,6 +282,36 @@ t GET "libpod/quadlets/$quadlet_5/file" 200 is "$output" "$quadlet_5_updated_content" "quadlet-5 should be updated" is "$(cat "$quadlet_install_dir/$containerfile_1")" "$containerfile_1_updated_content" "containerfile_1 should be installed" +# Scenario: install tar where a non-quadlet file sorts lexicographically before the quadlet file. +# "AAA-" sorts before "quadlet-test-", exercising the file ordering in the API handler. +quadlet_7=quadlet-test-7-$(cat /proc/sys/kernel/random/uuid).container +containerfile_3=AAA-containerfile-$(cat /proc/sys/kernel/random/uuid) + +quadlet_7_content=$(cat << EOF +[Container] +ContainerName=quadlet-7 +Image=quay.io/podman/hello +EOF +) + +containerfile_3_content=$(cat << EOF +FROM quay.io/podman/hello +CMD ["echo", "hello"] +EOF +) + +echo "$quadlet_7_content" > "$TMPD/$quadlet_7" +echo "$containerfile_3_content" > "$TMPD/$containerfile_3" +tar --format=posix -C "$TMPD" -cvf "$TMPD/$quadlet_7$containerfile_3.tar" "$quadlet_7" "$containerfile_3" &> /dev/null + +t POST "libpod/quadlets" "$TMPD/$quadlet_7$containerfile_3.tar" 200 \ + '.InstalledQuadlets|length=2' \ + '.QuadletErrors|length=0' + +t GET "libpod/quadlets/$quadlet_7/file" 200 +is "$output" "$quadlet_7_content" "quadlet-7 should be installed" +is "$(cat "$quadlet_install_dir/$containerfile_3")" "$containerfile_3_content" "containerfile_3 should be installed" + # Scenario: test a multipart call, then update without replace, and then replace quadlet_6=quadlet-test-6-$(cat /proc/sys/kernel/random/uuid).container containerfile_2=quadlet-test-containerfile-2-$(cat /proc/sys/kernel/random/uuid).Containerfile @@ -332,10 +371,13 @@ is "$(cat "$quadlet_install_dir/$containerfile_2")" "$containerfile_2_updated_co podman quadlet rm "$quadlet_1" \ "$quadlet_5" \ - "$quadlet_6" + "$quadlet_6" \ + "$quadlet_7" rm -f "$quadlet_install_dir/$containerfile_1" +rm -f "$quadlet_install_dir/$configfile_1" rm -f "$quadlet_install_dir/$containerfile_2" +rm -f "$quadlet_install_dir/$containerfile_3" rm -rf $TMPD # DELETE endpoint tests