Add imageParts.referenceWithRegistry

This is the primary goal of decompose()+assemble(), to support
qualifying an image name.

Does not have any users yet, so does not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač
2019-01-09 20:32:30 +01:00
parent ae2a95196e
commit 72777b7fee
2 changed files with 60 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ import (
"strings"
"github.com/containers/image/docker/reference"
"github.com/pkg/errors"
)
// imageParts describes the parts of an image's name
@@ -76,6 +77,23 @@ func decompose(input string) (imageParts, error) {
}, nil
}
// referenceWithRegistry returns a (normalized) reference.Named composed of ip (with !ip.hasRegistry)
// qualified with registry.
func (ip *imageParts) referenceWithRegistry(registry string) (reference.Named, error) {
if ip.hasRegistry {
return nil, errors.Errorf("internal error: referenceWithRegistry called on imageParts with a registry (%#v)", *ip)
}
// We could build a reference.WithName+WithTag/WithDigest here, but we need to round-trip via a string
// and a ParseNormalizedNamed anyway to get the right normalization of docker.io/library, so
// just use a string directly.
qualified := registry + "/" + ip.unnormalizedRef.String()
ref, err := reference.ParseNormalizedNamed(qualified)
if err != nil {
return nil, errors.Wrapf(err, "error normalizing registry+unqualified reference %#v", qualified)
}
return ref, nil
}
// assemble concatenates an image's parts into a string
func (ip *imageParts) assemble() string {
spec := fmt.Sprintf("%s:%s", ip.name, ip.tag)

View File

@@ -4,6 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDecompose(t *testing.T) {
@@ -62,3 +63,44 @@ func TestDecompose(t *testing.T) {
}
}
}
func TestImagePartsReferenceWithRegistry(t *testing.T) {
const digestSuffix = "@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
for _, c := range []struct {
input string
withDocker, withNonDocker string
}{
{"example.com/ns/busybox", "", ""}, // Fully-qualified input is invalid.
{"busybox", "docker.io/library/busybox", "example.com/busybox"}, // Single-name input
{"ns/busybox", "docker.io/ns/busybox", "example.com/ns/busybox"}, // Namespaced input
{"ns/busybox:notlatest", "docker.io/ns/busybox:notlatest", "example.com/ns/busybox:notlatest"}, // name:tag
{"ns/busybox" + digestSuffix, "docker.io/ns/busybox" + digestSuffix, "example.com/ns/busybox" + digestSuffix}, // name@digest
{ // name:tag@digest
"ns/busybox:notlatest" + digestSuffix,
"docker.io/ns/busybox:notlatest" + digestSuffix, "example.com/ns/busybox:notlatest" + digestSuffix,
},
} {
parts, err := decompose(c.input)
require.NoError(t, err)
if c.withDocker == "" {
_, err := parts.referenceWithRegistry("docker.io")
assert.Error(t, err, c.input)
_, err = parts.referenceWithRegistry("example.com")
assert.Error(t, err, c.input)
} else {
ref, err := parts.referenceWithRegistry("docker.io")
require.NoError(t, err, c.input)
assert.Equal(t, c.withDocker, ref.String())
ref, err = parts.referenceWithRegistry("example.com")
require.NoError(t, err, c.input)
assert.Equal(t, c.withNonDocker, ref.String())
}
}
// Invalid registry value
parts, err := decompose("busybox")
require.NoError(t, err)
_, err = parts.referenceWithRegistry("invalid@domain")
assert.Error(t, err)
}