-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update relocation map during porter publish #2186
Changes from 5 commits
18a0ff6
ef8e2f8
464b82f
2ccad0b
12d87c5
c4279b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,9 @@ import ( | |
"get.porter.sh/porter/pkg/cache" | ||
"get.porter.sh/porter/pkg/cnab" | ||
"github.com/cnabio/cnab-go/bundle" | ||
"github.com/cnabio/cnab-to-oci/relocation" | ||
"github.com/pivotal/image-relocation/pkg/image" | ||
"github.com/pivotal/image-relocation/pkg/registry" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
@@ -33,7 +35,7 @@ func TestPublish_Validate_PorterYamlDoesNotExist(t *testing.T) { | |
assert.EqualError( | ||
t, | ||
err, | ||
"could not find porter.yaml in the current directory, make sure you are in the right directory or specify the porter manifest with --file", | ||
"could not find porter.yaml in the current directory /, make sure you are in the right directory or specify the porter manifest with --file", | ||
"porter.yaml not present so should have failed validation", | ||
) | ||
} | ||
|
@@ -145,51 +147,56 @@ func TestPublish_getNewImageNameFromBundleReference(t *testing.T) { | |
}) | ||
} | ||
|
||
func TestPublish_UpdateBundleWithNewImage(t *testing.T) { | ||
func TestPublish_UpdateRelocationMapping(t *testing.T) { | ||
p := NewTestPorter(t) | ||
defer p.Close() | ||
|
||
bun := cnab.NewBundle(bundle.Bundle{ | ||
Name: "mybuns", | ||
InvocationImages: []bundle.InvocationImage{ | ||
{ | ||
BaseImage: bundle.BaseImage{ | ||
Image: "myorg/myinvimg", | ||
Digest: "abc", | ||
}, | ||
}, | ||
}, | ||
Images: map[string]bundle.Image{ | ||
"myimg": { | ||
BaseImage: bundle.BaseImage{ | ||
Image: "myorg/myimg", | ||
Digest: "abc", | ||
}, | ||
}, | ||
}, | ||
}) | ||
originImg := "myorg/myinvimg" | ||
tag := "myneworg/mynewbuns" | ||
|
||
digest, err := image.NewDigest("sha256:6b5a28ccbb76f12ce771a23757880c6083234255c5ba191fca1c5db1f71c1687") | ||
require.NoError(t, err, "should have successfully created a digest") | ||
|
||
// update invocation image | ||
newInvImgName, err := getNewImageNameFromBundleReference(bun.InvocationImages[0].Image, tag) | ||
require.NoError(t, err, "should have successfully derived new image name from bundle tag") | ||
testcases := []struct { | ||
description string | ||
relocationMap relocation.ImageRelocationMap | ||
layout registry.Layout | ||
hasError bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's change this to use |
||
}{ | ||
{description: "has relocation mapping defined", relocationMap: relocation.ImageRelocationMap{"myorg/myinvimg": "private/myinvimg"}, layout: mockRegistryLayout{expectedDigest: digest}}, | ||
{description: "empty relocation map", relocationMap: relocation.ImageRelocationMap{}, layout: mockRegistryLayout{expectedDigest: digest}}, | ||
{description: "failed to update", relocationMap: relocation.ImageRelocationMap{"myorg/myinvimg": "private/myinvimg"}, layout: mockRegistryLayout{hasError: true}, hasError: true}, | ||
} | ||
|
||
err = p.updateBundleWithNewImage(bun, newInvImgName, digest, 0) | ||
require.NoError(t, err, "updating bundle with new image should not have failed") | ||
require.Equal(t, tag+":535ae3fd0b6a46c169fd3d38b486a8a2@sha256:6b5a28ccbb76f12ce771a23757880c6083234255c5ba191fca1c5db1f71c1687", bun.InvocationImages[0].Image) | ||
require.Equal(t, "sha256:6b5a28ccbb76f12ce771a23757880c6083234255c5ba191fca1c5db1f71c1687", bun.InvocationImages[0].Digest) | ||
for _, tc := range testcases { | ||
tc := tc | ||
t.Run(tc.description, func(t *testing.T) { | ||
newMap, err := p.updateRelocationMapping(tc.relocationMap, tc.layout, originImg, tag) | ||
require.Equal(t, tc.hasError, err != nil) | ||
if !tc.hasError { | ||
require.Equal(t, tag+":535ae3fd0b6a46c169fd3d38b486a8a2@sha256:6b5a28ccbb76f12ce771a23757880c6083234255c5ba191fca1c5db1f71c1687", newMap[originImg]) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// update image | ||
newImgName, err := getNewImageNameFromBundleReference(bun.Images["myimg"].Image, tag) | ||
require.NoError(t, err, "should have successfully derived new image name from bundle tag") | ||
type mockRegistryLayout struct { | ||
hasError bool | ||
expectedDigest image.Digest | ||
} | ||
|
||
func (m mockRegistryLayout) Add(name image.Name) (image.Digest, error) { | ||
if m.hasError { | ||
return image.EmptyDigest, errors.New("failed to add image") | ||
} | ||
return m.expectedDigest, nil | ||
} | ||
|
||
func (m mockRegistryLayout) Push(digest image.Digest, name image.Name) error { | ||
return nil | ||
} | ||
|
||
err = p.updateBundleWithNewImage(bun, newImgName, digest, "myimg") | ||
require.NoError(t, err, "updating bundle with new image should not have failed") | ||
require.Equal(t, tag+":2055d740dd5c7ec245f0ce739ef7ab57@sha256:6b5a28ccbb76f12ce771a23757880c6083234255c5ba191fca1c5db1f71c1687", bun.Images["myimg"].Image) | ||
require.Equal(t, "sha256:6b5a28ccbb76f12ce771a23757880c6083234255c5ba191fca1c5db1f71c1687", bun.Images["myimg"].Digest) | ||
func (m mockRegistryLayout) Find(n image.Name) (image.Digest, error) { | ||
return m.expectedDigest, nil | ||
} | ||
|
||
func TestPublish_RefreshCachedBundle(t *testing.T) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,6 +77,8 @@ func TestArchive_StableDigest(t *testing.T) { | |
|
||
// Use a fixed bundle to work with so that we can rely on the registry and layer digests | ||
const reference = "ghcr.io/getporter/examples/whalegap:v0.2.0" | ||
const referencedImg = "carolynvs/whalesayd@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was expecting that these extra validations would be added to the Airgapped test above, since this feature supports airgap and testing it requires that we are making it impossible to use the original images by taking the original registry offline. The test you are editing is for checking that when we archive twice, we get the same digest. Can you move these checks into the other test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good |
||
const invocationImg = "ghcr.io/getporter/examples/whalegap:2bed6d7bf087c159835ddfac5838fd34@sha256:5ada057d9b24c443d9fb0240b49c13a5a36a11d5f4dda8adaaa2ec74e39c0d24" | ||
|
||
// Archive bundle | ||
archive1Opts := porter.ArchiveOptions{} | ||
|
@@ -91,7 +93,9 @@ func TestArchive_StableDigest(t *testing.T) { | |
info, err := p.FileSystem.Stat(archiveFile1) | ||
require.NoError(p.T(), err) | ||
tests.AssertFilePermissionsEqual(t, archiveFile1, pkg.FileModeWritable, info.Mode()) | ||
containsRequiredMetadata(p, archiveFile1) | ||
relocMap := getRelocationMap(p, archiveFile1) | ||
require.Equal(p.T(), relocMap[referencedImg], "ghcr.io/getporter/examples/whalegap@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f", relocMap) | ||
require.Equal(p.T(), relocMap[invocationImg], "ghcr.io/getporter/examples/whalegap@sha256:5ada057d9b24c443d9fb0240b49c13a5a36a11d5f4dda8adaaa2ec74e39c0d24", relocMap) | ||
|
||
hash1 := getHash(p, archiveFile1) | ||
|
||
|
@@ -108,20 +112,36 @@ func TestArchive_StableDigest(t *testing.T) { | |
err = p.Archive(ctx, archive2Opts) | ||
require.NoError(t, err, "Second archive failed") | ||
assert.Equal(p.T(), hash1, getHash(p, archiveFile2), "shasum of archive did not stay the same on the second call to archive") | ||
containsRequiredMetadata(p, archiveFile2) | ||
relocMap = getRelocationMap(p, archiveFile1) | ||
require.Equal(p.T(), relocMap[referencedImg], "ghcr.io/getporter/examples/whalegap@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f", relocMap) | ||
require.Equal(p.T(), relocMap[invocationImg], "ghcr.io/getporter/examples/whalegap@sha256:5ada057d9b24c443d9fb0240b49c13a5a36a11d5f4dda8adaaa2ec74e39c0d24", relocMap) | ||
|
||
// Publish bundle from archive, with new reference | ||
localReference := "localhost:5000/archived-whalegap:v0.2.0" | ||
publishFromArchiveOpts := porter.PublishOptions{ | ||
ArchiveFile: archiveFile1, | ||
BundlePullOptions: porter.BundlePullOptions{ | ||
Reference: fmt.Sprintf("localhost:5000/archived-whalegap:v0.2.0"), | ||
Reference: localReference, | ||
}, | ||
} | ||
err = publishFromArchiveOpts.Validate(p.Context) | ||
require.NoError(p.T(), err, "validation of publish opts for bundle failed") | ||
|
||
err = p.Publish(ctx, publishFromArchiveOpts) | ||
require.NoError(p.T(), err, "publish of bundle from archive failed") | ||
|
||
// Archive from the newly published bundle in local registry | ||
archive3Opts := porter.ArchiveOptions{} | ||
archive3Opts.Reference = localReference | ||
archiveFile3 := "mybuns3.tgz" | ||
err = archive3Opts.Validate(ctx, []string{archiveFile3}, p.Porter) | ||
require.NoError(p.T(), err, "validation of archive opts for bundle failed") | ||
err = p.Archive(ctx, archive3Opts) | ||
require.NoError(t, err, "archive from the published bundle in local registry failed") | ||
// make sure the relocation map has updated to use local registry for referenced images | ||
relocMap = getRelocationMap(p, archiveFile3) | ||
require.Equal(p.T(), relocMap[referencedImg], "localhost:5000/archived-whalegap@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f", relocMap) | ||
require.Equal(p.T(), relocMap[invocationImg], "localhost:5000/archived-whalegap@sha256:5ada057d9b24c443d9fb0240b49c13a5a36a11d5f4dda8adaaa2ec74e39c0d24", relocMap) | ||
} | ||
|
||
func getHash(p *porter.TestPorter, path string) string { | ||
|
@@ -136,26 +156,24 @@ func getHash(p *porter.TestPorter, path string) string { | |
return fmt.Sprintf("%x", h.Sum(nil)) | ||
} | ||
|
||
func containsRequiredMetadata(p *porter.TestPorter, path string) { | ||
func getRelocationMap(p *porter.TestPorter, archiveFilePath string) relocation.ImageRelocationMap { | ||
tmpDir, err := p.FileSystem.TempDir("", "porter-integration-tests") | ||
require.NoError(p.T(), err) | ||
defer p.FileSystem.RemoveAll(tmpDir) | ||
|
||
source := p.FileSystem.Abs(path) | ||
source := p.FileSystem.Abs(archiveFilePath) | ||
l := loader.NewLoader() | ||
imp := packager.NewImporter(source, tmpDir, l) | ||
err = imp.Import() | ||
require.NoError(p.T(), err, "opening archive failed") | ||
|
||
_, err = p.FileSystem.Stat(filepath.Join(tmpDir, strings.TrimSuffix(filepath.Base(source), ".tgz"), "bundle.json")) | ||
require.NoError(p.T(), err) | ||
relocMapBytes, err := p.FileSystem.ReadFile(filepath.Join(tmpDir, strings.TrimSuffix(filepath.Base(source), ".tgz"), "relocation-mapping.json")) | ||
require.NoError(p.T(), err) | ||
|
||
// make sure the relocation map contains the expected image | ||
relocMap := relocation.ImageRelocationMap{} | ||
require.NoError(p.T(), json.Unmarshal(relocMapBytes, &relocMap)) | ||
require.Equal(p.T(), relocMap["carolynvs/whalesayd@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f"], "ghcr.io/getporter/examples/whalegap@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f", relocMap) | ||
require.Equal(p.T(), relocMap["ghcr.io/getporter/examples/whalegap:2bed6d7bf087c159835ddfac5838fd34@sha256:5ada057d9b24c443d9fb0240b49c13a5a36a11d5f4dda8adaaa2ec74e39c0d24"], "ghcr.io/getporter/examples/whalegap@sha256:5ada057d9b24c443d9fb0240b49c13a5a36a11d5f4dda8adaaa2ec74e39c0d24", relocMap) | ||
|
||
_, err = p.FileSystem.Stat(filepath.Join(tmpDir, strings.TrimSuffix(filepath.Base(source), ".tgz"), "bundle.json")) | ||
require.NoError(p.T(), err) | ||
return relocMap | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function name made me initially assume that this function only updated the relocation mapping file, and it never ocurred to me that it would also push the image. What do you think about changing the function name so that it's more obvious what it does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's good point and a great name. I will change it