Skip to content

Commit 59417ae

Browse files
authored
Merge pull request #2609 from mtrmac/copy-resolve-destination
Add Copy.Options.ReportResolvedReference
2 parents ba2a4ae + 6ba898f commit 59417ae

File tree

17 files changed

+188
-104
lines changed

17 files changed

+188
-104
lines changed

copy/copy.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,17 @@ type Options struct {
137137
// DestinationCtx.CompressionFormat is used exclusively, and blobs of other
138138
// compression algorithms are not reused.
139139
ForceCompressionFormat bool
140+
141+
// ReportResolvedReference, if set, asks the destination transport to store
142+
// a “resolved” (more detailed) reference to the created image
143+
// into the value this option points to.
144+
// What “resolved” means is transport-specific.
145+
// Most transports don’t support this, and cause the value to be set to nil.
146+
//
147+
// For the containers-storage: transport, the reference contains an image ID,
148+
// so that storage.ResolveReference returns exactly the created image.
149+
// WARNING: It is unspecified whether the reference also contains a reference.Named element.
150+
ReportResolvedReference *types.ImageReference
140151
}
141152

142153
// OptionCompressionVariant allows to supply information about
@@ -337,7 +348,13 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
337348
}
338349
}
339350

340-
if err := c.dest.Commit(ctx, c.unparsedToplevel); err != nil {
351+
if options.ReportResolvedReference != nil {
352+
*options.ReportResolvedReference = nil // The default outcome, if not specifically supported by the transport.
353+
}
354+
if err := c.dest.CommitWithOptions(ctx, private.CommitOptions{
355+
UnparsedToplevel: c.unparsedToplevel,
356+
ReportResolvedReference: options.ReportResolvedReference,
357+
}); err != nil {
341358
return nil, fmt.Errorf("committing the finished image: %w", err)
342359
}
343360

directory/directory_dest.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,11 @@ func (d *dirImageDestination) PutSignaturesWithFormat(ctx context.Context, signa
251251
return nil
252252
}
253253

254-
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
255-
// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
256-
// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
257-
// original manifest list digest, if desired.
254+
// CommitWithOptions marks the process of storing the image as successful and asks for the image to be persisted.
258255
// WARNING: This does not have any transactional semantics:
259-
// - Uploaded data MAY be visible to others before Commit() is called
260-
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
261-
func (d *dirImageDestination) Commit(context.Context, types.UnparsedImage) error {
256+
// - Uploaded data MAY be visible to others before CommitWithOptions() is called
257+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed)
258+
func (d *dirImageDestination) CommitWithOptions(ctx context.Context, options private.CommitOptions) error {
262259
return nil
263260
}
264261

docker/archive/dest.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,17 @@ func newImageDestination(sys *types.SystemContext, ref archiveReference) (privat
3434
writer = w
3535
closeWriter = true
3636
}
37-
tarDest := tarfile.NewDestination(sys, writer.archive, ref.Transport().Name(), ref.ref)
38-
if sys != nil && sys.DockerArchiveAdditionalTags != nil {
39-
tarDest.AddRepoTags(sys.DockerArchiveAdditionalTags)
40-
}
41-
return &archiveImageDestination{
42-
Destination: tarDest,
37+
d := &archiveImageDestination{
4338
ref: ref,
4439
writer: writer,
4540
closeWriter: closeWriter,
46-
}, nil
41+
}
42+
tarDest := tarfile.NewDestination(sys, writer.archive, ref.Transport().Name(), ref.ref, d.CommitWithOptions)
43+
if sys != nil && sys.DockerArchiveAdditionalTags != nil {
44+
tarDest.AddRepoTags(sys.DockerArchiveAdditionalTags)
45+
}
46+
d.Destination = tarDest
47+
return d, nil
4748
}
4849

