Skip to content
This repository has been archived by the owner on May 3, 2022. It is now read-only.

Commit

Permalink
Relocate invocation images
Browse files Browse the repository at this point in the history
Also allow for images not to have digest fields set.

Fixes #706
  • Loading branch information
glyn committed Apr 23, 2019
1 parent 1ca5e40 commit a67cf0d
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 24 deletions.
68 changes: 45 additions & 23 deletions cmd/duffle/relocate.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import (

const (
relocateDesc = `
Relocates any docker and oci images referenced by a bundle, tags and pushes the images to a registry, and creates a new
bundle with an updated image map.
Relocates any docker and oci images, including invocation images, referenced by a bundle, tags and pushes the images to
a registry, and creates a new bundle with an updated invocation images section and an updated image map.
The --repository-prefix flag determines the repositories for the relocated images.
Each image is tagged with a name starting with the given prefix and pushed to the repository.
Expand Down Expand Up @@ -115,36 +115,58 @@ func (r *relocateCmd) relocate(bun *bundle.Bundle) error {
bun.Name = r.outputBundle
}

for i := range bun.InvocationImages {
ii := bun.InvocationImages[i]
modified, err := r.relocateImage(&ii.BaseImage)
if err != nil {
return err
}
if modified {
bun.InvocationImages[i] = ii
}
}

for k := range bun.Images {
im := bun.Images[k]
if isOCI(im.ImageType) || isDocker(im.ImageType) {
// map the image name
n, err := image.NewName(im.Image)
if err != nil {
return err
}
rn := r.mapping(r.repoPrefix, n)

// tag/push the image to its new repository
dig, err := r.registryClient.Copy(n, rn)
if err != nil {
return err
}
if dig.String() != im.Digest {
// should not happen
return fmt.Errorf("digest of image %s not preserved: old digest %s; new digest %s", im.Image, im.Digest, dig.String())
}

// update the imagemap
im.OriginalImage = im.Image
im.Image = rn.String()
modified, err := r.relocateImage(&im.BaseImage)
if err != nil {
return err
}
if modified {
bun.Images[k] = im
}
}

return nil
}

func (r *relocateCmd) relocateImage(i *bundle.BaseImage) (bool, error) {
if !isOCI(i.ImageType) && !isDocker(i.ImageType) {
return false, nil
}
// map the image name
n, err := image.NewName(i.Image)
if err != nil {
return false, err
}
rn := r.mapping(r.repoPrefix, n)

// tag/push the image to its new repository
dig, err := r.registryClient.Copy(n, rn)
if err != nil {
return false, err
}
if i.Digest != "" && dig.String() != i.Digest {
// should not happen
return false, fmt.Errorf("digest of image %s not preserved: old digest %s; new digest %s", i.Image, i.Digest, dig.String())
}

// update the imagemap
i.OriginalImage = i.Image
i.Image = rn.String()
return true, nil
}

func isOCI(imageType string) bool {
return imageType == "" || imageType == "oci"
}
Expand Down
26 changes: 26 additions & 0 deletions cmd/duffle/relocate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import (
const (
testRepositoryPrefix = "example.com/user"

originalInvocationImageName = "technosophos/helloworld:0.1.0"
relocatedInvocationImageName = "example.com/user/technosophos/helloworld/relocated:0.1.0"
invocationImageDigest = "sha256:86959ecb500308ae523922eab84f2f94082f20b4e7bda84ce9be219f3f1b4e65"

originalImageNameA = "deislabs/duffle@sha256:4d41eeb38fb14266b7c0461ef1ef0b2f8c05f41cd544987a259a9d92cdad2540"
relocatedImageNameA = "example.com/user/deislabs/duffle/relocated@sha256:4d41eeb38fb14266b7c0461ef1ef0b2f8c05f41cd544987a259a9d92cdad2540"
imageDigestA = "sha256:4d41eeb38fb14266b7c0461ef1ef0b2f8c05f41cd544987a259a9d92cdad2540"
Expand Down Expand Up @@ -70,6 +74,10 @@ func relocateFileToFile(t *testing.T, preserveDigest bool, expectedErr error) {
},
registryClient: &mockRegClient{
copyStub: func(source image.Name, target image.Name) (image.Digest, error) {
oiin, err := image.NewName(originalInvocationImageName)
if err != nil {
t.Fatal(err)
}
oinA, err := image.NewName(originalImageNameA)
if err != nil {
t.Fatal(err)
Expand All @@ -79,6 +87,10 @@ func relocateFileToFile(t *testing.T, preserveDigest bool, expectedErr error) {
t.Fatal(err)
}
switch source {
case oiin:
if target.String() == relocatedInvocationImageName {
return image.NewDigest(invocationImageDigest)
}
case oinA:
if target.String() == relocatedImageNameA {
return image.NewDigest(imageDigestA)
Expand Down Expand Up @@ -124,6 +136,19 @@ func relocateFileToFile(t *testing.T, preserveDigest bool, expectedErr error) {
t.Fatal(err)
}

ii := bun.InvocationImages[0]
actualInvocationImageName := ii.Image
if actualInvocationImageName != relocatedInvocationImageName {
t.Fatalf("output bundle has invocation image with unexpected name: %q (expected %q)",
actualInvocationImageName, relocatedInvocationImageName)
}

actualOriginalInvocationImageName := ii.OriginalImage
if actualOriginalInvocationImageName != originalInvocationImageName {
t.Fatalf("output bundle has invocation image with unexpected original name: %q (expected %q)",
actualOriginalInvocationImageName, originalInvocationImageName)
}

assertImage := func(i string, expectedOriginalImageName string, expectedImageName string) {
img := bun.Images[i]

Expand All @@ -146,6 +171,7 @@ func relocateFileToFile(t *testing.T, preserveDigest bool, expectedErr error) {
}

// naïve test mapping, preserving any tag and/or digest
// Note: unlike the real mapping, this produces names with more than two slash-separated components.
func testMapping(originalImage image.Name, t *testing.T) image.Name {
rn, err := image.NewName(path.Join(testRepositoryPrefix, originalImage.Path(), "relocated"))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/duffle/testdata/relocate/bundle.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "a bundle with images",
"invocationImages": [
{
"image": "deislabs/helloworld-cnab:675c2daf7449ae58927f251acdd88acb9d1e9767",
"image": "technosophos/helloworld:0.1.0",
"imageType": "docker"
}
],
Expand Down

0 comments on commit a67cf0d

Please sign in to comment.