Skip to content

Commit e2cab5f

Browse files
Merge pull request #758 from rosenhouse/gabe/shallow-copy-bundle
Allow shallow-copy of a bundle
2 parents 3908d6f + 795ad3e commit e2cab5f

4 files changed

Lines changed: 94 additions & 9 deletions

File tree

pkg/imgpkg/cmd/copy.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ import (
2323
type CopyOptions struct {
2424
ui ui.UI
2525

26-
ImageFlags ImageFlags
27-
BundleFlags BundleFlags
28-
LockInputFlags LockInputFlags
29-
LockOutputFlags LockOutputFlags
30-
TarFlags TarFlags
31-
RegistryFlags RegistryFlags
32-
SignatureFlags SignatureFlags
26+
ImageFlags ImageFlags
27+
IgnoreBundleCheck bool
28+
BundleFlags BundleFlags
29+
LockInputFlags LockInputFlags
30+
LockOutputFlags LockOutputFlags
31+
TarFlags TarFlags
32+
RegistryFlags RegistryFlags
33+
SignatureFlags SignatureFlags
3334

3435
RepoDst string
3536

@@ -73,6 +74,7 @@ func NewCopyCmd(o *CopyOptions) *cobra.Command {
7374
}
7475

7576
o.ImageFlags.SetCopy(cmd)
77+
cmd.Flags().BoolVar(&o.IgnoreBundleCheck, "ignore-bundle-check", false, "When set to true with -i, imgpkg will not check if the image is a bundle. This enables shallow-copying the bundle image.")
7678
o.BundleFlags.SetCopy(cmd)
7779
o.LockInputFlags.Set(cmd)
7880
o.LockOutputFlags.SetOnCopy(cmd)
@@ -95,6 +97,9 @@ func (c *CopyOptions) Run() error {
9597
if !c.hasOneDst() {
9698
return fmt.Errorf("Expected either --to-tar or --to-repo")
9799
}
100+
if c.IgnoreBundleCheck && len(c.BundleFlags.Bundle) != 0 {
101+
return fmt.Errorf("Cannot set --ignore-bundle-check while using -b flag")
102+
}
98103

99104
registryOpts := c.RegistryFlags.AsRegistryOpts()
100105
registryOpts.IncludeNonDistributableLayers = c.IncludeNonDistributable
@@ -130,6 +135,7 @@ func (c *CopyOptions) Run() error {
130135

131136
opts := v1.CopyOpts{
132137
Logger: levelLogger,
138+
AllowShallowCopyBundle: c.IgnoreBundleCheck,
133139
ImageSet: imageSet,
134140
TarImageSet: tarImageSet,
135141
Concurrency: c.Concurrency,

pkg/imgpkg/v1/copy.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const rootBundleLabelKey string = "dev.carvel.imgpkg.copy.root-bundle"
2323
type CopyOpts struct {
2424
Logger Logger
2525
ImageSet ctlimgset.ImageSet
26+
AllowShallowCopyBundle bool
2627
TarImageSet ctlimgset.TarImageSet
2728
Concurrency int
2829
SignatureRetriever SignatureFetcher
@@ -216,11 +217,11 @@ func getProvidedSourceImages(origin CopyOrigin, reg registry.Registry, opts Copy
216217
opts.Logger.Tracef("copy single image\n")
217218
plainImg := plainimage.NewPlainImage(origin.ImageRef, reg)
218219

219-
ok, err := ctlbundle.NewBundleFromPlainImage(plainImg, reg).IsBundle()
220+
isBundle, err := ctlbundle.NewBundleFromPlainImage(plainImg, reg).IsBundle()
220221
if err != nil {
221222
return nil, nil, err
222223
}
223-
if ok {
224+
if isBundle && !opts.AllowShallowCopyBundle {
224225
return nil, nil, fmt.Errorf("Expected bundle flag when copying a bundle (hint: Use -b instead of -i for bundles)")
225226
}
226227

pkg/imgpkg/v1/copy_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,38 @@ bundle:
126126

127127
assertTarballLabelsOuterBundle(bundleTarPath, origin.BundleRef, t)
128128
})
129+
130+
t.Run("When attemping to shallow-copy without the special flag, it fails", func(t *testing.T) {
131+
originForShallowCopy := v1.CopyOrigin{
132+
ImageRef: origin.BundleRef,
133+
}
134+
bundleTarPath := filepath.Join(os.TempDir(), "bundle.tar")
135+
defer os.Remove(bundleTarPath)
136+
137+
_, err := v1.CopyToTar(originForShallowCopy, bundleTarPath, opts, reg)
138+
require.ErrorContains(t, err, "Expected bundle flag when copying a bundle (hint: Use -b instead of -i for bundles)")
139+
})
140+
141+
t.Run("When attemping to shallow-copy with the special flag, it succeeds, but only copies the top-level bundle image and not nested images", func(t *testing.T) {
142+
originForShallowCopy := v1.CopyOrigin{
143+
ImageRef: origin.BundleRef,
144+
}
145+
bundleTarPath := filepath.Join(os.TempDir(), "bundle.tar")
146+
defer os.Remove(bundleTarPath)
147+
148+
shallowCopyOpts := opts
149+
shallowCopyOpts.AllowShallowCopyBundle = true
150+
151+
_, err := v1.CopyToTar(originForShallowCopy, bundleTarPath, shallowCopyOpts, reg)
152+
require.NoError(t, err)
153+
154+
assertTarballContainsOnlyDistributableLayers(bundleTarPath, t)
155+
156+
reader := imagetar.NewTarReader(bundleTarPath, 1)
157+
layersInTar, err := reader.PresentLayers()
158+
require.NoError(t, err)
159+
require.Len(t, layersInTar, 1)
160+
})
129161
}
130162

131163
func TestToTarBundleContainingNonDistributableLayers(t *testing.T) {

test/e2e/copy_from_image_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,49 @@ func startRegistryForAirgapTesting(t *testing.T, env *helpers.Env) (string, *hel
468468

469469
return fakeRegistry.ReferenceOnTestServer("repo/airgapped-image"), fakeRegistry
470470
}
471+
472+
func TestShallowCopyOfBundle(t *testing.T) {
473+
logger := &helpers.Logger{}
474+
475+
env := helpers.BuildEnv(t)
476+
imgpkg := helpers.Imgpkg{T: t, L: helpers.Logger{}, ImgpkgPath: env.ImgpkgPath}
477+
defer env.Cleanup()
478+
479+
registry := helpers.NewFakeRegistry(t, logger)
480+
randomBundle := registry.WithBundleFromPath("repo/some-bundle-name", "assets/bundle")
481+
registry.Build()
482+
defer registry.CleanUp()
483+
484+
t.Run("when --ignore-bundle-check is NOT provided it fails", func(t *testing.T) {
485+
out := bytes.NewBufferString("")
486+
_, err := imgpkg.RunWithOpts([]string{"copy", "--tty", "-i", randomBundle.RefDigest, "--to-repo", env.RelocationRepo}, helpers.RunOpts{
487+
AllowError: true,
488+
StderrWriter: out,
489+
StdoutWriter: out,
490+
})
491+
492+
require.Error(t, err)
493+
assert.Contains(t, out.String(), "Expected bundle flag when copying a bundle (hint: Use -b instead of -i for bundles)")
494+
})
495+
496+
t.Run("when --ignore-bundle-check=true is provided while using the -b flag it fails", func(t *testing.T) {
497+
out := bytes.NewBufferString("")
498+
_, err := imgpkg.RunWithOpts([]string{"copy", "--tty", "-b", randomBundle.RefDigest, "--to-repo", env.RelocationRepo, "--ignore-bundle-check"}, helpers.RunOpts{
499+
AllowError: true,
500+
StderrWriter: out,
501+
StdoutWriter: out,
502+
})
503+
504+
require.Error(t, err)
505+
assert.Contains(t, out.String(), "Cannot set --ignore-bundle-check while using -b flag")
506+
})
507+
508+
t.Run("when --ignore-bundle-check=true is provided it copies the OCI Image of the bundle (shallow copy)", func(t *testing.T) {
509+
imgpkg.RunWithOpts([]string{"copy", "--tty", "-i", randomBundle.RefDigest, "--to-repo", env.RelocationRepo, "--ignore-bundle-check"}, helpers.RunOpts{})
510+
511+
parts := strings.SplitN(randomBundle.RefDigest, "@", 2)
512+
require.Len(t, parts, 2)
513+
imageWithDigest := env.RelocationRepo + "@" + parts[1]
514+
require.NoError(t, env.Assert.ValidateImagesPresenceInRegistry([]string{imageWithDigest}))
515+
})
516+
}

0 commit comments

Comments
 (0)