4950
// Reference returns the reference used to set up this destination. Note that this should directly correspond to user's intent,
@@ -60,14 +61,11 @@ func (d *archiveImageDestination) Close() error {
6061
return nil
6162
}
6263

63-
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
64-
// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
65-
// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
66-
// original manifest list digest, if desired.
64+
// CommitWithOptions marks the process of storing the image as successful and asks for the image to be persisted.
6765
// WARNING: This does not have any transactional semantics:
68-
// - Uploaded data MAY be visible to others before Commit() is called
69-
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
70-
func (d *archiveImageDestination) Commit(ctx context.Context, unparsedToplevel types.UnparsedImage) error {
66+
// - Uploaded data MAY be visible to others before CommitWithOptions() is called
67+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed)
68+
func (d *archiveImageDestination) CommitWithOptions(ctx context.Context, options private.CommitOptions) error {
7169
d.writer.imageCommitted()
7270
if d.closeWriter {
7371
// We could do this only in .Close(), but failures in .Close() are much more likely to be

docker/daemon/daemon_dest.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,17 @@ func newImageDestination(ctx context.Context, sys *types.SystemContext, ref daem
5656
goroutineContext, goroutineCancel := context.WithCancel(ctx)
5757
go imageLoadGoroutine(goroutineContext, c, reader, statusChannel)
5858

59-
return &daemonImageDestination{
59+
d := &daemonImageDestination{
6060
ref: ref,
6161
mustMatchRuntimeOS: mustMatchRuntimeOS,
62-
Destination: tarfile.NewDestination(sys, archive, ref.Transport().Name(), namedTaggedRef),
6362
archive: archive,
6463
goroutineCancel: goroutineCancel,
6564
statusChannel: statusChannel,
6665
writer: writer,
6766
committed: false,
68-
}, nil
67+
}
68+
d.Destination = tarfile.NewDestination(sys, archive, ref.Transport().Name(), namedTaggedRef, d.CommitWithOptions)
69+
return d, nil
6970
}
7071

7172
// imageLoadGoroutine accepts tar stream on reader, sends it to c, and reports error or success by writing to statusChannel
@@ -146,7 +147,7 @@ func (d *daemonImageDestination) Close() error {
146147
// immediately, and hopefully, through terminating the sending which uses "Transfer-Encoding: chunked"" without sending
147148
// the terminating zero-length chunk, prevent the docker daemon from processing the tar stream at all.
148149
// Whether that works or not, closing the PipeWriter seems desirable in any case.
149-
if err := d.writer.CloseWithError(errors.New("Aborting upload, daemonImageDestination closed without a previous .Commit()")); err != nil {
150+
if err := d.writer.CloseWithError(errors.New("Aborting upload, daemonImageDestination closed without a previous .CommitWithOptions()")); err != nil {
150151
return err
151152
}
152153
}
@@ -159,14 +160,11 @@ func (d *daemonImageDestination) Reference() types.ImageReference {
159160
return d.ref
160161
}
161162

162-
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
163-
// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
164-
// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
165-
// original manifest list digest, if desired.
163+
// CommitWithOptions marks the process of storing the image as successful and asks for the image to be persisted.
166164
// WARNING: This does not have any transactional semantics:
167-
// - Uploaded data MAY be visible to others before Commit() is called
168-
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
169-
func (d *daemonImageDestination) Commit(ctx context.Context, unparsedToplevel types.UnparsedImage) error {
165+
// - Uploaded data MAY be visible to others before CommitWithOptions() is called
166+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed)
167+
func (d *daemonImageDestination) CommitWithOptions(ctx context.Context, options private.CommitOptions) error {
170168
logrus.Debugf("docker-daemon: Closing tar stream")
171169
if err := d.archive.Close(); err != nil {
172170
return err

docker/docker_image_dest.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -923,13 +923,10 @@ func (d *dockerImageDestination) putSignaturesToAPIExtension(ctx context.Context
923923
return nil
924924
}
925925

926-
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
927-
// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
928-
// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
929-
// original manifest list digest, if desired.
926+
// CommitWithOptions marks the process of storing the image as successful and asks for the image to be persisted.
930927
// WARNING: This does not have any transactional semantics:
931-
// - Uploaded data MAY be visible to others before Commit() is called
932-
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
933-
func (d *dockerImageDestination) Commit(context.Context, types.UnparsedImage) error {
928+
// - Uploaded data MAY be visible to others before CommitWithOptions() is called
929+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed)
930+
func (d *dockerImageDestination) CommitWithOptions(ctx context.Context, options private.CommitOptions) error {
934931
return nil
935932
}

docker/internal/tarfile/dest.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,25 @@ import (
2020
"github.com/sirupsen/logrus"
2121
)
2222

23-
// Destination is a partial implementation of private.ImageDestination for writing to an io.Writer.
23+
// Destination is a partial implementation of private.ImageDestination for writing to a Writer.
2424
type Destination struct {
2525
impl.Compat
2626
impl.PropertyMethodsInitialize
2727
stubs.NoPutBlobPartialInitialize
2828
stubs.NoSignaturesInitialize
2929

30-
archive *Writer
31-
repoTags []reference.NamedTagged
30+
archive *Writer
31+
commitWithOptions func(ctx context.Context, options private.CommitOptions) error
32+
repoTags []reference.NamedTagged
3233
// Other state.
3334
config []byte
3435
sysCtx *types.SystemContext
3536
}
3637

3738
// NewDestination returns a tarfile.Destination adding images to the specified Writer.
38-
func NewDestination(sys *types.SystemContext, archive *Writer, transportName string, ref reference.NamedTagged) *Destination {
39+
// commitWithOptions implements ImageDestination.CommitWithOptions.
40+
func NewDestination(sys *types.SystemContext, archive *Writer, transportName string, ref reference.NamedTagged,
41+
commitWithOptions func(ctx context.Context, options private.CommitOptions) error) *Destination {
3942
repoTags := []reference.NamedTagged{}
4043
if ref != nil {
4144
repoTags = append(repoTags, ref)
@@ -57,9 +60,10 @@ func NewDestination(sys *types.SystemContext, archive *Writer, transportName str
5760
NoPutBlobPartialInitialize: stubs.NoPutBlobPartialRaw(transportName),
5861
NoSignaturesInitialize: stubs.NoSignatures("Storing signatures for docker tar files is not supported"),
5962

60-
archive: archive,
61-
repoTags: repoTags,
62-
sysCtx: sys,
63+
archive: archive,
64+
commitWithOptions: commitWithOptions,
65+
repoTags: repoTags,
66+
sysCtx: sys,
6367
}
6468
dest.Compat = impl.AddCompat(dest)
6569
return dest
@@ -179,3 +183,13 @@ func (d *Destination) PutManifest(ctx context.Context, m []byte, instanceDigest
179183

180184
return d.archive.ensureManifestItemLocked(man.LayersDescriptors, man.ConfigDescriptor.Digest, d.repoTags)
181185
}
186+
187+
// CommitWithOptions marks the process of storing the image as successful and asks for the image to be persisted.
188+
// WARNING: This does not have any transactional semantics:
189+
// - Uploaded data MAY be visible to others before CommitWithOptions() is called
190+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed)
191+
func (d *Destination) CommitWithOptions(ctx context.Context, options private.CommitOptions) error {
192+
// This indirection exists because impl.Compat expects all ImageDestinationInternalOnly methods
193+
// to be implemented in one place.
194+
return d.commitWithOptions(ctx, options)
195+
}

docker/internal/tarfile/src_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestSourcePrepareLayerData(t *testing.T) {
2828
ctx := context.Background()
2929

3030
writer := NewWriter(&tarfileBuffer)
31-
dest := NewDestination(nil, writer, "transport name", nil)
31+
dest := NewDestination(nil, writer, "transport name", nil, nil)
3232
// No layers
3333
configInfo, err := dest.PutBlob(ctx, strings.NewReader(c.config),
3434
types.BlobInfo{Size: -1}, cache, true)

docker/tarfile/dest.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
internal "github.com/containers/image/v5/docker/internal/tarfile"
88
"github.com/containers/image/v5/docker/reference"
9+
"github.com/containers/image/v5/internal/private"
910
"github.com/containers/image/v5/types"
1011
"github.com/opencontainers/go-digest"
1112
)
@@ -25,10 +26,11 @@ func NewDestination(dest io.Writer, ref reference.NamedTagged) *Destination {
2526
// NewDestinationWithContext returns a tarfile.Destination for the specified io.Writer.
2627
func NewDestinationWithContext(sys *types.SystemContext, dest io.Writer, ref reference.NamedTagged) *Destination {
2728
archive := internal.NewWriter(dest)
28-
return &Destination{
29-
internal: internal.NewDestination(sys, archive, "[An external docker/tarfile caller]", ref),
30-
archive: archive,
29+
d := &Destination{
30+
archive: archive,
3131
}
32+
d.internal = internal.NewDestination(sys, archive, "[An external docker/tarfile caller]", ref, d.commitWithOptions)
33+
return d
3234
}
3335

3436
// AddRepoTags adds the specified tags to the destination's repoTags.
@@ -117,3 +119,11 @@ func (d *Destination) PutSignatures(ctx context.Context, signatures [][]byte, in
117119
func (d *Destination) Commit(ctx context.Context) error {
118120
return d.archive.Close()
119121
}
122+
123+
// commitWithOptions marks the process of storing the image as successful and asks for the image to be persisted.
124+
// WARNING: This does not have any transactional semantics:
125+
// - Uploaded data MAY be visible to others before CommitWithOptions() is called
126+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed)
127+
func (d *Destination) commitWithOptions(ctx context.Context, options private.CommitOptions) error {
128+
return d.Commit(ctx)
129+
}

internal/imagedestination/impl/compat.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,16 @@ func (c *Compat) PutSignatures(ctx context.Context, signatures [][]byte, instanc
9999
}
100100
return c.dest.PutSignaturesWithFormat(ctx, withFormat, instanceDigest)
101101
}
102+
103+
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
104+
// unparsedToplevel contains data about the top-level manifest of the source (which may be a single-arch image or a manifest list
105+
// if PutManifest was only called for the single-arch image with instanceDigest == nil), primarily to allow lookups by the
106+
// original manifest list digest, if desired.
107+
// WARNING: This does not have any transactional semantics:
108+
// - Uploaded data MAY be visible to others before Commit() is called
109+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
110+
func (c *Compat) Commit(ctx context.Context, unparsedToplevel types.UnparsedImage) error {
111+
return c.dest.CommitWithOptions(ctx, private.CommitOptions{
112+
UnparsedToplevel: unparsedToplevel,
113+
})
114+
}

internal/imagedestination/wrapper.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,11 @@ func (w *wrapped) PutSignaturesWithFormat(ctx context.Context, signatures []sign
9797
}
9898
return w.PutSignatures(ctx, simpleSigs, instanceDigest)
9999
}
100+
101+
// CommitWithOptions marks the process of storing the image as successful and asks for the image to be persisted.
102+
// WARNING: This does not have any transactional semantics:
103+
// - Uploaded data MAY be visible to others before CommitWithOptions() is called
104+
// - Uploaded data MAY be removed or MAY remain around if Close() is called without CommitWithOptions() (i.e. rollback is allowed but not guaranteed)
105+
func (w *wrapped) CommitWithOptions(ctx context.Context, options private.CommitOptions) error {
106+
return w.Commit(ctx, options.UnparsedToplevel)
107+
}

0 commit comments

Comments
 (0)