From df82159f4d272c57b92e9470c706776560ffde72 Mon Sep 17 00:00:00 2001 From: Kenfe-Mickael Laventure Date: Tue, 19 Sep 2017 20:47:00 -0700 Subject: [PATCH] client: Allow setting image labels on Pull() and Import() Signed-off-by: Kenfe-Mickael Laventure --- client.go | 35 +++++++++++++++++++++++++++++++++-- client_opts.go | 40 +++++++++++++++++++++++++++++++++------- cmd/ctr/fetch.go | 11 ++++++++--- cmd/ctr/import.go | 3 +++ cmd/ctr/pull.go | 2 +- cmd/ctr/utils.go | 5 +++++ import.go | 1 + 7 files changed, 84 insertions(+), 13 deletions(-) diff --git a/client.go b/client.go index 8dedc40d4..c18437372 100644 --- a/client.go +++ b/client.go @@ -178,6 +178,9 @@ type RemoteContext struct { // Snapshotter used for unpacking Snapshotter string + // Labels to be applied to the created image + Labels map[string]string + // BaseHandlers are a set of handlers which get are called on dispatch. // These handlers always get called before any operation specific // handlers. @@ -199,7 +202,7 @@ func defaultRemoteContext() *RemoteContext { } // Pull downloads the provided content into containerd's content store -func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Image, error) { +func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image, error) { pullCtx := defaultRemoteContext() for _, o := range opts { if err := o(c, pullCtx); err != nil { @@ -244,6 +247,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Imag imgrec := images.Image{ Name: name, Target: desc, + Labels: pullCtx.Labels, } is := c.ImageService() @@ -275,7 +279,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Imag } // Push uploads the provided content to a remote resource -func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpts) error { +func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpt) error { pushCtx := defaultRemoteContext() for _, o := range opts { if err := o(c, pushCtx); err != nil { @@ -485,11 +489,38 @@ const ( type importOpts struct { format imageFormat refObject string + labels map[string]string } // ImportOpt allows the caller to specify import specific options type ImportOpt func(c *importOpts) error +// WithImportLabel sets a label to be associated with an imported image +func WithImportLabel(key, value string) ImportOpt { + return func(opts *importOpts) error { + if opts.labels == nil { + opts.labels = make(map[string]string) + } + + opts.labels[key] = value + return nil + } +} + +// WithImportLabels associates a set of labels to an imported image +func WithImportLabels(labels map[string]string) ImportOpt { + return func(opts *importOpts) error { + if opts.labels == nil { + opts.labels = make(map[string]string) + } + + for k, v := range labels { + opts.labels[k] = v + } + return nil + } +} + // WithOCIImportFormat sets the import format for an OCI image format func WithOCIImportFormat() ImportOpt { return func(c *importOpts) error { diff --git a/client_opts.go b/client_opts.go index 83d5288c4..c1e93bae9 100644 --- a/client_opts.go +++ b/client_opts.go @@ -33,25 +33,51 @@ func WithDialOpts(opts []grpc.DialOption) ClientOpt { } } -// RemoteOpts allows the caller to set distribution options for a remote -type RemoteOpts func(*Client, *RemoteContext) error +// RemoteOpt allows the caller to set distribution options for a remote +type RemoteOpt func(*Client, *RemoteContext) error // WithPullUnpack is used to unpack an image after pull. This // uses the snapshotter, content store, and diff service // configured for the client. -func WithPullUnpack(client *Client, c *RemoteContext) error { +func WithPullUnpack(_ *Client, c *RemoteContext) error { c.Unpack = true return nil } // WithPullSnapshotter specifies snapshotter name used for unpacking -func WithPullSnapshotter(snapshotterName string) RemoteOpts { - return func(client *Client, c *RemoteContext) error { +func WithPullSnapshotter(snapshotterName string) RemoteOpt { + return func(_ *Client, c *RemoteContext) error { c.Snapshotter = snapshotterName return nil } } +// WithPullLabel sets a label to be associated with a pulled reference +func WithPullLabel(key, value string) RemoteOpt { + return func(_ *Client, rc *RemoteContext) error { + if rc.Labels == nil { + rc.Labels = make(map[string]string) + } + + rc.Labels[key] = value + return nil + } +} + +// WithPullLabels associates a set of labels to a pulled reference +func WithPullLabels(labels map[string]string) RemoteOpt { + return func(_ *Client, rc *RemoteContext) error { + if rc.Labels == nil { + rc.Labels = make(map[string]string) + } + + for k, v := range labels { + rc.Labels[k] = v + } + return nil + } +} + // WithSchema1Conversion is used to convert Docker registry schema 1 // manifests to oci manifests on pull. Without this option schema 1 // manifests will return a not supported error. @@ -61,7 +87,7 @@ func WithSchema1Conversion(client *Client, c *RemoteContext) error { } // WithResolver specifies the resolver to use. -func WithResolver(resolver remotes.Resolver) RemoteOpts { +func WithResolver(resolver remotes.Resolver) RemoteOpt { return func(client *Client, c *RemoteContext) error { c.Resolver = resolver return nil @@ -69,7 +95,7 @@ func WithResolver(resolver remotes.Resolver) RemoteOpts { } // WithImageHandler adds a base handler to be called on dispatch. -func WithImageHandler(h images.Handler) RemoteOpts { +func WithImageHandler(h images.Handler) RemoteOpt { return func(client *Client, c *RemoteContext) error { c.BaseHandlers = append(c.BaseHandlers, h) return nil diff --git a/cmd/ctr/fetch.go b/cmd/ctr/fetch.go index 36e90e0ad..65fb8587b 100644 --- a/cmd/ctr/fetch.go +++ b/cmd/ctr/fetch.go @@ -39,7 +39,7 @@ not use this implementation as a guide. The end goal should be having metadata, content and snapshots ready for a direct use via the 'ctr run'. Most of this is experimental and there are few leaps to make this work.`, - Flags: registryFlags, + Flags: append(registryFlags, labelFlag), Action: func(clicontext *cli.Context) error { var ( ref = clicontext.Args().First() @@ -84,8 +84,13 @@ func fetch(ctx context.Context, ref string, clicontext *cli.Context) (containerd }) log.G(pctx).WithField("image", ref).Debug("fetching") - - img, err := client.Pull(pctx, ref, containerd.WithResolver(resolver), containerd.WithImageHandler(h), containerd.WithSchema1Conversion) + labels := labelArgs(clicontext.StringSlice("label")) + img, err := client.Pull(pctx, ref, + containerd.WithPullLabels(labels), + containerd.WithResolver(resolver), + containerd.WithImageHandler(h), + containerd.WithSchema1Conversion, + ) stopProgress() if err != nil { return nil, err diff --git a/cmd/ctr/import.go b/cmd/ctr/import.go index ead33f33e..0cc6b0b60 100644 --- a/cmd/ctr/import.go +++ b/cmd/ctr/import.go @@ -21,12 +21,14 @@ var imagesImportCommand = cli.Command{ Value: "", Usage: "reference object e.g. tag@digest (default: use the object specified in ref)", }, + labelFlag, }, Action: func(clicontext *cli.Context) error { var ( ref = clicontext.Args().First() in = clicontext.Args().Get(1) refObject = clicontext.String("ref-object") + labels = labelArgs(clicontext.StringSlice("label")) ) ctx, cancel := appContext(clicontext) @@ -50,6 +52,7 @@ var imagesImportCommand = cli.Command{ ref, r, containerd.WithRefObject(refObject), + containerd.WithImportLabels(labels), ) if err != nil { return err diff --git a/cmd/ctr/pull.go b/cmd/ctr/pull.go index 4f9239d8f..41050db66 100644 --- a/cmd/ctr/pull.go +++ b/cmd/ctr/pull.go @@ -20,7 +20,7 @@ command. As part of this process, we do the following: 2. Prepare the snapshot filesystem with the pulled resources. 3. Register metadata for the image. `, - Flags: append(registryFlags, snapshotterFlags...), + Flags: append(registryFlags, append(snapshotterFlags, labelFlag)...), Action: func(clicontext *cli.Context) error { var ( ref = clicontext.Args().First() diff --git a/cmd/ctr/utils.go b/cmd/ctr/utils.go index 143756481..e84b19cb9 100644 --- a/cmd/ctr/utils.go +++ b/cmd/ctr/utils.go @@ -57,6 +57,11 @@ var ( }, } + labelFlag = cli.StringSliceFlag{ + Name: "label", + Usage: "labels to attach to the pulled image", + } + registryFlags = []cli.Flag{ cli.BoolFlag{ Name: "skip-verify,k", diff --git a/import.go b/import.go index a8fe63ffe..9f8f9af7d 100644 --- a/import.go +++ b/import.go @@ -68,6 +68,7 @@ func (c *Client) importFromOCITar(ctx context.Context, ref string, reader io.Rea imgrec := images.Image{ Name: ref, Target: *desc, + Labels: iopts.labels, } is := c.ImageService() if updated, err := is.Update(ctx, imgrec, "target"); err != nil {