summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/image/pull.go164
-rw-r--r--libpod/image/pull_test.go152
2 files changed, 169 insertions, 147 deletions
diff --git a/libpod/image/pull.go b/libpod/image/pull.go
index f3a10d94d..ff978d563 100644
--- a/libpod/image/pull.go
+++ b/libpod/image/pull.go
@@ -63,31 +63,17 @@ type pullGoal struct {
searchedRegistries []string // The list of search registries used; set only if usedSearchRegistries
}
-// pullRefName records a prepared source reference and a destination name to pull.
-type pullRefName struct {
- image string
- srcRef types.ImageReference
- dstName string
-}
-
-// pullGoalNames is an intermediate variant of pullGoal which uses pullRefName instead of pullRefPair.
-type pullGoalNames struct {
- refNames []pullRefName
- pullAllPairs bool // Pull all refNames instead of stopping on first success.
- usedSearchRegistries bool // refPairs construction has depended on registries.GetRegistries()
- searchedRegistries []string // The list of search registries used; set only if usedSearchRegistries
-}
-
-func singlePullRefNameGoal(rn pullRefName) *pullGoalNames {
- return &pullGoalNames{
- refNames: []pullRefName{rn},
+// singlePullRefPairGoal returns a no-frills pull goal for the specified reference pair.
+func singlePullRefPairGoal(rp pullRefPair) *pullGoal {
+ return &pullGoal{
+ refPairs: []pullRefPair{rp},
pullAllPairs: false, // Does not really make a difference.
usedSearchRegistries: false,
searchedRegistries: nil,
}
}
-func getPullRefName(srcRef types.ImageReference, destName string) pullRefName {
+func (ir *Runtime) getPullRefPair(srcRef types.ImageReference, destName string) (pullRefPair, error) {
imgPart, err := decompose(destName)
if err == nil && !imgPart.hasRegistry {
// If the image doesn't have a registry, set it as the default repo
@@ -100,15 +86,28 @@ func getPullRefName(srcRef types.ImageReference, destName string) pullRefName {
if srcRef.DockerReference() != nil {
reference = srcRef.DockerReference().String()
}
- return pullRefName{
- image: destName,
- srcRef: srcRef,
- dstName: reference,
+ destRef, err := is.Transport.ParseStoreReference(ir.store, reference)
+ if err != nil {
+ return pullRefPair{}, errors.Wrapf(err, "error parsing dest reference name %#v", destName)
+ }
+ return pullRefPair{
+ image: destName,
+ srcRef: srcRef,
+ dstRef: destRef,
+ }, nil
+}
+
+// getSinglePullRefPairGoal calls getPullRefPair with the specified parameters, and returns a single-pair goal for the return value.
+func (ir *Runtime) getSinglePullRefPairGoal(srcRef types.ImageReference, destName string) (*pullGoal, error) {
+ rp, err := ir.getPullRefPair(srcRef, destName)
+ if err != nil {
+ return nil, err
}
+ return singlePullRefPairGoal(rp), nil
}
-// pullGoalNamesFromImageReference returns a pullGoalNames for a single ImageReference, depending on the used transport.
-func pullGoalNamesFromImageReference(ctx context.Context, srcRef types.ImageReference, imgName string, sc *types.SystemContext) (*pullGoalNames, error) {
+// pullGoalFromImageReference returns a pull goal for a single ImageReference, depending on the used transport.
+func (ir *Runtime) pullGoalFromImageReference(ctx context.Context, srcRef types.ImageReference, imgName string, sc *types.SystemContext) (*pullGoal, error) {
// supports pulling from docker-archive, oci, and registries
switch srcRef.Transport().Name() {
case DockerArchive:
@@ -129,7 +128,7 @@ func pullGoalNamesFromImageReference(ctx context.Context, srcRef types.ImageRefe
if err != nil {
return nil, err
}
- return singlePullRefNameGoal(getPullRefName(srcRef, reference)), nil
+ return ir.getSinglePullRefPairGoal(srcRef, reference)
}
if len(manifest[0].RepoTags) == 0 {
@@ -138,17 +137,20 @@ func pullGoalNamesFromImageReference(ctx context.Context, srcRef types.ImageRefe
if err != nil {
return nil, err
}
- return singlePullRefNameGoal(getPullRefName(srcRef, digest)), nil
+ return ir.getSinglePullRefPairGoal(srcRef, digest)
}
// Need to load in all the repo tags from the manifest
- res := []pullRefName{}
+ res := []pullRefPair{}
for _, dst := range manifest[0].RepoTags {
- pullInfo := getPullRefName(srcRef, dst)
+ pullInfo, err := ir.getPullRefPair(srcRef, dst)
+ if err != nil {
+ return nil, err
+ }
res = append(res, pullInfo)
}
- return &pullGoalNames{
- refNames: res,
+ return &pullGoal{
+ refPairs: res,
pullAllPairs: true,
usedSearchRegistries: false,
searchedRegistries: nil,
@@ -172,7 +174,7 @@ func pullGoalNamesFromImageReference(ctx context.Context, srcRef types.ImageRefe
} else {
dest = manifest.Annotations["org.opencontainers.image.ref.name"]
}
- return singlePullRefNameGoal(getPullRefName(srcRef, dest)), nil
+ return ir.getSinglePullRefPairGoal(srcRef, dest)
case DirTransport:
path := srcRef.StringWithinTransport()
@@ -183,27 +185,17 @@ func pullGoalNamesFromImageReference(ctx context.Context, srcRef types.ImageRefe
// so docker.io isn't prepended, and the path becomes the repository
image = DefaultLocalRepo + image
}
- return singlePullRefNameGoal(getPullRefName(srcRef, image)), nil
+ return ir.getSinglePullRefPairGoal(srcRef, image)
default:
- return singlePullRefNameGoal(getPullRefName(srcRef, imgName)), nil
+ return ir.getSinglePullRefPairGoal(srcRef, imgName)
}
}
-// pullGoalFromImageReference returns a pull goal for a single ImageReference, depending on the used transport.
-func (ir *Runtime) pullGoalFromImageReference(ctx context.Context, srcRef types.ImageReference, imgName string, sc *types.SystemContext) (pullGoal, error) {
- goalNames, err := pullGoalNamesFromImageReference(ctx, srcRef, imgName, sc)
- if err != nil {
- return pullGoal{}, err
- }
-
- return ir.pullGoalFromGoalNames(goalNames)
-}
-
// pullImageFromHeuristicSource pulls an image based on inputName, which is heuristically parsed and may involve configured registries.
// Use pullImageFromReference if the source is known precisely.
func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, forceSecure bool) ([]string, error) {
- var goal pullGoal
+ var goal *pullGoal
sc := GetSystemContext(signaturePolicyPath, authfile, false)
srcRef, err := alltransports.ParseImageName(inputName)
if err != nil {
@@ -218,7 +210,7 @@ func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName s
return nil, errors.Wrapf(err, "error determining pull goal for image %q", inputName)
}
}
- return ir.doPullImage(ctx, sc, goal, writer, signingOptions, dockerOptions, forceSecure)
+ return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, forceSecure)
}
// pullImageFromReference pulls an image from a types.imageReference.
@@ -228,7 +220,7 @@ func (ir *Runtime) pullImageFromReference(ctx context.Context, srcRef types.Imag
if err != nil {
return nil, errors.Wrapf(err, "error determining pull goal for image %q", transports.ImageName(srcRef))
}
- return ir.doPullImage(ctx, sc, goal, writer, signingOptions, dockerOptions, forceSecure)
+ return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, forceSecure)
}
// doPullImage is an internal helper interpreting pullGoal. Almost everyone should call one of the callers of doPullImage instead.
@@ -291,15 +283,15 @@ func hasShaInInputName(inputName string) bool {
return strings.Contains(inputName, "@sha256:")
}
-// pullGoalNamesFromPossiblyUnqualifiedName looks at a decomposed image and determines the possible
-// image names to try pulling in combination with the registries.conf file as well
-func pullGoalNamesFromPossiblyUnqualifiedName(inputName string) (*pullGoalNames, error) {
+// pullGoalFromPossiblyUnqualifiedName looks at inputName and determines the possible
+// image references to try pulling in combination with the registries.conf file as well
+func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(inputName string) (*pullGoal, error) {
decomposedImage, err := decompose(inputName)
if err != nil {
return nil, err
}
if decomposedImage.hasRegistry {
- var imageName string
+ var imageName, destName string
if hasShaInInputName(inputName) {
imageName = fmt.Sprintf("%s%s", decomposedImage.transport, inputName)
} else {
@@ -309,23 +301,28 @@ func pullGoalNamesFromPossiblyUnqualifiedName(inputName string) (*pullGoalNames,
if err != nil {
return nil, errors.Wrapf(err, "unable to parse '%s'", inputName)
}
- ps := pullRefName{
- image: inputName,
- srcRef: srcRef,
- }
if hasShaInInputName(inputName) {
- ps.dstName = decomposedImage.assemble()
+ destName = decomposedImage.assemble()
} else {
- ps.dstName = ps.image
+ destName = inputName
+ }
+ destRef, err := is.Transport.ParseStoreReference(ir.store, destName)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error parsing dest reference name %#v", destName)
}
- return singlePullRefNameGoal(ps), nil
+ ps := pullRefPair{
+ image: inputName,
+ srcRef: srcRef,
+ dstRef: destRef,
+ }
+ return singlePullRefPairGoal(ps), nil
}
searchRegistries, err := registries.GetRegistries()
if err != nil {
return nil, err
}
- var pullNames []pullRefName
+ var refPairs []pullRefPair
for _, registry := range searchRegistries {
decomposedImage.registry = registry
imageName := decomposedImage.assembleWithTransport()
@@ -336,53 +333,20 @@ func pullGoalNamesFromPossiblyUnqualifiedName(inputName string) (*pullGoalNames,
if err != nil {
return nil, errors.Wrapf(err, "unable to parse '%s'", inputName)
}
- ps := pullRefName{
+ ps := pullRefPair{
image: decomposedImage.assemble(),
srcRef: srcRef,
}
- ps.dstName = ps.image
- pullNames = append(pullNames, ps)
+ ps.dstRef, err = is.Transport.ParseStoreReference(ir.store, ps.image)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error parsing dest reference name %#v", ps.image)
+ }
+ refPairs = append(refPairs, ps)
}
- return &pullGoalNames{
- refNames: pullNames,
+ return &pullGoal{
+ refPairs: refPairs,
pullAllPairs: false,
usedSearchRegistries: true,
searchedRegistries: searchRegistries,
}, nil
}
-
-// pullGoalFromPossiblyUnqualifiedName looks at inputName and determines the possible
-// image references to try pulling in combination with the registries.conf file as well
-func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(inputName string) (pullGoal, error) {
- goalNames, err := pullGoalNamesFromPossiblyUnqualifiedName(inputName)
- if err != nil {
- return pullGoal{}, err
- }
- return ir.pullGoalFromGoalNames(goalNames)
-}
-
-// pullGoalFromGoalNames converts a pullGoalNames to a pullGoal
-func (ir *Runtime) pullGoalFromGoalNames(goalNames *pullGoalNames) (pullGoal, error) {
- if goalNames == nil { // The value is a pointer only to make (return nil, err) possible in callers; they should never return nil on success
- return pullGoal{}, errors.New("internal error: pullGoalFromGoalNames(nil)")
- }
- // Here we construct the destination references
- res := make([]pullRefPair, len(goalNames.refNames))
- for i, rn := range goalNames.refNames {
- destRef, err := is.Transport.ParseStoreReference(ir.store, rn.dstName)
- if err != nil {
- return pullGoal{}, errors.Wrapf(err, "error parsing dest reference name %#v", rn.dstName)
- }
- res[i] = pullRefPair{
- image: rn.image,
- srcRef: rn.srcRef,
- dstRef: destRef,
- }
- }
- return pullGoal{
- refPairs: res,
- pullAllPairs: goalNames.pullAllPairs,
- usedSearchRegistries: goalNames.usedSearchRegistries,
- searchedRegistries: goalNames.searchedRegistries,
- }, nil
-}
diff --git a/libpod/image/pull_test.go b/libpod/image/pull_test.go
index 13ba759c8..5ef8c47a5 100644
--- a/libpod/image/pull_test.go
+++ b/libpod/image/pull_test.go
@@ -5,24 +5,74 @@ import (
"fmt"
"io/ioutil"
"os"
+ "path/filepath"
+ "strings"
"testing"
"github.com/containers/image/transports"
"github.com/containers/image/transports/alltransports"
+ "github.com/containers/image/types"
+ "github.com/containers/storage"
+ "github.com/containers/storage/pkg/idtools"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func TestGetPullRefName(t *testing.T) {
+// newTestRuntime returns a *Runtime implementation and a cleanup function which the caller is expected to call.
+func newTestRuntime(t *testing.T) (*Runtime, func()) {
+ wd, err := ioutil.TempDir("", "testStorageRuntime")
+ require.NoError(t, err)
+ err = os.MkdirAll(wd, 0700)
+ require.NoError(t, err)
+
+ store, err := storage.GetStore(storage.StoreOptions{
+ RunRoot: filepath.Join(wd, "run"),
+ GraphRoot: filepath.Join(wd, "root"),
+ GraphDriverName: "vfs",
+ GraphDriverOptions: []string{},
+ UIDMap: []idtools.IDMap{{
+ ContainerID: 0,
+ HostID: os.Getuid(),
+ Size: 1,
+ }},
+ GIDMap: []idtools.IDMap{{
+ ContainerID: 0,
+ HostID: os.Getgid(),
+ Size: 1,
+ }},
+ })
+ require.NoError(t, err)
+
+ ir := NewImageRuntimeFromStore(store)
+ cleanup := func() { _ = os.RemoveAll(wd) }
+ return ir, cleanup
+}
+
+// storageReferenceWithoutLocation returns ref.StringWithinTransport(),
+// stripping the [store-specification] prefix from containers/image/storage reference format.
+func storageReferenceWithoutLocation(ref types.ImageReference) string {
+ res := ref.StringWithinTransport()
+ if res[0] == '[' {
+ closeIndex := strings.IndexRune(res, ']')
+ if closeIndex > 0 {
+ res = res[closeIndex+1:]
+ }
+ }
+ return res
+}
+
+func TestGetPullRefPair(t *testing.T) {
const imageID = "@0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
const digestSuffix = "@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+ ir, cleanup := newTestRuntime(t)
+ defer cleanup()
+
for _, c := range []struct{ srcName, destName, expectedImage, expectedDstName string }{
// == Source does not have a Docker reference (as is the case for docker-archive:, oci-archive, dir:); destination formats:
{ // registry/name, no tag:
"dir:/dev/this-does-not-exist", "example.com/from-directory",
- // The destName value will be interpreted as "example.com/from-directory:latest" by storageTransport.
- "example.com/from-directory", "example.com/from-directory",
+ "example.com/from-directory", "example.com/from-directory:latest",
},
{ // name, no registry, no tag:
"dir:/dev/this-does-not-exist", "from-directory",
@@ -50,7 +100,7 @@ func TestGetPullRefName(t *testing.T) {
{ // ns/name:tag, no registry:
// FIXME: This is interpreted as "registry == ns"
"dir:/dev/this-does-not-exist", "ns/from-directory:notlatest",
- "ns/from-directory:notlatest", "ns/from-directory:notlatest",
+ "ns/from-directory:notlatest", "docker.io/ns/from-directory:notlatest",
},
{ // containers-storage image ID
"dir:/dev/this-does-not-exist", imageID,
@@ -68,17 +118,29 @@ func TestGetPullRefName(t *testing.T) {
"docker://busybox", "docker://busybox:destination",
"docker://busybox:destination", "docker.io/library/busybox:latest",
},
+ // == Invalid destination format.
+ {"tarball:/dev/null", "tarball:/dev/null", "", ""},
} {
+ testDescription := fmt.Sprintf("%#v %#v", c.srcName, c.destName)
srcRef, err := alltransports.ParseImageName(c.srcName)
- require.NoError(t, err, c.srcName)
+ require.NoError(t, err, testDescription)
- res := getPullRefName(srcRef, c.destName)
- assert.Equal(t, pullRefName{image: c.expectedImage, srcRef: srcRef, dstName: c.expectedDstName}, res,
- fmt.Sprintf("%#v %#v", c.srcName, c.destName))
+ res, err := ir.getPullRefPair(srcRef, c.destName)
+ if c.expectedDstName == "" {
+ assert.Error(t, err, testDescription)
+ } else {
+ require.NoError(t, err, testDescription)
+ assert.Equal(t, c.expectedImage, res.image, testDescription)
+ assert.Equal(t, srcRef, res.srcRef, testDescription)
+ assert.Equal(t, c.expectedDstName, storageReferenceWithoutLocation(res.dstRef), testDescription)
+ }
}
}
-func TestPullGoalNamesFromImageReference(t *testing.T) {
+func TestPullGoalFromImageReference(t *testing.T) {
+ ir, cleanup := newTestRuntime(t)
+ defer cleanup()
+
type expected struct{ image, dstName string }
for _, c := range []struct {
srcName string
@@ -139,29 +201,26 @@ func TestPullGoalNamesFromImageReference(t *testing.T) {
// []expected{{"example.com/empty:latest", "example.com/empty:latest"}},
// false,
// },
- // { // Name exists, but is an invalid Docker reference; such names are passed through, and will fail when intepreting dstName.
- // "oci-archive:testdata/oci-non-docker-name.tar.gz",
- // []expected{{"UPPERCASE-IS-INVALID", "UPPERCASE-IS-INVALID"}},
- // false,
- // },
+ // // Name exists, but is an invalid Docker reference; such names will fail when creating dstReference.
+ // {"oci-archive:testdata/oci-non-docker-name.tar.gz", nil, false},
// Maybe test support of two images in a single archive? It should be transparently handled by adding a reference to srcRef.
// == dir:
{ // Absolute path
"dir:/dev/this-does-not-exist",
- []expected{{"localhost/dev/this-does-not-exist", "localhost/dev/this-does-not-exist"}},
+ []expected{{"localhost/dev/this-does-not-exist", "localhost/dev/this-does-not-exist:latest"}},
false,
},
{ // Relative path, single element.
- // FIXME? Note the :latest difference in .image. (In .dstName as well, but it has the same semantics in there.)
+ // FIXME? Note the :latest difference in .image.
"dir:this-does-not-exist",
[]expected{{"localhost/this-does-not-exist:latest", "localhost/this-does-not-exist:latest"}},
false,
},
{ // Relative path, multiple elements.
- // FIXME: This does not add localhost/, and dstName is parsed as docker.io/testdata.
+ // FIXME: This does not add localhost/, so dstName is normalized to docker.io/testdata.
"dir:testdata/this-does-not-exist",
- []expected{{"testdata/this-does-not-exist", "testdata/this-does-not-exist"}},
+ []expected{{"testdata/this-does-not-exist", "docker.io/testdata/this-does-not-exist:latest"}},
false,
},
@@ -179,24 +238,24 @@ func TestPullGoalNamesFromImageReference(t *testing.T) {
},
// === tarball: (as an example of what happens when ImageReference.DockerReference is nil).
- { // FIXME? The dstName value is invalid, and will fail.
- // (This is NOT an API promise that the results will continue to be this way.)
- "tarball:/dev/null",
- []expected{{"tarball:/dev/null", "tarball:/dev/null"}},
- false,
- },
+ // FIXME? This tries to parse "tarball:/dev/null" as a storageReference, and fails.
+ // (This is NOT an API promise that the results will continue to be this way.)
+ {"tarball:/dev/null", nil, false},
} {
srcRef, err := alltransports.ParseImageName(c.srcName)
require.NoError(t, err, c.srcName)
- res, err := pullGoalNamesFromImageReference(context.Background(), srcRef, c.srcName, nil)
+ res, err := ir.pullGoalFromImageReference(context.Background(), srcRef, c.srcName, nil)
if len(c.expected) == 0 {
assert.Error(t, err, c.srcName)
} else {
require.NoError(t, err, c.srcName)
- require.Len(t, res.refNames, len(c.expected), c.srcName)
+ require.Len(t, res.refPairs, len(c.expected), c.srcName)
for i, e := range c.expected {
- assert.Equal(t, pullRefName{image: e.image, srcRef: srcRef, dstName: e.dstName}, res.refNames[i], fmt.Sprintf("%s #%d", c.srcName, i))
+ testDescription := fmt.Sprintf("%s #%d", c.srcName, i)
+ assert.Equal(t, e.image, res.refPairs[i].image, testDescription)
+ assert.Equal(t, srcRef, res.refPairs[i].srcRef, testDescription)
+ assert.Equal(t, e.dstName, storageReferenceWithoutLocation(res.refPairs[i].dstRef), testDescription)
}
assert.Equal(t, c.expectedPullAllPairs, res.pullAllPairs, c.srcName)
assert.False(t, res.usedSearchRegistries, c.srcName)
@@ -209,11 +268,11 @@ const registriesConfWithSearch = `[registries.search]
registries = ['example.com', 'docker.io']
`
-func TestPullGoalNamesFromPossiblyUnqualifiedName(t *testing.T) {
+func TestPullGoalFromPossiblyUnqualifiedName(t *testing.T) {
const digestSuffix = "@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
- type pullRefStrings struct{ image, srcRef, dstName string } // pullRefName with string data only
+ type pullRefStrings struct{ image, srcRef, dstName string } // pullRefPair with string data only
- registriesConf, err := ioutil.TempFile("", "TestPullGoalNamesFromPossiblyUnqualifiedName")
+ registriesConf, err := ioutil.TempFile("", "TestPullGoalFromPossiblyUnqualifiedName")
require.NoError(t, err)
defer registriesConf.Close()
defer os.Remove(registriesConf.Name())
@@ -221,6 +280,9 @@ func TestPullGoalNamesFromPossiblyUnqualifiedName(t *testing.T) {
err = ioutil.WriteFile(registriesConf.Name(), []byte(registriesConfWithSearch), 0600)
require.NoError(t, err)
+ ir, cleanup := newTestRuntime(t)
+ defer cleanup()
+
// Environment is per-process, so this looks very unsafe; actually it seems fine because tests are not
// run in parallel unless they opt in by calling t.Parallel(). So don’t do that.
oldRCP, hasRCP := os.LookupEnv("REGISTRIES_CONFIG_PATH")
@@ -242,19 +304,18 @@ func TestPullGoalNamesFromPossiblyUnqualifiedName(t *testing.T) {
{ // Fully-explicit docker.io, name-only.
"docker.io/library/busybox",
// (The docker:// representation is shortened by c/image/docker.Reference but it refers to "docker.io/library".)
- []pullRefStrings{{"docker.io/library/busybox", "docker://busybox:latest", "docker.io/library/busybox"}},
+ []pullRefStrings{{"docker.io/library/busybox", "docker://busybox:latest", "docker.io/library/busybox:latest"}},
false,
},
{ // docker.io with implied /library/, name-only.
"docker.io/busybox",
// (The docker:// representation is shortened by c/image/docker.Reference but it refers to "docker.io/library".)
- // The .dstName fields differ for the explicit/implicit /library/ cases, but StorageTransport.ParseStoreReference normalizes that.
- []pullRefStrings{{"docker.io/busybox", "docker://busybox:latest", "docker.io/busybox"}},
+ []pullRefStrings{{"docker.io/busybox", "docker://busybox:latest", "docker.io/library/busybox:latest"}},
false,
},
{ // Qualified example.com, name-only.
"example.com/ns/busybox",
- []pullRefStrings{{"example.com/ns/busybox", "docker://example.com/ns/busybox:latest", "example.com/ns/busybox"}},
+ []pullRefStrings{{"example.com/ns/busybox", "docker://example.com/ns/busybox:latest", "example.com/ns/busybox:latest"}},
false,
},
{ // Qualified example.com, name:tag.
@@ -276,7 +337,7 @@ func TestPullGoalNamesFromPossiblyUnqualifiedName(t *testing.T) {
[]pullRefStrings{
{"example.com/busybox:latest", "docker://example.com/busybox:latest", "example.com/busybox:latest"},
// (The docker:// representation is shortened by c/image/docker.Reference but it refers to "docker.io/library".)
- {"docker.io/busybox:latest", "docker://busybox:latest", "docker.io/busybox:latest"},
+ {"docker.io/busybox:latest", "docker://busybox:latest", "docker.io/library/busybox:latest"},
},
true,
},
@@ -285,7 +346,7 @@ func TestPullGoalNamesFromPossiblyUnqualifiedName(t *testing.T) {
// FIXME: This is interpreted as "registry == ns", and actual pull happens from docker.io/ns/busybox:latest;
// example.com should be first in the list but isn't used at all.
[]pullRefStrings{
- {"ns/busybox", "docker://ns/busybox:latest", "ns/busybox"},
+ {"ns/busybox", "docker://ns/busybox:latest", "docker.io/ns/busybox:latest"},
},
false,
},
@@ -294,7 +355,7 @@ func TestPullGoalNamesFromPossiblyUnqualifiedName(t *testing.T) {
[]pullRefStrings{
{"example.com/busybox:notlatest", "docker://example.com/busybox:notlatest", "example.com/busybox:notlatest"},
// (The docker:// representation is shortened by c/image/docker.Reference but it refers to "docker.io/library".)
- {"docker.io/busybox:notlatest", "docker://busybox:notlatest", "docker.io/busybox:notlatest"},
+ {"docker.io/busybox:notlatest", "docker://busybox:notlatest", "docker.io/library/busybox:notlatest"},
},
true,
},
@@ -304,27 +365,24 @@ func TestPullGoalNamesFromPossiblyUnqualifiedName(t *testing.T) {
// FIXME?! Why is .input and .dstName dropping the digest, and adding :none?!
{"example.com/busybox:none", "docker://example.com/busybox" + digestSuffix, "example.com/busybox:none"},
// (The docker:// representation is shortened by c/image/docker.Reference but it refers to "docker.io/library".)
- {"docker.io/busybox:none", "docker://busybox" + digestSuffix, "docker.io/busybox:none"},
+ {"docker.io/busybox:none", "docker://busybox" + digestSuffix, "docker.io/library/busybox:none"},
},
true,
},
// Unqualified, name:tag@digest. This code is happy to try, but .srcRef parsing currently rejects such input.
{"busybox:notlatest" + digestSuffix, nil, false},
} {
- res, err := pullGoalNamesFromPossiblyUnqualifiedName(c.input)
+ res, err := ir.pullGoalFromPossiblyUnqualifiedName(c.input)
if len(c.expected) == 0 {
assert.Error(t, err, c.input)
} else {
assert.NoError(t, err, c.input)
- strings := make([]pullRefStrings, len(res.refNames))
- for i, rn := range res.refNames {
- strings[i] = pullRefStrings{
- image: rn.image,
- srcRef: transports.ImageName(rn.srcRef),
- dstName: rn.dstName,
- }
+ for i, e := range c.expected {
+ testDescription := fmt.Sprintf("%s #%d", c.input, i)
+ assert.Equal(t, e.image, res.refPairs[i].image, testDescription)
+ assert.Equal(t, e.srcRef, transports.ImageName(res.refPairs[i].srcRef), testDescription)
+ assert.Equal(t, e.dstName, storageReferenceWithoutLocation(res.refPairs[i].dstRef), testDescription)
}
- assert.Equal(t, c.expected, strings, c.input)
assert.False(t, res.pullAllPairs, c.input)
assert.Equal(t, c.expectedUsedSearchRegistries, res.usedSearchRegistries, c.input)
if !c.expectedUsedSearchRegistries {