github.com/containerd/Containerd@v1.4.13/container_opts.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package containerd 18 19 import ( 20 "context" 21 22 "github.com/containerd/containerd/containers" 23 "github.com/containerd/containerd/errdefs" 24 "github.com/containerd/containerd/oci" 25 "github.com/containerd/containerd/snapshots" 26 "github.com/containerd/typeurl" 27 "github.com/gogo/protobuf/types" 28 "github.com/opencontainers/image-spec/identity" 29 "github.com/pkg/errors" 30 ) 31 32 // DeleteOpts allows the caller to set options for the deletion of a container 33 type DeleteOpts func(ctx context.Context, client *Client, c containers.Container) error 34 35 // NewContainerOpts allows the caller to set additional options when creating a container 36 type NewContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error 37 38 // UpdateContainerOpts allows the caller to set additional options when updating a container 39 type UpdateContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error 40 41 // InfoOpts controls how container metadata is fetched and returned 42 type InfoOpts func(*InfoConfig) 43 44 // InfoConfig specifies how container metadata is fetched 45 type InfoConfig struct { 46 // Refresh will to a fetch of the latest container metadata 47 Refresh bool 48 } 49 50 // WithRuntime allows a user to specify the runtime name and additional options that should 51 // be used to create tasks for the container 52 func WithRuntime(name string, options interface{}) NewContainerOpts { 53 return func(ctx context.Context, client *Client, c *containers.Container) error { 54 var ( 55 any *types.Any 56 err error 57 ) 58 if options != nil { 59 any, err = typeurl.MarshalAny(options) 60 if err != nil { 61 return err 62 } 63 } 64 c.Runtime = containers.RuntimeInfo{ 65 Name: name, 66 Options: any, 67 } 68 return nil 69 } 70 } 71 72 // WithImage sets the provided image as the base for the container 73 func WithImage(i Image) NewContainerOpts { 74 return func(ctx context.Context, client *Client, c *containers.Container) error { 75 c.Image = i.Name() 76 return nil 77 } 78 } 79 80 // WithImageName allows setting the image name as the base for the container 81 func WithImageName(n string) NewContainerOpts { 82 return func(ctx context.Context, _ *Client, c *containers.Container) error { 83 c.Image = n 84 return nil 85 } 86 } 87 88 // WithContainerLabels adds the provided labels to the container 89 func WithContainerLabels(labels map[string]string) NewContainerOpts { 90 return func(_ context.Context, _ *Client, c *containers.Container) error { 91 c.Labels = labels 92 return nil 93 } 94 } 95 96 // WithImageStopSignal sets a well-known containerd label (StopSignalLabel) 97 // on the container for storing the stop signal specified in the OCI image 98 // config 99 func WithImageStopSignal(image Image, defaultSignal string) NewContainerOpts { 100 return func(ctx context.Context, _ *Client, c *containers.Container) error { 101 if c.Labels == nil { 102 c.Labels = make(map[string]string) 103 } 104 stopSignal, err := GetOCIStopSignal(ctx, image, defaultSignal) 105 if err != nil { 106 return err 107 } 108 c.Labels[StopSignalLabel] = stopSignal 109 return nil 110 } 111 } 112 113 // WithSnapshotter sets the provided snapshotter for use by the container 114 // 115 // This option must appear before other snapshotter options to have an effect. 116 func WithSnapshotter(name string) NewContainerOpts { 117 return func(ctx context.Context, client *Client, c *containers.Container) error { 118 c.Snapshotter = name 119 return nil 120 } 121 } 122 123 // WithSnapshot uses an existing root filesystem for the container 124 func WithSnapshot(id string) NewContainerOpts { 125 return func(ctx context.Context, client *Client, c *containers.Container) error { 126 // check that the snapshot exists, if not, fail on creation 127 var err error 128 c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) 129 if err != nil { 130 return err 131 } 132 s, err := client.getSnapshotter(ctx, c.Snapshotter) 133 if err != nil { 134 return err 135 } 136 if _, err := s.Mounts(ctx, id); err != nil { 137 return err 138 } 139 c.SnapshotKey = id 140 return nil 141 } 142 } 143 144 // WithNewSnapshot allocates a new snapshot to be used by the container as the 145 // root filesystem in read-write mode 146 func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts { 147 return func(ctx context.Context, client *Client, c *containers.Container) error { 148 diffIDs, err := i.RootFS(ctx) 149 if err != nil { 150 return err 151 } 152 153 parent := identity.ChainID(diffIDs).String() 154 c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) 155 if err != nil { 156 return err 157 } 158 s, err := client.getSnapshotter(ctx, c.Snapshotter) 159 if err != nil { 160 return err 161 } 162 if _, err := s.Prepare(ctx, id, parent, opts...); err != nil { 163 return err 164 } 165 c.SnapshotKey = id 166 c.Image = i.Name() 167 return nil 168 } 169 } 170 171 // WithSnapshotCleanup deletes the rootfs snapshot allocated for the container 172 func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Container) error { 173 if c.SnapshotKey != "" { 174 if c.Snapshotter == "" { 175 return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot") 176 } 177 s, err := client.getSnapshotter(ctx, c.Snapshotter) 178 if err != nil { 179 return err 180 } 181 if err := s.Remove(ctx, c.SnapshotKey); err != nil && !errdefs.IsNotFound(err) { 182 return err 183 } 184 } 185 return nil 186 } 187 188 // WithNewSnapshotView allocates a new snapshot to be used by the container as the 189 // root filesystem in read-only mode 190 func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainerOpts { 191 return func(ctx context.Context, client *Client, c *containers.Container) error { 192 diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) 193 if err != nil { 194 return err 195 } 196 197 parent := identity.ChainID(diffIDs).String() 198 c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) 199 if err != nil { 200 return err 201 } 202 s, err := client.getSnapshotter(ctx, c.Snapshotter) 203 if err != nil { 204 return err 205 } 206 if _, err := s.View(ctx, id, parent, opts...); err != nil { 207 return err 208 } 209 c.SnapshotKey = id 210 c.Image = i.Name() 211 return nil 212 } 213 } 214 215 // WithContainerExtension appends extension data to the container object. 216 // Use this to decorate the container object with additional data for the client 217 // integration. 218 // 219 // Make sure to register the type of `extension` in the typeurl package via 220 // `typeurl.Register` or container creation may fail. 221 func WithContainerExtension(name string, extension interface{}) NewContainerOpts { 222 return func(ctx context.Context, client *Client, c *containers.Container) error { 223 if name == "" { 224 return errors.Wrapf(errdefs.ErrInvalidArgument, "extension key must not be zero-length") 225 } 226 227 any, err := typeurl.MarshalAny(extension) 228 if err != nil { 229 if errors.Is(err, typeurl.ErrNotFound) { 230 return errors.Wrapf(err, "extension %q is not registered with the typeurl package, see `typeurl.Register`", name) 231 } 232 return errors.Wrap(err, "error marshalling extension") 233 } 234 235 if c.Extensions == nil { 236 c.Extensions = make(map[string]types.Any) 237 } 238 c.Extensions[name] = *any 239 return nil 240 } 241 } 242 243 // WithNewSpec generates a new spec for a new container 244 func WithNewSpec(opts ...oci.SpecOpts) NewContainerOpts { 245 return func(ctx context.Context, client *Client, c *containers.Container) error { 246 s, err := oci.GenerateSpec(ctx, client, c, opts...) 247 if err != nil { 248 return err 249 } 250 c.Spec, err = typeurl.MarshalAny(s) 251 return err 252 } 253 } 254 255 // WithSpec sets the provided spec on the container 256 func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts { 257 return func(ctx context.Context, client *Client, c *containers.Container) error { 258 if err := oci.ApplyOpts(ctx, client, c, s, opts...); err != nil { 259 return err 260 } 261 262 var err error 263 c.Spec, err = typeurl.MarshalAny(s) 264 return err 265 } 266 } 267 268 // WithoutRefreshedMetadata will use the current metadata attached to the container object 269 func WithoutRefreshedMetadata(i *InfoConfig) { 270 i.Refresh = false 271 }