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  }