CI: use local registry, part 2 of 3: fix tests

This commit gets tests working under the new local-registry system:

  * amend a few image names, mostly just sticking to a consistent
    list of those images in our registry cache. Mostly minor
    tag updates.

  * trickier: pull_test: change some error messages, and remove
    a test that's now a NOP. Basically, with a local (unprotected)
    registry we always get "404 manifest unknown"; with a real
    registry we'll get "403 I can't tell you".

  * trickiest: seccomp_test: build our own images at run time,
    with our desired labels. Until now we've been pulling
    prebuilt images, but those will not copy to the local
    cache registry. Something about v1? Anyhow, I gave up
    trying to cache them, and the workaround is straightforward.

Also took the liberty of strengthening a few error-message checks

Signed-off-by: Ed Santiago <santiago@redhat.com>
This commit is contained in:
Ed Santiago
2024-06-06 13:15:52 -06:00
parent 2e8c074234
commit dd1bcabae9
15 changed files with 119 additions and 89 deletions

View File

@ -124,6 +124,7 @@ exec_container() {
# VM Images and Container images are built using (nearly) identical operations.
set -x
env CONTAINERS_REGISTRIES_CONF=/dev/null bin/podman pull -q $CTR_FQIN
# shellcheck disable=SC2154
exec bin/podman run --rm --privileged --net=host --cgroupns=host \
-v `mktemp -d -p /var/tmp`:/var/tmp:Z \

View File

@ -7,7 +7,7 @@ ME=$(basename $0)
###############################################################################
# BEGIN defaults
PODMAN_REGISTRY_IMAGE=quay.io/libpod/registry:2.8
PODMAN_REGISTRY_IMAGE=quay.io/libpod/registry:2.8.2
PODMAN_REGISTRY_USER=
PODMAN_REGISTRY_PASS=

View File

@ -177,7 +177,7 @@ var _ = Describe("Podman images", func() {
// Adding one more image. There Should be no errors in the response.
// And the count should be three now.
bt.Pull("testimage:20200929")
bt.Pull("testimage:20221018")
imageSummary, err = images.List(bt.conn, nil)
Expect(err).ToNot(HaveOccurred())
Expect(len(imageSummary)).To(BeNumerically(">=", 2))

View File

@ -7,7 +7,9 @@
podman pull -q $IMAGE
t GET libpod/images/json 200 \
.[0].Id~[0-9a-f]\\{64\\}
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Names[0]="$IMAGE"
iid=$(jq -r '.[0].Id' <<<"$output")
# Create an empty manifest and make sure it is not listed
@ -18,7 +20,7 @@ t GET images/json 200 length=1
t GET libpod/images/json 200 length=2
t GET libpod/images/$iid/exists 204
t GET libpod/images/$PODMAN_TEST_IMAGE_NAME/exists 204
t GET libpod/images/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG/exists 204
t GET libpod/images/${iid}abcdef/exists 404 \
.cause="failed to find image ${iid}abcdef"
@ -51,11 +53,13 @@ t GET images/$iid/json 200 \
t POST "images/create?fromImage=alpine" 200 .error~null .status~".*Download complete.*"
t POST "libpod/images/pull?reference=alpine&compatMode=true" 200 .error~null .status~".*Download complete.*"
t POST "images/create?fromImage=alpine&tag=latest" 200
t POST "images/create?fromImage=alpine&tag=latest" 200 \
.status~"Already exists"
# 10977 - handle platform parameter correctly
t POST "images/create?fromImage=quay.io/libpod/testimage:20240123&platform=linux/arm64" 200
t GET "images/testimage:20240123/json" 200 \
# THIS IMAGE MUST NOT BE THE SAME AS $IMAGE
t POST "images/create?fromImage=quay.io/libpod/testimage:20221018&platform=linux/arm64" 200
t GET "images/testimage:20221018/json" 200 \
.Architecture=arm64
# Make sure that new images are pulled
@ -78,34 +82,42 @@ t POST /images/create?fromImage=busybox:invalidtag123 404
# Display the image history
t GET libpod/images/nonesuch/history 404
for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME; do
for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG; do
t GET libpod/images/$i/history 200 \
.[0].Id=$iid \
.[0].Created~[0-9]\\{10\\} \
.[0].Tags[0]="$IMAGE" \
.[0].Size=0 \
.[0].Comment=
.[0].Size=1024 \
.[0].Comment="FROM localhost/interim-image:latest"
done
for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME; do
for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG; do
t GET images/$i/history 200 \
.[0].Id="sha256:"$iid \
.[0].Created~[0-9]\\{10\\} \
.[0].Tags[0]="$IMAGE" \
.[0].Size=0 \
.[0].Comment=
.[0].Size=1024 \
.[0].Comment="FROM localhost/interim-image:latest"
done
# compat api pull image unauthorized message error
t POST "/images/create?fromImage=quay.io/idonotexist/idonotexist:dummy" 401 \
.message="unauthorized: access to the requested resource is not authorized"
# This depends on whether we're using local cache registry or real quay
expect_code=401
expect_msg="unauthorized: access to the requested resource is not authorized"
if [[ -n "$CI_USE_REGISTRY_CACHE" ]]; then
# local registry has no auth, so it can return 404
expect_code=404
expect_msg="manifest unknown: manifest unknown"
fi
t POST "/images/create?fromImage=quay.io/idonotexist/idonotexist:dummy" $expect_code \
.message="$expect_msg"
# Export an image on the local
t GET libpod/images/nonesuch/get 404
t GET libpod/images/$iid/get?format=foo 500
t GET libpod/images/$PODMAN_TEST_IMAGE_NAME/get?compress=bar 400
for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME; do
for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG; do
t GET "libpod/images/$i/get" 200 '[POSIX tar archive]'
t GET "libpod/images/$i/get?compress=true" 200 '[POSIX tar archive]'
t GET "libpod/images/$i/get?compress=false" 200 '[POSIX tar archive]'
@ -296,10 +308,12 @@ t DELETE libpod/images/test:test 200
# This sleep seems to avoid the race.
# If it fails and begins to flake, investigate a retry loop.
sleep 1
# FIXME 2024-05-30 #22726: when running with a local cache registry, DELETE
# sometimes produces 5-6 events instead of the desired only-one.
t GET "libpod/events?stream=false&since=$START" 200 \
'select(.status | contains("remove")).Action=remove'
'select(.status | contains("remove")).Actor.Attributes.name~.*localhost/test:test'
t GET "events?stream=false&since=$START" 200 \
'select(.status | contains("delete")).Action=delete'
'select(.status | contains("delete")).Actor.Attributes.name~.*localhost/test:test'
# Test image removal with `noprune={true,false}`
podman create --name c_test1 $IMAGE true

View File

@ -4,12 +4,10 @@
#
# WORKDIR=/data
ENV_WORKDIR_IMG=quay.io/libpod/testimage:20240123
MultiTagName=localhost/test/testformultitag:tag
podman pull $IMAGE &>/dev/null
podman tag $IMAGE $MultiTagName
podman pull $ENV_WORKDIR_IMG &>/dev/null
# Unimplemented
#t POST libpod/containers/create '' 201 'sdf'
@ -281,7 +279,7 @@ t DELETE libpod/containers/bogus 404
# test apiv2 create container with correct entrypoint and cmd
# --data '{"Image":"quay.io/libpod/alpine_labels:latest","Entrypoint":["echo"],"Cmd":["param1","param2"]}'
# --data '{"Image":"quay.io/libpod/some:thing","Entrypoint":["echo"],"Cmd":["param1","param2"]}'
t POST containers/create \
Image=$IMAGE \
Entrypoint='["echo"]' \
@ -352,7 +350,7 @@ t DELETE containers/$cid_top 204
# test the WORKDIR and StopSignal
t POST containers/create \
Image=$ENV_WORKDIR_IMG \
Image=$IMAGE \
WorkingDir=/dataDir \
StopSignal=\"9\" \
201 \
@ -406,7 +404,7 @@ t GET containers/json 200 \
podman stop bar
#compat api list containers sanity checks
podman run -d --rm --name labelcontainer_with $ENV_WORKDIR_IMG top
podman run -d --rm --name labelcontainer_with --label slartibart=fast $IMAGE top
podman run -d --rm --name labelcontainer_without $IMAGE top
t GET containers/json?filters='garb1age}' 500 \
@ -436,10 +434,10 @@ t POST containers/prune?filters='{"label":["tes' 500 \
t POST libpod/containers/prune?filters='{"label":["tes' 500 \
.cause="unexpected end of JSON input"
t GET libpod/containers/json?filters='{"label":["created_by"]}' 200 \
t GET libpod/containers/json?filters='{"label":["slartibart"]}' 200 \
length=1 \
.[0].Names[0]="labelcontainer_with"
t GET libpod/containers/json?filters='{"label!":["created_by"]}' 200 \
t GET libpod/containers/json?filters='{"label!":["slartibart"]}' 200 \
length=1 \
.[0].Names[0]="labelcontainer_without"
t GET libpod/containers/json?filters='{"label!":["testlabel"]}' 200 length=2

View File

@ -11,13 +11,13 @@ ME=$(basename $0)
PODMAN_TEST_IMAGE_REGISTRY=${PODMAN_TEST_IMAGE_REGISTRY:-"quay.io"}
PODMAN_TEST_IMAGE_USER=${PODMAN_TEST_IMAGE_USER:-"libpod"}
PODMAN_TEST_IMAGE_NAME=${PODMAN_TEST_IMAGE_NAME:-"alpine_labels"}
PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"latest"}
PODMAN_TEST_IMAGE_NAME=${PODMAN_TEST_IMAGE_NAME:-"testimage"}
PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"20240123"}
PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG"
IMAGE=$PODMAN_TEST_IMAGE_FQN
REGISTRY_IMAGE="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/registry:2.7"
REGISTRY_IMAGE="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/registry:2.8.2"
# END stuff you can but probably shouldn't customize
###############################################################################
@ -54,6 +54,14 @@ fi
# Path to podman binary
PODMAN_BIN=${PODMAN:-${CONTAINERS_HELPER_BINARY_DIR}/podman}
# Path to registries.conf file. CI uses a locally-running cache registry,
# but we can't expect developers to have that in their local environment.
registries_conf_file=registries.conf
if [[ -n "$CI_USE_REGISTRY_CACHE" ]]; then
registries_conf_file=registries-cached.conf
fi
registries_conf_path=$TESTS_DIR/../$registries_conf_file
# Cleanup handlers
clean_up_server() {
if [ -n "$service_pid" ]; then
@ -474,7 +482,7 @@ function start_service() {
$PODMAN_BIN unshare true
fi
CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf \
CONTAINERS_REGISTRIES_CONF=$registries_conf_path \
$PODMAN_BIN \
--root $WORKDIR/server_root --syslog=true \
system service \
@ -526,7 +534,7 @@ function start_registry() {
mkdir -p $AUTHDIR
mkdir -p ${REGDIR}/{root,runroot}
local PODMAN_REGISTRY_ARGS="--root ${REGDIR}/root --runroot ${REGDIR}/runroot"
local PODMAN_REGISTRY_ARGS="--root ${REGDIR}/root --runroot ${REGDIR}/runroot --tmpdir ${REGDIR}/tmp"
# Give it three tries, to compensate for network flakes
podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE ||
@ -644,7 +652,7 @@ function wait_for_port() {
############
function podman() {
echo "\$ $PODMAN_BIN $*" >>$WORKDIR/output.log
# env CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf \
env CONTAINERS_REGISTRIES_CONF=$registries_conf_path \
$PODMAN_BIN --root $WORKDIR/server_root "$@" >>$WORKDIR/output.log 2>&1
}

View File

@ -1493,3 +1493,7 @@ func CopySymLink(source, dest string) error {
}
return os.Symlink(link, dest)
}
func UsingCacheRegistry() bool {
return os.Getenv("CI_USE_REGISTRY_CACHE") != ""
}

View File

@ -15,15 +15,6 @@ var (
HEALTHCHECK_IMAGE = "quay.io/libpod/alpine_healthcheck:latest" //nolint:revive,stylecheck
volumeTest = "quay.io/libpod/volume-plugin-test-img:20220623"
// This image has seccomp profiles that blocks all syscalls.
// The intention behind blocking all syscalls is to prevent
// regressions in the future. The required syscalls can vary
// depending on which runtime we're using.
alpineSeccomp = "quay.io/libpod/alpine-with-seccomp:label"
// This image has a bogus/invalid seccomp profile which should
// yield a json error when being read.
alpineBogusSeccomp = "quay.io/libpod/alpine-with-bogus-seccomp:label"
// ImageCacheDir is initialized at runtime.
// e.g., filepath.Join(os.TempDir(), "imagecachedir")
// This directory should be used by per-user.

View File

@ -117,13 +117,11 @@ var _ = Describe("Podman Info", func() {
Expect(session.OutputToString()).To(Equal("false"))
}
session = podmanTest.Podman([]string{"info", "--format", "{{.Host.RemoteSocket.Exists}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
if IsRemote() {
Expect(session.OutputToString()).To(ContainSubstring("true"))
} else {
Expect(session.OutputToString()).To(ContainSubstring("false"))
session = podmanTest.Podman([]string{"info", "--format", "{{.Host.RemoteSocket.Exists}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("true"))
}
})

View File

@ -49,8 +49,12 @@ func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os
}
func (p *PodmanTestIntegration) setDefaultRegistriesConfigEnv() {
defaultFile := filepath.Join(INTEGRATION_ROOT, "test/registries.conf")
os.Setenv("CONTAINERS_REGISTRIES_CONF", defaultFile)
defaultFile := "registries.conf"
if UsingCacheRegistry() {
defaultFile = "registries-cached.conf"
}
defaultPath := filepath.Join(INTEGRATION_ROOT, "test", defaultFile)
os.Setenv("CONTAINERS_REGISTRIES_CONF", defaultPath)
}
func (p *PodmanTestIntegration) setRegistriesConfigEnv(b []byte) {

View File

@ -37,8 +37,12 @@ func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os
}
func (p *PodmanTestIntegration) setDefaultRegistriesConfigEnv() {
defaultFile := filepath.Join(INTEGRATION_ROOT, "test/registries.conf")
err := os.Setenv("CONTAINERS_REGISTRIES_CONF", defaultFile)
defaultFile := "registries.conf"
if UsingCacheRegistry() {
defaultFile = "registries-cached.conf"
}
defaultPath := filepath.Join(INTEGRATION_ROOT, "test", defaultFile)
err := os.Setenv("CONTAINERS_REGISTRIES_CONF", defaultPath)
Expect(err).ToNot(HaveOccurred())
}

View File

@ -148,7 +148,7 @@ var _ = Describe("Podman load", func() {
Skip("skip on ppc64le")
}
outfile := filepath.Join(podmanTest.TempDir, "alpine.tar")
alpVersion := "quay.io/libpod/alpine:3.2"
alpVersion := "quay.io/libpod/alpine:3.10.2"
pull := podmanTest.Podman([]string{"pull", "-q", alpVersion})
pull.WaitWithDefaultTimeout()
@ -169,9 +169,12 @@ var _ = Describe("Podman load", func() {
inspect := podmanTest.Podman([]string{"inspect", ALPINE})
inspect.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
Expect(result.OutputToString()).To(ContainSubstring(alpVersion))
inspect = podmanTest.Podman([]string{"inspect", alpVersion})
inspect.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
Expect(result.OutputToString()).To(ContainSubstring(alpVersion))
})
It("podman load localhost registry from scratch", func() {

View File

@ -21,26 +21,21 @@ var _ = Describe("Podman pull", func() {
session = podmanTest.Podman([]string{"pull", "busybox:latest", "docker.io/library/ibetthisdoesnotexistfr:random", "alpine"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitWithError(125, "initializing source docker://ibetthisdoesnotexistfr:random: reading manifest random in quay.io/libpod/ibetthisdoesnotexistfr:"))
// As of 2024-06 all Cirrus tests run using a local registry where
// we get 404. When running in dev environment, though, we still
// test against real registry, which returns 401
expect := "quay.io/libpod/ibetthisdoesnotexistfr: unauthorized: access to the requested resource is not authorized"
if UsingCacheRegistry() {
expect = "127.0.0.1:60333/libpod/ibetthisdoesnotexistfr: manifest unknown"
}
Expect(session).Should(ExitWithError(125, "initializing source docker://ibetthisdoesnotexistfr:random: reading manifest random in "+expect))
session = podmanTest.Podman([]string{"rmi", "busybox:musl", "alpine", "quay.io/libpod/cirros", "testdigest_v2s2@sha256:755f4d90b3716e2bf57060d249e2cd61c9ac089b1233465c5c2cb2d7ee550fdb"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman pull bogus image", func() {
// This is a NOP in CI; but in a developer environment, if user
// has a valid login to quay.io, pull fails with "repository not found"
defer func() {
os.Unsetenv("REGISTRY_AUTH_FILE")
}()
os.Setenv("REGISTRY_AUTH_FILE", "/tmp/this/does/not/exist")
session := podmanTest.Podman([]string{"pull", "quay.io/libpod/ibetthisdoesntexist:there"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, "nitializing source docker://quay.io/libpod/ibetthisdoesntexist:there: reading manifest there in quay.io/libpod/ibetthisdoesntexist: unauthorized: access to the requested resource is not authorized"))
})
It("podman pull with tag --quiet", func() {
session := podmanTest.Podman([]string{"pull", "-q", "quay.io/libpod/testdigest_v2s2:20200210"})
session.WaitWithDefaultTimeout()

View File

@ -2,59 +2,69 @@ package integration
import (
"fmt"
"path/filepath"
. "github.com/containers/podman/v5/test/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
// Create an image with the given seccomp label
func makeLabeledImage(seccompLabel string) string {
ctrName := "temp-working-container"
imgName := "workingimage"
session := podmanTest.Podman([]string{"run", "--name", ctrName, CITEST_IMAGE, "true"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitCleanly())
session = podmanTest.Podman([]string{"commit", "-q", "--change", "LABEL io.containers.seccomp.profile=" + seccompLabel, ctrName, imgName})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitCleanly())
return imgName
}
var _ = Describe("Podman run", func() {
It("podman run --seccomp-policy default", func() {
session := podmanTest.Podman([]string{"run", "-q", "--seccomp-policy", "default", alpineSeccomp, "ls"})
session := podmanTest.Podman([]string{"run", "-q", "--seccomp-policy", "default", CITEST_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman run --seccomp-policy ''", func() {
// Empty string is interpreted as "default".
session := podmanTest.Podman([]string{"run", "-q", "--seccomp-policy", "", alpineSeccomp, "ls"})
session := podmanTest.Podman([]string{"run", "-q", "--seccomp-policy", "", CITEST_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman run --seccomp-policy invalid", func() {
session := podmanTest.Podman([]string{"run", "--seccomp-policy", "invalid", alpineSeccomp, "ls"})
session := podmanTest.Podman([]string{"run", "--seccomp-policy", "invalid", CITEST_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, `invalid seccomp policy "invalid": valid policies are ["default" "image"]`))
})
It("podman run --seccomp-policy image (block all syscalls)", func() {
session := podmanTest.Podman([]string{"run", "--seccomp-policy", "image", alpineSeccomp, "ls"})
// This image has seccomp profiles that blocks all syscalls.
// The intention behind blocking all syscalls is to prevent
// regressions in the future. The required syscalls can vary
// depending on which runtime we're using.
img := makeLabeledImage(`'{"defaultAction":"SCMP_ACT_ERRNO"}'`)
session := podmanTest.Podman([]string{"run", "--seccomp-policy", "image", img, "ls"})
session.WaitWithDefaultTimeout()
// TODO: we're getting a "cannot start a container that has
// stopped" error which seems surprising. Investigate
// why that is so.
base := filepath.Base(podmanTest.OCIRuntime)
if base == "runc" {
// TODO: worse than that. With runc, we get two alternating failures:
// 126 + cannot start a container that has stopped
// 127 + failed to connect to container's attach socket ... ENOENT
Expect(session.ExitCode()).To(BeNumerically(">=", 126), "Exit status using runc")
} else if base == "crun" {
expect := fmt.Sprintf("OCI runtime error: %s: read from the init process", podmanTest.OCIRuntime)
if IsRemote() {
expect = fmt.Sprintf("for attach: %s: read from the init process: OCI runtime error", podmanTest.OCIRuntime)
}
Expect(session).To(ExitWithError(126, expect))
} else {
Skip("Not valid with the current OCI runtime")
expect := fmt.Sprintf("OCI runtime error: %s: read from the init process", podmanTest.OCIRuntime)
if IsRemote() {
expect = fmt.Sprintf("for attach: %s: read from the init process: OCI runtime error", podmanTest.OCIRuntime)
}
Expect(session).To(ExitWithError(126, expect))
})
It("podman run --seccomp-policy image (bogus profile)", func() {
session := podmanTest.Podman([]string{"run", "--seccomp-policy", "image", alpineBogusSeccomp, "ls"})
// This image has a bogus/invalid seccomp profile which should
// yield a json error when being read.
img := makeLabeledImage(`'BOGUS - this should yield an error'`)
session := podmanTest.Podman([]string{"run", "--seccomp-policy", "image", img, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitWithError(125, "loading seccomp profile failed: decoding seccomp profile failed: invalid character 'B' looking for beginning of value"))
})

View File

@ -34,7 +34,7 @@ function start_registry() {
mkdir -p $AUTHDIR
# Registry image; copy of docker.io, but on our own registry
local REGISTRY_IMAGE="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/registry:2.8"
local REGISTRY_IMAGE="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/registry:2.8.2"
# Pull registry image, but into a separate container storage and DB and everything
PODMAN_LOGIN_ARGS="--storage-driver vfs $(podman_isolation_opts ${PODMAN_LOGIN_WORKDIR})"