diff options
38 files changed, 742 insertions, 163 deletions
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index e5124d8e4..050fb16f3 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -6,25 +6,23 @@ # BEGIN Global export of all variables set -a -if [[ "$CI" == "true" ]]; then - # Due to differences across platforms and runtime execution environments, - # handling of the (otherwise) default shell setup is non-uniform. Rather - # than attempt to workaround differences, simply force-load/set required - # items every time this library is utilized. - source /etc/profile - source /etc/environment - USER="$(whoami)" - HOME="$(getent passwd $USER | cut -d : -f 6)" - # Some platforms set and make this read-only - [[ -n "$UID" ]] || \ - UID=$(getent passwd $USER | cut -d : -f 3) - GID=$(getent passwd $USER | cut -d : -f 4) -fi +# Due to differences across platforms and runtime execution environments, +# handling of the (otherwise) default shell setup is non-uniform. Rather +# than attempt to workaround differences, simply force-load/set required +# items every time this library is utilized. +source /etc/profile +source /etc/environment +if [[ -r "/etc/ci_environment" ]]; then source /etc/ci_environment; fi +USER="$(whoami)" +HOME="$(getent passwd $USER | cut -d : -f 6)" +# Some platforms set and make this read-only +[[ -n "$UID" ]] || \ + UID=$(getent passwd $USER | cut -d : -f 3) # During VM Image build, the 'containers/automation' installation -# was performed. The final step of that installation sets the -# installation location in $AUTOMATION_LIB_PATH in /etc/environment -# or in the default shell profile. +# was performed. The final step of installation sets the library +# location $AUTOMATION_LIB_PATH in /etc/environment or in the +# default shell profile depending on distribution. # shellcheck disable=SC2154 if [[ -n "$AUTOMATION_LIB_PATH" ]]; then for libname in defaults anchors console_output utils; do @@ -88,8 +86,10 @@ CIRRUS_BUILD_ID=${CIRRUS_BUILD_ID:-$RANDOM$(date +%s)} # must be short and uniq # The starting place for linting and code validation EPOCH_TEST_COMMIT="$CIRRUS_BASE_SHA" -# Regex of env. vars. to explicitly pass when executing tests -# inside a container or as a rootless user +# Regex defining all CI-releated env. vars. necessary for all possible +# testing operations on all platforms and versions. This is necessary +# to avoid needlessly passing through global/system values across +# contexts, such as host->container or root->rootless user PASSTHROUGH_ENV_RE='(^CI.*)|(^CIRRUS)|(^DISTRO_NV)|(^GOPATH)|(^GOCACHE)|(^GOSRC)|(^SCRIPT_BASE)|(CGROUP_MANAGER)|(OCI_RUNTIME)|(^TEST.*)|(^PODBIN_NAME)|(^PRIV_NAME)|(^ALT_NAME)|(^ROOTLESS_USER)|(SKIP_USERNS)|(.*_NAME)|(.*_FQIN)' # Unsafe env. vars for display SECRET_ENV_RE='(ACCOUNT)|(GC[EP]..+)|(SSH)|(PASSWORD)|(TOKEN)' @@ -107,10 +107,8 @@ lilto() { err_retry 8 1000 "" "$@"; } # just over 4 minutes max bigto() { err_retry 7 5670 "" "$@"; } # 12 minutes max # Print shell-escaped variable=value pairs, one per line, based on -# variable name matching a regex. This is intended to support -# passthrough of CI variables from host -> container or from root -> user. -# For all other vars. we rely on tooling to load this library from inside -# the container or as rootless user to pickup the remainder. +# variable name matching a regex. This is intended to catch +# variables being passed down from higher layers, like Cirrus-CI. passthrough_envars(){ local xchars local envname @@ -176,22 +174,7 @@ setup_rootless() { echo "${ROOTLESS_USER}:$[rootless_uid * 100]:65536" | \ tee -a /etc/subuid >> /etc/subgid - # Env. vars set by Cirrus and setup_environment.sh must be explicitly - # transferred to the test-user. - msg "Configuring rootless user's environment variables:" - - ( - echo "# Added by ${BASH_SOURCE[0]} ${FUNCNAME[0]}()" - echo "export SETUP_ENVIRONMENT=1" - ) >> "/home/$ROOTLESS_USER/.bashrc" - - while read -r env_var_val; do - echo "export $env_var_val" >> "/home/$ROOTLESS_USER/.bashrc" - done <<<"$(passthrough_envars)" - chown $ROOTLESS_USER:$ROOTLESS_USER "/home/$ROOTLESS_USER/.bashrc" - cat "/home/$ROOTLESS_USER/.bashrc" | indent 2 - - msg "Ensure the systems ssh process is up and running within 5 minutes" + msg "Ensure the ssh daemon is up and running within 5 minutes" systemctl start sshd lilto ssh $ROOTLESS_USER@localhost \ -o UserKnownHostsFile=/dev/null \ @@ -208,6 +191,7 @@ install_test_configs() { # as the default). This config prevents allocation of network address space used # by default in google cloud. https://cloud.google.com/vpc/docs/vpc#ip-ranges install -v -D -m 644 $SCRIPT_BASE/99-do-not-use-google-subnets.conflist /etc/cni/net.d/ + install -v -D -m 644 ./test/registries.conf /etc/containers/ } diff --git a/contrib/cirrus/logcollector.sh b/contrib/cirrus/logcollector.sh index 9dcc252c0..746bccec9 100755 --- a/contrib/cirrus/logcollector.sh +++ b/contrib/cirrus/logcollector.sh @@ -45,8 +45,10 @@ case $1 in containernetworking-plugins \ containers-common \ criu \ + crun \ golang \ podman \ + runc \ skopeo \ slirp4netns \ ) @@ -56,9 +58,7 @@ case $1 in PKG_LST_CMD='rpm -q --qf=%{N}-%{V}-%{R}-%{ARCH}\n' PKG_NAMES+=(\ container-selinux \ - crun \ libseccomp \ - runc \ ) ;; ubuntu*) diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh index b97a696d9..084b196a9 100755 --- a/contrib/cirrus/runner.sh +++ b/contrib/cirrus/runner.sh @@ -40,7 +40,7 @@ function _run_automation() { req_env_vars CI DEST_BRANCH IMAGE_SUFFIX TEST_FLAVOR TEST_ENVIRON \ PODBIN_NAME PRIV_NAME DISTRO_NV CONTAINER USER HOME \ - UID GID AUTOMATION_LIB_PATH SCRIPT_BASE OS_RELEASE_ID \ + UID AUTOMATION_LIB_PATH SCRIPT_BASE OS_RELEASE_ID \ OS_RELEASE_VER CG_FS_TYPE bigto ooe.sh dnf install -y ShellCheck # small/quick addition $SCRIPT_BASE/shellcheck.sh diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 3135a5e65..a3840d7e6 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -1,5 +1,12 @@ #!/usr/bin/env bash +# This script is intended to be executed early by automation before +# performing other substantial operations. It relies heavily on +# desired setup information being passed in environment variables +# from Cirrus-CI and/or other orchestration tooling. To that end, +# VM's must always be considered single-purpose, single-use, +# disposable entities. i.e. One setup, one test, then always discarded. + set -e # shellcheck source=./contrib/cirrus/lib.sh @@ -29,6 +36,17 @@ do fi done +# Ensure that all lower-level contexts and child-processes have +# ready access to higher level orchestration (e.g Cirrus-CI) +# variables. +echo -e "\n# Begin single-use VM global variables (${BASH_SOURCE[0]})" \ + > "/etc/ci_environment" +( + while read -r env_var_val; do + echo "$env_var_val" + done <<<"$(passthrough_envars)" +) >> "/etc/ci_environment" + # This is a possible manual maintenance gaff, check to be sure everything matches. # shellcheck disable=SC2154 [[ "$DISTRO_NV" == "$OS_REL_VER" ]] || \ @@ -50,9 +68,9 @@ case "$CG_FS_TYPE" in if ((CONTAINER==0)); then warn "Forcing testing with runc instead of crun" if [[ "$OS_RELEASE_ID" == "ubuntu" ]]; then - echo "export OCI_RUNTIME=/usr/lib/cri-o-runc/sbin/runc" >> /etc/environment + echo "OCI_RUNTIME=/usr/lib/cri-o-runc/sbin/runc" >> /etc/ci_environment else - echo "export OCI_RUNTIME=runc" >> /etc/environment + echo "OCI_RUNTIME=runc" >> /etc/ci_environment fi fi ;; @@ -61,7 +79,7 @@ case "$CG_FS_TYPE" in # This is necessary since we've built/installed from source, # which uses runc as the default. warn "Forcing testing with crun instead of runc" - echo "export OCI_RUNTIME=crun" >> /etc/environment + echo "OCI_RUNTIME=crun" >> /etc/ci_environment fi ;; *) die_unknown CG_FS_TYPE @@ -91,15 +109,13 @@ case "$TEST_ENVIRON" in host) if [[ "$OS_RELEASE_ID" == "fedora" ]]; then # The e2e tests wrongly guess `--cgroup-manager cgroupfs` - msg "Forcing CGROUP_MANAGER=systemd" - _cgm="export CGROUP_MANAGER=systemd" - echo "$_cgm" >> /etc/environment - source /etc/environment + warn "Forcing CGROUP_MANAGER=systemd" + echo "CGROUP_MANAGER=systemd" >> /etc/ci_environment fi ;; container) if ((CONTAINER==0)); then # not yet inside a container - msg "Force loading iptables modules" + warn "Force loading iptables modules" # Since CRIU 3.11, uses iptables to lock and unlock # the network during checkpoint and restore. Needs # the following two modules loaded on the host. @@ -107,10 +123,8 @@ case "$TEST_ENVIRON" in modprobe iptable_nat || : else # The e2e tests wrongly guess `--cgroup-manager systemd` - msg "Forcing CGROUP_MANAGER=cgroupfs" - _cgm="export CGROUP_MANAGER=cgroupfs" - echo "$_cgm" >> /etc/environment - source /etc/environment + warn "Forcing CGROUP_MANAGER=cgroupfs" + echo "CGROUP_MANAGER=cgroupfs" >> /etc/ci_environment fi ;; *) die_unknown TEST_ENVIRON @@ -123,15 +137,14 @@ case "$PRIV_NAME" in if [[ "$TEST_ENVIRON" == "container" ]] && ((container)); then # There's no practical way to detect userns w/in a container # affected/related tests are sensitive to this variable. - _suns='export SKIP_USERNS=1' - echo "$_suns" >> /etc/environment - source /etc/environment + warn "Disabling usernamespace integration testing" + echo "SKIP_USERNS=1" >> /etc/ci_environment fi ;; rootless) - _ru="export ROOTLESS_USER='${ROOTLESS_USER:-some${RANDOM}dude}'" - echo "$_ru" >> /etc/environment - source /etc/environment + # Needs to exist for setup_rootless() + ROOTLESS_USER="${ROOTLESS_USER:-some${RANDOM}dude}" + echo "ROOTLESS_USER=$ROOTLESS_USER" >> /etc/ci_environment setup_rootless ;; *) die_unknown PRIV_NAME @@ -178,11 +191,18 @@ case "$TEST_FLAVOR" in remove_packaged_podman_files make install PREFIX=/usr ETCDIR=/etc fi + + install_test_configs ;; vendor) make clean ;; release) ;; *) die_unknown TEST_FLAVOR esac -# Must be the very last command. Establishes successful setup. -echo 'export SETUP_ENVIRONMENT=1' >> /etc/environment +# Must be the very last command. Prevents setup from running twice. +echo 'SETUP_ENVIRONMENT=1' >> /etc/ci_environment +echo -e "\n# End of global variable definitions" \ + >> /etc/ci_environment + +msg "Global CI Environment vars.:" +cat /etc/ci_environment | sort | indent diff --git a/libpod/define/errors.go b/libpod/define/errors.go index 627928ef7..300e0d7ca 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -14,6 +14,9 @@ var ( // ErrNoSuchImage indicates the requested image does not exist ErrNoSuchImage = errors.New("no such image") + // ErrMultipleImages found multiple name and tag matches + ErrMultipleImages = errors.New("found multiple name and tag matches") + // ErrNoSuchTag indicates the requested image tag does not exist ErrNoSuchTag = errors.New("no such tag") diff --git a/libpod/image/utils.go b/libpod/image/utils.go index 2538f429b..7429a7f10 100644 --- a/libpod/image/utils.go +++ b/libpod/image/utils.go @@ -11,6 +11,7 @@ import ( "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/signature" "github.com/containers/image/v5/types" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/storage" "github.com/pkg/errors" ) @@ -42,7 +43,7 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er if len(results) == 0 { return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName) } else if len(results) > 1 { - return &storage.Image{}, errors.Errorf("found multiple name and tag matches for %s in repotags", searchName) + return &storage.Image{}, errors.Wrapf(define.ErrMultipleImages, searchName) } return results[0], nil } diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 598a46abe..55264b3b6 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -44,11 +44,16 @@ func ImageExists(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) name := utils.GetName(r) - _, err := runtime.ImageRuntime().NewFromLocal(name) + ir := abi.ImageEngine{Libpod: runtime} + report, err := ir.Exists(r.Context(), name) if err != nil { utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name)) return } + if !report.Value { + utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(nil, "failed to find image %s", name)) + return + } utils.WriteResponse(w, http.StatusNoContent, "") } diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index 681855293..7d9415f91 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -166,7 +166,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("busybox:glibc") + bt.Pull("testimage:20200929") imageSummary, err = images.List(bt.conn, nil, nil) Expect(err).To(BeNil()) Expect(len(imageSummary)).To(Equal(3)) diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 25335cf11..ef0e15264 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -39,8 +39,14 @@ const SignatureStoreDir = "/var/lib/containers/sigstore" func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) { _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID) - if err != nil && errors.Cause(err) != define.ErrNoSuchImage { - return nil, err + if err != nil { + if errors.Cause(err) == define.ErrMultipleImages { + return &entities.BoolReport{Value: true}, nil + } else { + if errors.Cause(err) != define.ErrNoSuchImage { + return nil, err + } + } } return &entities.BoolReport{Value: err == nil}, nil } diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 57c098166..613c4a6d8 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -123,7 +123,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) } } if err != nil { - logrus.Error(err) + logrus.Error(errors.Wrapf(err, "invalid internal status, try resetting the pause process with %q", os.Args[0]+" system migrate")) os.Exit(1) } if became { diff --git a/pkg/terminal/util.go b/pkg/terminal/util.go index ab3dc54e4..169bec2af 100644 --- a/pkg/terminal/util.go +++ b/pkg/terminal/util.go @@ -12,6 +12,7 @@ import ( "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/knownhosts" "golang.org/x/crypto/ssh/terminal" "k8s.io/client-go/util/homedir" ) @@ -114,6 +115,9 @@ func HostKey(host string) ssh.PublicKey { return nil } + // support -H parameter for ssh-keyscan + hashhost := knownhosts.HashHostname(host) + scanner := bufio.NewScanner(fd) for scanner.Scan() { _, hosts, key, _, _, err := ssh.ParseKnownHosts(scanner.Bytes()) @@ -123,7 +127,7 @@ func HostKey(host string) ssh.PublicKey { } for _, h := range hosts { - if h == host { + if h == host || h == hashhost { return key } } diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at index 1f5722a0c..c105a9278 100644 --- a/test/apiv2/10-images.at +++ b/test/apiv2/10-images.at @@ -43,7 +43,7 @@ t POST "images/create?fromImage=alpine" '' 200 t POST "images/create?fromImage=alpine&tag=latest" '' 200 -t POST "images/create?fromImage=docker.io/library/alpine&tag=sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f" '' 200 +t POST "images/create?fromImage=quay.io/libpod/alpine&tag=sha256:fa93b01658e3a5a1686dc3ae55f170d8de487006fb53a28efcd12ab0710a2e5f" '' 200 # Display the image history t GET libpod/images/nonesuch/history 404 diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at index d720ffa65..896e685cd 100644 --- a/test/apiv2/12-imagesMore.at +++ b/test/apiv2/12-imagesMore.at @@ -23,7 +23,7 @@ t GET libpod/images/$IMAGE/json 200 \ .RepoTags[1]=localhost:5000/myrepo:mytag # Run registry container -podman run -d --name registry -p 5000:5000 docker.io/library/registry:2.6 /entrypoint.sh /etc/docker/registry/config.yml +podman run -d --name registry -p 5000:5000 quay.io/libpod/registry:2.6 /entrypoint.sh /etc/docker/registry/config.yml # Push to local registry # FIXME: this is failing: @@ -44,5 +44,5 @@ t DELETE libpod/containers/registry?force=true 204 # Remove images t DELETE libpod/images/$IMAGE 200 \ .ExitCode=0 -t DELETE libpod/images/docker.io/library/registry:2.6 200 \ +t DELETE libpod/images/quay.io/libpod/registry:2.6 200 \ .ExitCode=0 diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index c7055dfc4..b35c27215 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -4,7 +4,7 @@ # # WORKDIR=/data -ENV_WORKDIR_IMG=docker.io/library/redis:alpine +ENV_WORKDIR_IMG=quay.io/libpod/testimage:20200929 podman pull $IMAGE &>/dev/null podman pull $ENV_WORKDIR_IMG &>/dev/null diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go index 572e55fe5..ea15e2b8d 100644 --- a/test/e2e/build_test.go +++ b/test/e2e/build_test.go @@ -226,7 +226,7 @@ var _ = Describe("Podman build", func() { podmanTest.StartRemoteService() } podmanTest.RestoreAllArtifacts() - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest RUN printenv http_proxy` dockerfilePath := filepath.Join(podmanTest.TempDir, "Dockerfile") diff --git a/test/e2e/config.go b/test/e2e/config.go index 54e39f9d2..e66cd6846 100644 --- a/test/e2e/config.go +++ b/test/e2e/config.go @@ -1,18 +1,18 @@ package integration var ( - redis = "docker.io/library/redis:alpine" + redis = "quay.io/libpod/redis:alpine" fedoraMinimal = "quay.io/libpod/fedora-minimal:latest" - ALPINE = "docker.io/library/alpine:latest" - ALPINELISTTAG = "docker.io/library/alpine:3.10.2" - ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb" - ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f" + ALPINE = "quay.io/libpod/alpine:latest" + ALPINELISTTAG = "quay.io/libpod/alpine:3.10.2" + ALPINELISTDIGEST = "quay.io/libpod/alpine@sha256:fa93b01658e3a5a1686dc3ae55f170d8de487006fb53a28efcd12ab0710a2e5f" + ALPINEAMD64DIGEST = "quay.io/libpod/alpine@sha256:634a8f35b5f16dcf4aaa0822adc0b1964bb786fca12f6831de8ddc45e5986a00" ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4" - ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e" + ALPINEARM64DIGEST = "quay.io/libpod/alpine@sha256:f270dcd11e64b85919c3bab66886e59d677cf657528ac0e4805d3c71e458e525" ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672" infra = "k8s.gcr.io/pause:3.2" - BB = "docker.io/library/busybox:latest" - healthcheck = "docker.io/libpod/alpine_healthcheck:latest" + BB = "quay.io/libpod/busybox:latest" + healthcheck = "quay.io/libpod/alpine_healthcheck:latest" ImageCacheDir = "/tmp/podman/imagecachedir" fedoraToolbox = "registry.fedoraproject.org/f32/fedora-toolbox:latest" @@ -20,8 +20,8 @@ var ( // 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 = "docker.io/libpod/alpine-with-seccomp:label" + 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 = "docker.io/libpod/alpine-with-bogus-seccomp:label" + alpineBogusSeccomp = "quay.io/libpod/alpine-with-bogus-seccomp:label" ) diff --git a/test/e2e/config_amd64.go b/test/e2e/config_amd64.go index 151120058..2323c7e6b 100644 --- a/test/e2e/config_amd64.go +++ b/test/e2e/config_amd64.go @@ -8,7 +8,7 @@ var ( CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry, infra, labels, healthcheck, ubi_init, ubi_minimal} nginx = "quay.io/libpod/alpine_nginx:latest" BB_GLIBC = "docker.io/library/busybox:glibc" - registry = "docker.io/library/registry:2.6" + registry = "quay.io/libpod/registry:2.6" labels = "quay.io/libpod/alpine_labels:latest" ubi_minimal = "registry.access.redhat.com/ubi8-minimal" ubi_init = "registry.access.redhat.com/ubi8-init" diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 6b0f7a7af..d9378abca 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -271,11 +271,11 @@ var _ = Describe("Podman create", func() { }) It("podman create --pull", func() { - session := podmanTest.PodmanNoCache([]string{"create", "--pull", "never", "--name=foo", "debian"}) + session := podmanTest.PodmanNoCache([]string{"create", "--pull", "never", "--name=foo", "testimage:00000000"}) session.WaitWithDefaultTimeout() Expect(session).To(ExitWithError()) - session = podmanTest.PodmanNoCache([]string{"create", "--pull", "always", "--name=foo", "debian"}) + session = podmanTest.PodmanNoCache([]string{"create", "--pull", "always", "--name=foo", "testimage:00000000"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go index 1076dfc61..1408e59bb 100644 --- a/test/e2e/exists_test.go +++ b/test/e2e/exists_test.go @@ -39,6 +39,7 @@ var _ = Describe("Podman image|container exists", func() { Expect(session).Should(Exit(0)) }) It("podman image exists in local storage by short name", func() { + Skip("FIXME-8165: shortnames don't seem to work with quay (#8176)") session := podmanTest.Podman([]string{"image", "exists", "alpine"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go index 71e73af9c..403f15fa7 100644 --- a/test/e2e/healthcheck_run_test.go +++ b/test/e2e/healthcheck_run_test.go @@ -81,7 +81,7 @@ var _ = Describe("Podman healthcheck run", func() { }) It("podman healthcheck that should fail", func() { - session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "docker.io/libpod/badhealthcheck:latest"}) + session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "quay.io/libpod/badhealthcheck:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go index 9344132d9..b42061c20 100644 --- a/test/e2e/images_test.go +++ b/test/e2e/images_test.go @@ -41,8 +41,8 @@ var _ = Describe("Podman images", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2)) - Expect(session.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue()) - Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue()) + Expect(session.LineInOuputStartsWith("quay.io/libpod/alpine")).To(BeTrue()) + Expect(session.LineInOuputStartsWith("quay.io/libpod/busybox")).To(BeTrue()) }) It("podman images with no images prints header", func() { @@ -62,8 +62,8 @@ var _ = Describe("Podman images", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2)) - Expect(session.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue()) - Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue()) + Expect(session.LineInOuputStartsWith("quay.io/libpod/alpine")).To(BeTrue()) + Expect(session.LineInOuputStartsWith("quay.io/libpod/busybox")).To(BeTrue()) }) It("podman images with multiple tags", func() { @@ -80,13 +80,13 @@ var _ = Describe("Podman images", func() { session = podmanTest.PodmanNoCache([]string{"images"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session.LineInOutputContainsTag("docker.io/library/alpine", "latest") - session.LineInOutputContainsTag("docker.io/library/busybox", "glibc") - session.LineInOutputContainsTag("foo", "a") - session.LineInOutputContainsTag("foo", "b") - session.LineInOutputContainsTag("foo", "c") - session.LineInOutputContainsTag("bar", "a") - session.LineInOutputContainsTag("bar", "b") + Expect(session.LineInOutputContainsTag("quay.io/libpod/alpine", "latest")).To(BeTrue()) + Expect(session.LineInOutputContainsTag("quay.io/libpod/busybox", "latest")).To(BeTrue()) + Expect(session.LineInOutputContainsTag("localhost/foo", "a")).To(BeTrue()) + Expect(session.LineInOutputContainsTag("localhost/foo", "b")).To(BeTrue()) + Expect(session.LineInOutputContainsTag("localhost/foo", "c")).To(BeTrue()) + Expect(session.LineInOutputContainsTag("localhost/bar", "a")).To(BeTrue()) + Expect(session.LineInOutputContainsTag("localhost/bar", "b")).To(BeTrue()) session = podmanTest.PodmanNoCache([]string{"images", "-qn"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -98,8 +98,8 @@ var _ = Describe("Podman images", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 2)) - Expect(session.LineInOuputStartsWith("docker.io/library/alpine")).To(BeTrue()) - Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue()) + Expect(session.LineInOuputStartsWith("quay.io/libpod/alpine")).To(BeTrue()) + Expect(session.LineInOuputStartsWith("quay.io/libpod/busybox")).To(BeTrue()) }) It("podman empty images list in JSON format", func() { @@ -152,10 +152,10 @@ var _ = Describe("Podman images", func() { It("podman images filter reference", func() { podmanTest.RestoreAllArtifacts() - result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "reference=docker.io*"}) + result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "reference=quay.io*"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) - Expect(len(result.OutputToStringArray())).To(Equal(2)) + Expect(len(result.OutputToStringArray())).To(Equal(3)) retapline := podmanTest.PodmanNoCache([]string{"images", "-f", "reference=a*pine"}) retapline.WaitWithDefaultTimeout() @@ -176,7 +176,7 @@ var _ = Describe("Podman images", func() { }) It("podman images filter before image", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest RUN apk update && apk add strace ` podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") @@ -188,7 +188,7 @@ RUN apk update && apk add strace }) It("podman images workingdir from image", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest WORKDIR /test ` podmanTest.BuildImage(dockerfile, "foobar.com/workdir:latest", "false") @@ -204,10 +204,10 @@ WORKDIR /test rmi.WaitWithDefaultTimeout() Expect(rmi).Should(Exit(0)) - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest ` podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") - result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "after=docker.io/library/alpine:latest"}) + result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "after=quay.io/libpod/alpine:latest"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) Expect(len(result.OutputToStringArray())).To(Equal(0)) @@ -219,17 +219,17 @@ WORKDIR /test rmi.WaitWithDefaultTimeout() Expect(rmi).Should(Exit(0)) - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest ` podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") - result := podmanTest.PodmanNoCache([]string{"image", "list", "-q", "-f", "after=docker.io/library/alpine:latest"}) + result := podmanTest.PodmanNoCache([]string{"image", "list", "-q", "-f", "after=quay.io/libpod/alpine:latest"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) Expect(result.OutputToStringArray()).Should(HaveLen(0), "list filter output: %q", result.OutputToString()) }) It("podman images filter dangling", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest ` podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") @@ -240,6 +240,7 @@ WORKDIR /test }) It("podman pull by digest and list --all", func() { + Skip("FIXME-8165: 'rmi -af' fails with 'layer not known' (#6510)") // Prevent regressing on issue #7651. digestPullAndList := func(noneTag bool) { session := podmanTest.Podman([]string{"pull", ALPINEAMD64DIGEST}) @@ -341,7 +342,7 @@ WORKDIR /test It("podman images --all flag", func() { SkipIfRemote("FIXME This should work on podman-remote, problem is with podman-remote build") podmanTest.RestoreAllArtifacts() - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest RUN mkdir hello RUN touch test.txt ENV foo=bar @@ -359,7 +360,7 @@ ENV foo=bar }) It("podman images filter by label", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest LABEL version="1.0" LABEL "com.example.vendor"="Example Vendor" ` @@ -436,7 +437,7 @@ LABEL "com.example.vendor"="Example Vendor" }) It("podman images --filter readonly", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest ` podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") result := podmanTest.Podman([]string{"images", "-f", "readonly=true"}) diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index e8a82f9a1..9ede3384f 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -40,7 +40,7 @@ var _ = Describe("Podman inspect", func() { Expect(session.ExitCode()).To(Equal(0)) Expect(session.IsJSONOutputValid()).To(BeTrue()) imageData := session.InspectImageJSON() - Expect(imageData[0].RepoTags[0]).To(Equal("docker.io/library/alpine:latest")) + Expect(imageData[0].RepoTags[0]).To(Equal("quay.io/libpod/alpine:latest")) }) It("podman inspect bogus container", func() { diff --git a/test/e2e/load_test.go b/test/e2e/load_test.go index dd91381d9..e85a38c66 100644 --- a/test/e2e/load_test.go +++ b/test/e2e/load_test.go @@ -166,7 +166,7 @@ var _ = Describe("Podman load", func() { Skip("skip on ppc64le") } outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - alpVersion := "docker.io/library/alpine:3.2" + alpVersion := "quay.io/libpod/alpine:3.2" pull := podmanTest.PodmanNoCache([]string{"pull", alpVersion}) pull.WaitWithDefaultTimeout() diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go index b85132814..f984345f4 100644 --- a/test/e2e/manifest_test.go +++ b/test/e2e/manifest_test.go @@ -55,7 +55,7 @@ var _ = Describe("Podman manifest", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.PodmanNoCache([]string{"manifest", "inspect", "docker.io/library/busybox"}) + session = podmanTest.PodmanNoCache([]string{"manifest", "inspect", "quay.io/libpod/busybox"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) }) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 7ab8dc6f8..6dcfa9bd8 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -1092,7 +1092,7 @@ var _ = Describe("Podman play kube", func() { }) It("podman play kube with pull always", func() { - oldBB := "docker.io/library/busybox:1.30.1" + oldBB := "quay.io/libpod/busybox:1.30.1" pull := podmanTest.Podman([]string{"pull", oldBB}) pull.WaitWithDefaultTimeout() @@ -1123,7 +1123,7 @@ var _ = Describe("Podman play kube", func() { }) It("podman play kube with latest image should always pull", func() { - oldBB := "docker.io/library/busybox:1.30.1" + oldBB := "quay.io/libpod/busybox:1.30.1" pull := podmanTest.Podman([]string{"pull", oldBB}) pull.WaitWithDefaultTimeout() diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 95870788e..be0a2f6f0 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -382,7 +382,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman create pod with --infra-image", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest entrypoint ["/fromimage"] ` podmanTest.BuildImage(dockerfile, "localhost/infra", "false") @@ -409,7 +409,7 @@ entrypoint ["/fromimage"] }) It("podman create pod with --infra-command --infra-image", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest entrypoint ["/fromimage"] ` podmanTest.BuildImage(dockerfile, "localhost/infra", "false") diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index 11d0b8c9b..f3a66e58a 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -232,12 +232,19 @@ var _ = Describe("Podman ps", func() { }) It("podman ps ancestor filter flag", func() { - _, ec, _ := podmanTest.RunLsContainer("test1") + _, ec, cid := podmanTest.RunLsContainer("test1") Expect(ec).To(Equal(0)) - result := podmanTest.Podman([]string{"ps", "-a", "--filter", "ancestor=docker.io/library/alpine:latest"}) + result := podmanTest.Podman([]string{"ps", "-q", "--no-trunc", "-a", "--filter", "ancestor=quay.io/libpod/alpine:latest"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(Equal(cid)) + + // Query just by image name, without :latest tag + result = podmanTest.Podman([]string{"ps", "-q", "--no-trunc", "-a", "--filter", "ancestor=quay.io/libpod/alpine"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(Equal(cid)) }) It("podman ps id filter flag", func() { diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index 08ab50de1..5ccefe285 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -41,21 +41,21 @@ var _ = Describe("Podman pull", func() { }) It("podman pull from docker with tag", func() { - session := podmanTest.PodmanNoCache([]string{"pull", "busybox:glibc"}) + session := podmanTest.PodmanNoCache([]string{"pull", "quay.io/libpod/testdigest_v2s2:20200210"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.PodmanNoCache([]string{"rmi", "busybox:glibc"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "testdigest_v2s2:20200210"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull from docker without tag", func() { - session := podmanTest.PodmanNoCache([]string{"pull", "busybox"}) + session := podmanTest.PodmanNoCache([]string{"pull", "quay.io/libpod/testdigest_v2s2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.PodmanNoCache([]string{"rmi", "busybox"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "testdigest_v2s2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) @@ -81,11 +81,11 @@ var _ = Describe("Podman pull", func() { }) It("podman pull by digest", func() { - session := podmanTest.PodmanNoCache([]string{"pull", "alpine@sha256:1072e499f3f655a032e88542330cf75b02e7bdf673278f701d7ba61629ee3ebe"}) + session := podmanTest.PodmanNoCache([]string{"pull", "quay.io/libpod/testdigest_v2s2@sha256:755f4d90b3716e2bf57060d249e2cd61c9ac089b1233465c5c2cb2d7ee550fdb"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.PodmanNoCache([]string{"rmi", "alpine:none"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "testdigest_v2s2:none"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go index 7cb489113..cd62bf3b9 100644 --- a/test/e2e/rmi_test.go +++ b/test/e2e/rmi_test.go @@ -191,14 +191,14 @@ var _ = Describe("Podman rmi", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest RUN mkdir hello RUN touch test.txt ENV foo=bar ` podmanTest.BuildImage(dockerfile, "test", "true") - dockerfile = `FROM docker.io/library/alpine:latest + dockerfile = `FROM quay.io/libpod/alpine:latest RUN mkdir hello RUN touch test.txt RUN mkdir blah @@ -256,7 +256,7 @@ var _ = Describe("Podman rmi", func() { }) It("podman rmi -a with parent|child images", func() { - dockerfile := `FROM docker.io/library/alpine:latest AS base + dockerfile := `FROM quay.io/libpod/alpine:latest AS base RUN touch /1 ENV LOCAL=/1 RUN find $LOCAL diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go index db802946e..2185d6b13 100644 --- a/test/e2e/run_entrypoint_test.go +++ b/test/e2e/run_entrypoint_test.go @@ -33,7 +33,7 @@ var _ = Describe("Podman run entrypoint", func() { }) It("podman run no command, entrypoint, or cmd", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest ENTRYPOINT [] CMD [] ` @@ -44,7 +44,7 @@ CMD [] }) It("podman run entrypoint", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false") @@ -55,7 +55,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with cmd", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest CMD [ "-v"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` @@ -67,7 +67,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with user cmd overrides image cmd", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest CMD [ "-v"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` @@ -79,7 +79,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with user cmd no image cmd", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false") @@ -91,7 +91,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] It("podman run user entrypoint overrides image entrypoint and image cmd", func() { SkipIfRemote("FIXME: podman-remote not handling passing --entrypoint=\"\" flag correctly") - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest CMD ["-i"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` @@ -108,7 +108,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run user entrypoint with command overrides image entrypoint and image cmd", func() { - dockerfile := `FROM docker.io/library/alpine:latest + dockerfile := `FROM quay.io/libpod/alpine:latest CMD ["-i"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go index 79fc4d737..bdaef9259 100644 --- a/test/e2e/save_test.go +++ b/test/e2e/save_test.go @@ -134,7 +134,7 @@ var _ = Describe("Podman save", func() { defer os.Setenv("GNUPGHOME", origGNUPGHOME) port := 5000 - session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"), "docker.io/registry:2.6"}) + session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"), "quay.io/libpod/registry:2.6"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) { diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index 218c250cd..48294943b 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -59,7 +59,7 @@ WantedBy=multi-user.target Expect(stop.ExitCode()).To(Equal(0)) }() - create := podmanTest.Podman([]string{"create", "--name", "redis", "redis"}) + create := podmanTest.Podman([]string{"create", "--name", "redis", redis}) create.WaitWithDefaultTimeout() Expect(create.ExitCode()).To(Equal(0)) diff --git a/test/e2e/tag_test.go b/test/e2e/tag_test.go index 72d5cad77..3b43b0e20 100644 --- a/test/e2e/tag_test.go +++ b/test/e2e/tag_test.go @@ -41,7 +41,7 @@ var _ = Describe("Podman tag", func() { results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(Equal(0)) inspectData := results.InspectImageJSON() - Expect(StringInSlice("docker.io/library/alpine:latest", inspectData[0].RepoTags)).To(BeTrue()) + Expect(StringInSlice("quay.io/libpod/alpine:latest", inspectData[0].RepoTags)).To(BeTrue()) Expect(StringInSlice("localhost/foobar:latest", inspectData[0].RepoTags)).To(BeTrue()) }) @@ -54,7 +54,7 @@ var _ = Describe("Podman tag", func() { results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(Equal(0)) inspectData := results.InspectImageJSON() - Expect(StringInSlice("docker.io/library/alpine:latest", inspectData[0].RepoTags)).To(BeTrue()) + Expect(StringInSlice("quay.io/libpod/alpine:latest", inspectData[0].RepoTags)).To(BeTrue()) Expect(StringInSlice("localhost/foobar:latest", inspectData[0].RepoTags)).To(BeTrue()) }) @@ -67,7 +67,7 @@ var _ = Describe("Podman tag", func() { results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(Equal(0)) inspectData := results.InspectImageJSON() - Expect(StringInSlice("docker.io/library/alpine:latest", inspectData[0].RepoTags)).To(BeTrue()) + Expect(StringInSlice("quay.io/libpod/alpine:latest", inspectData[0].RepoTags)).To(BeTrue()) Expect(StringInSlice("localhost/foobar:new", inspectData[0].RepoTags)).To(BeTrue()) }) diff --git a/test/e2e/tree_test.go b/test/e2e/tree_test.go index eeb00440c..22d53a8ea 100644 --- a/test/e2e/tree_test.go +++ b/test/e2e/tree_test.go @@ -35,7 +35,7 @@ var _ = Describe("Podman image tree", func() { It("podman image tree", func() { SkipIfRemote("Does not work on remote client") - dockerfile := `FROM docker.io/library/busybox:latest + dockerfile := `FROM quay.io/libpod/busybox:latest RUN mkdir hello RUN touch test.txt ENV foo=bar @@ -45,14 +45,14 @@ ENV foo=bar session := podmanTest.PodmanNoCache([]string{"image", "tree", "test:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.PodmanNoCache([]string{"image", "tree", "--whatrequires", "docker.io/library/busybox:latest"}) + session = podmanTest.PodmanNoCache([]string{"image", "tree", "--whatrequires", "quay.io/libpod/busybox:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) session = podmanTest.PodmanNoCache([]string{"rmi", "test:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.PodmanNoCache([]string{"rmi", "docker.io/library/busybox:latest"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "quay.io/libpod/busybox:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) diff --git a/test/registries.conf b/test/registries.conf index f27a282d6..0559c9e52 100644 --- a/test/registries.conf +++ b/test/registries.conf @@ -1,10 +1,17 @@ # Note that changing the order here may break tests. -[registries.search] -registries = ['docker.io', 'quay.io', 'registry.fedoraproject.org'] +unqualified-search-registries = ['docker.io', 'quay.io', 'registry.fedoraproject.org'] -[registries.insecure] -registries = [] +[[registry]] +# In Nov. 2020, Docker rate-limits image pulling. To avoid hitting these +# limits while testing, always use the google mirror for qualified and +# unqualified `docker.io` images. +# Ref: https://cloud.google.com/container-registry/docs/pulling-cached-images +prefix="docker.io" +location="mirror.gcr.io" -#blocked (docker only) -[registries.block] -registries = [] +# 2020-10-27 a number of images are not present in gcr.io, and podman +# barfs spectacularly when trying to fetch them. We've hand-copied +# those to quay, using skopeo copy --all ... +[[registry]] +prefix="docker.io/library" +location="quay.io/libpod" diff --git a/test/utils/utils.go b/test/utils/utils.go index a45ce7b36..cb76d4a54 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -302,12 +302,7 @@ func (s *PodmanSession) LineInOutputContains(term string) bool { // by podman-images(1). func (s *PodmanSession) LineInOutputContainsTag(repo, tag string) bool { tagMap := tagOutputToMap(s.OutputToStringArray()) - for r, t := range tagMap { - if repo == r && tag == t { - return true - } - } - return false + return tagMap[repo][tag] } // IsJSONOutputValid attempts to unmarshal the session buffer @@ -366,10 +361,11 @@ func StringInSlice(s string, sl []string) bool { } // tagOutPutToMap parses each string in imagesOutput and returns -// a map of repo:tag pairs. Notice, the first array item will +// a map whose key is a repo, and value is another map whose keys +// are the tags found for that repo. Notice, the first array item will // be skipped as it's considered to be the header. -func tagOutputToMap(imagesOutput []string) map[string]string { - m := make(map[string]string) +func tagOutputToMap(imagesOutput []string) map[string]map[string]bool { + m := make(map[string]map[string]bool) // iterate over output but skip the header for _, i := range imagesOutput[1:] { tmp := []string{} @@ -383,7 +379,10 @@ func tagOutputToMap(imagesOutput []string) map[string]string { if len(tmp) < 2 { continue } - m[tmp[0]] = tmp[1] + if m[tmp[0]] == nil { + m[tmp[0]] = map[string]bool{} + } + m[tmp[0]][tmp[1]] = true } return m } diff --git a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go new file mode 100644 index 000000000..260cfe58c --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go @@ -0,0 +1,540 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package knownhosts implements a parser for the OpenSSH known_hosts +// host key database, and provides utility functions for writing +// OpenSSH compliant known_hosts files. +package knownhosts + +import ( + "bufio" + "bytes" + "crypto/hmac" + "crypto/rand" + "crypto/sha1" + "encoding/base64" + "errors" + "fmt" + "io" + "net" + "os" + "strings" + + "golang.org/x/crypto/ssh" +) + +// See the sshd manpage +// (http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT) for +// background. + +type addr struct{ host, port string } + +func (a *addr) String() string { + h := a.host + if strings.Contains(h, ":") { + h = "[" + h + "]" + } + return h + ":" + a.port +} + +type matcher interface { + match(addr) bool +} + +type hostPattern struct { + negate bool + addr addr +} + +func (p *hostPattern) String() string { + n := "" + if p.negate { + n = "!" + } + + return n + p.addr.String() +} + +type hostPatterns []hostPattern + +func (ps hostPatterns) match(a addr) bool { + matched := false + for _, p := range ps { + if !p.match(a) { + continue + } + if p.negate { + return false + } + matched = true + } + return matched +} + +// See +// https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/addrmatch.c +// The matching of * has no regard for separators, unlike filesystem globs +func wildcardMatch(pat []byte, str []byte) bool { + for { + if len(pat) == 0 { + return len(str) == 0 + } + if len(str) == 0 { + return false + } + + if pat[0] == '*' { + if len(pat) == 1 { + return true + } + + for j := range str { + if wildcardMatch(pat[1:], str[j:]) { + return true + } + } + return false + } + + if pat[0] == '?' || pat[0] == str[0] { + pat = pat[1:] + str = str[1:] + } else { + return false + } + } +} + +func (p *hostPattern) match(a addr) bool { + return wildcardMatch([]byte(p.addr.host), []byte(a.host)) && p.addr.port == a.port +} + +type keyDBLine struct { + cert bool + matcher matcher + knownKey KnownKey +} + +func serialize(k ssh.PublicKey) string { + return k.Type() + " " + base64.StdEncoding.EncodeToString(k.Marshal()) +} + +func (l *keyDBLine) match(a addr) bool { + return l.matcher.match(a) +} + +type hostKeyDB struct { + // Serialized version of revoked keys + revoked map[string]*KnownKey + lines []keyDBLine +} + +func newHostKeyDB() *hostKeyDB { + db := &hostKeyDB{ + revoked: make(map[string]*KnownKey), + } + + return db +} + +func keyEq(a, b ssh.PublicKey) bool { + return bytes.Equal(a.Marshal(), b.Marshal()) +} + +// IsAuthorityForHost can be used as a callback in ssh.CertChecker +func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool { + h, p, err := net.SplitHostPort(address) + if err != nil { + return false + } + a := addr{host: h, port: p} + + for _, l := range db.lines { + if l.cert && keyEq(l.knownKey.Key, remote) && l.match(a) { + return true + } + } + return false +} + +// IsRevoked can be used as a callback in ssh.CertChecker +func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool { + _, ok := db.revoked[string(key.Marshal())] + return ok +} + +const markerCert = "@cert-authority" +const markerRevoked = "@revoked" + +func nextWord(line []byte) (string, []byte) { + i := bytes.IndexAny(line, "\t ") + if i == -1 { + return string(line), nil + } + + return string(line[:i]), bytes.TrimSpace(line[i:]) +} + +func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err error) { + if w, next := nextWord(line); w == markerCert || w == markerRevoked { + marker = w + line = next + } + + host, line = nextWord(line) + if len(line) == 0 { + return "", "", nil, errors.New("knownhosts: missing host pattern") + } + + // ignore the keytype as it's in the key blob anyway. + _, line = nextWord(line) + if len(line) == 0 { + return "", "", nil, errors.New("knownhosts: missing key type pattern") + } + + keyBlob, _ := nextWord(line) + + keyBytes, err := base64.StdEncoding.DecodeString(keyBlob) + if err != nil { + return "", "", nil, err + } + key, err = ssh.ParsePublicKey(keyBytes) + if err != nil { + return "", "", nil, err + } + + return marker, host, key, nil +} + +func (db *hostKeyDB) parseLine(line []byte, filename string, linenum int) error { + marker, pattern, key, err := parseLine(line) + if err != nil { + return err + } + + if marker == markerRevoked { + db.revoked[string(key.Marshal())] = &KnownKey{ + Key: key, + Filename: filename, + Line: linenum, + } + + return nil + } + + entry := keyDBLine{ + cert: marker == markerCert, + knownKey: KnownKey{ + Filename: filename, + Line: linenum, + Key: key, + }, + } + + if pattern[0] == '|' { + entry.matcher, err = newHashedHost(pattern) + } else { + entry.matcher, err = newHostnameMatcher(pattern) + } + + if err != nil { + return err + } + + db.lines = append(db.lines, entry) + return nil +} + +func newHostnameMatcher(pattern string) (matcher, error) { + var hps hostPatterns + for _, p := range strings.Split(pattern, ",") { + if len(p) == 0 { + continue + } + + var a addr + var negate bool + if p[0] == '!' { + negate = true + p = p[1:] + } + + if len(p) == 0 { + return nil, errors.New("knownhosts: negation without following hostname") + } + + var err error + if p[0] == '[' { + a.host, a.port, err = net.SplitHostPort(p) + if err != nil { + return nil, err + } + } else { + a.host, a.port, err = net.SplitHostPort(p) + if err != nil { + a.host = p + a.port = "22" + } + } + hps = append(hps, hostPattern{ + negate: negate, + addr: a, + }) + } + return hps, nil +} + +// KnownKey represents a key declared in a known_hosts file. +type KnownKey struct { + Key ssh.PublicKey + Filename string + Line int +} + +func (k *KnownKey) String() string { + return fmt.Sprintf("%s:%d: %s", k.Filename, k.Line, serialize(k.Key)) +} + +// KeyError is returned if we did not find the key in the host key +// database, or there was a mismatch. Typically, in batch +// applications, this should be interpreted as failure. Interactive +// applications can offer an interactive prompt to the user. +type KeyError struct { + // Want holds the accepted host keys. For each key algorithm, + // there can be one hostkey. If Want is empty, the host is + // unknown. If Want is non-empty, there was a mismatch, which + // can signify a MITM attack. + Want []KnownKey +} + +func (u *KeyError) Error() string { + if len(u.Want) == 0 { + return "knownhosts: key is unknown" + } + return "knownhosts: key mismatch" +} + +// RevokedError is returned if we found a key that was revoked. +type RevokedError struct { + Revoked KnownKey +} + +func (r *RevokedError) Error() string { + return "knownhosts: key is revoked" +} + +// check checks a key against the host database. This should not be +// used for verifying certificates. +func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.PublicKey) error { + if revoked := db.revoked[string(remoteKey.Marshal())]; revoked != nil { + return &RevokedError{Revoked: *revoked} + } + + host, port, err := net.SplitHostPort(remote.String()) + if err != nil { + return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", remote, err) + } + + hostToCheck := addr{host, port} + if address != "" { + // Give preference to the hostname if available. + host, port, err := net.SplitHostPort(address) + if err != nil { + return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", address, err) + } + + hostToCheck = addr{host, port} + } + + return db.checkAddr(hostToCheck, remoteKey) +} + +// checkAddr checks if we can find the given public key for the +// given address. If we only find an entry for the IP address, +// or only the hostname, then this still succeeds. +func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { + // TODO(hanwen): are these the right semantics? What if there + // is just a key for the IP address, but not for the + // hostname? + + // Algorithm => key. + knownKeys := map[string]KnownKey{} + for _, l := range db.lines { + if l.match(a) { + typ := l.knownKey.Key.Type() + if _, ok := knownKeys[typ]; !ok { + knownKeys[typ] = l.knownKey + } + } + } + + keyErr := &KeyError{} + for _, v := range knownKeys { + keyErr.Want = append(keyErr.Want, v) + } + + // Unknown remote host. + if len(knownKeys) == 0 { + return keyErr + } + + // If the remote host starts using a different, unknown key type, we + // also interpret that as a mismatch. + if known, ok := knownKeys[remoteKey.Type()]; !ok || !keyEq(known.Key, remoteKey) { + return keyErr + } + + return nil +} + +// The Read function parses file contents. +func (db *hostKeyDB) Read(r io.Reader, filename string) error { + scanner := bufio.NewScanner(r) + + lineNum := 0 + for scanner.Scan() { + lineNum++ + line := scanner.Bytes() + line = bytes.TrimSpace(line) + if len(line) == 0 || line[0] == '#' { + continue + } + + if err := db.parseLine(line, filename, lineNum); err != nil { + return fmt.Errorf("knownhosts: %s:%d: %v", filename, lineNum, err) + } + } + return scanner.Err() +} + +// New creates a host key callback from the given OpenSSH host key +// files. The returned callback is for use in +// ssh.ClientConfig.HostKeyCallback. By preference, the key check +// operates on the hostname if available, i.e. if a server changes its +// IP address, the host key check will still succeed, even though a +// record of the new IP address is not available. +func New(files ...string) (ssh.HostKeyCallback, error) { + db := newHostKeyDB() + for _, fn := range files { + f, err := os.Open(fn) + if err != nil { + return nil, err + } + defer f.Close() + if err := db.Read(f, fn); err != nil { + return nil, err + } + } + + var certChecker ssh.CertChecker + certChecker.IsHostAuthority = db.IsHostAuthority + certChecker.IsRevoked = db.IsRevoked + certChecker.HostKeyFallback = db.check + + return certChecker.CheckHostKey, nil +} + +// Normalize normalizes an address into the form used in known_hosts +func Normalize(address string) string { + host, port, err := net.SplitHostPort(address) + if err != nil { + host = address + port = "22" + } + entry := host + if port != "22" { + entry = "[" + entry + "]:" + port + } else if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { + entry = "[" + entry + "]" + } + return entry +} + +// Line returns a line to add append to the known_hosts files. +func Line(addresses []string, key ssh.PublicKey) string { + var trimmed []string + for _, a := range addresses { + trimmed = append(trimmed, Normalize(a)) + } + + return strings.Join(trimmed, ",") + " " + serialize(key) +} + +// HashHostname hashes the given hostname. The hostname is not +// normalized before hashing. +func HashHostname(hostname string) string { + // TODO(hanwen): check if we can safely normalize this always. + salt := make([]byte, sha1.Size) + + _, err := rand.Read(salt) + if err != nil { + panic(fmt.Sprintf("crypto/rand failure %v", err)) + } + + hash := hashHost(hostname, salt) + return encodeHash(sha1HashType, salt, hash) +} + +func decodeHash(encoded string) (hashType string, salt, hash []byte, err error) { + if len(encoded) == 0 || encoded[0] != '|' { + err = errors.New("knownhosts: hashed host must start with '|'") + return + } + components := strings.Split(encoded, "|") + if len(components) != 4 { + err = fmt.Errorf("knownhosts: got %d components, want 3", len(components)) + return + } + + hashType = components[1] + if salt, err = base64.StdEncoding.DecodeString(components[2]); err != nil { + return + } + if hash, err = base64.StdEncoding.DecodeString(components[3]); err != nil { + return + } + return +} + +func encodeHash(typ string, salt []byte, hash []byte) string { + return strings.Join([]string{"", + typ, + base64.StdEncoding.EncodeToString(salt), + base64.StdEncoding.EncodeToString(hash), + }, "|") +} + +// See https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 +func hashHost(hostname string, salt []byte) []byte { + mac := hmac.New(sha1.New, salt) + mac.Write([]byte(hostname)) + return mac.Sum(nil) +} + +type hashedHost struct { + salt []byte + hash []byte +} + +const sha1HashType = "1" + +func newHashedHost(encoded string) (*hashedHost, error) { + typ, salt, hash, err := decodeHash(encoded) + if err != nil { + return nil, err + } + + // The type field seems for future algorithm agility, but it's + // actually hardcoded in openssh currently, see + // https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 + if typ != sha1HashType { + return nil, fmt.Errorf("knownhosts: got hash type %s, must be '1'", typ) + } + + return &hashedHost{salt: salt, hash: hash}, nil +} + +func (h *hashedHost) match(a addr) bool { + return bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4e81d5f02..4ed3bbcda 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -591,6 +591,7 @@ golang.org/x/crypto/poly1305 golang.org/x/crypto/ssh golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf +golang.org/x/crypto/ssh/knownhosts golang.org/x/crypto/ssh/terminal # golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 golang.org/x/net/context |