github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/task_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  	"encoding/json"
    22  	"fmt"
    23  	"syscall"
    24  
    25  	"github.com/containerd/containerd/api/types"
    26  	"github.com/containerd/containerd/content"
    27  	"github.com/containerd/containerd/errdefs"
    28  	"github.com/containerd/containerd/images"
    29  	"github.com/containerd/containerd/mount"
    30  	"github.com/containerd/containerd/runtime/linux/runctypes"
    31  	"github.com/containerd/containerd/runtime/v2/runc/options"
    32  	imagespec "github.com/opencontainers/image-spec/specs-go/v1"
    33  	"github.com/opencontainers/runtime-spec/specs-go"
    34  	"github.com/pkg/errors"
    35  )
    36  
    37  // NewTaskOpts allows the caller to set options on a new task
    38  type NewTaskOpts func(context.Context, *Client, *TaskInfo) error
    39  
    40  // WithRootFS allows a task to be created without a snapshot being allocated to its container
    41  func WithRootFS(mounts []mount.Mount) NewTaskOpts {
    42  	return func(ctx context.Context, c *Client, ti *TaskInfo) error {
    43  		ti.RootFS = mounts
    44  		return nil
    45  	}
    46  }
    47  
    48  // WithTaskCheckpoint allows a task to be created with live runtime and memory data from a
    49  // previous checkpoint. Additional software such as CRIU may be required to
    50  // restore a task from a checkpoint
    51  func WithTaskCheckpoint(im Image) NewTaskOpts {
    52  	return func(ctx context.Context, c *Client, info *TaskInfo) error {
    53  		desc := im.Target()
    54  		id := desc.Digest
    55  		index, err := decodeIndex(ctx, c.ContentStore(), desc)
    56  		if err != nil {
    57  			return err
    58  		}
    59  		for _, m := range index.Manifests {
    60  			if m.MediaType == images.MediaTypeContainerd1Checkpoint {
    61  				info.Checkpoint = &types.Descriptor{
    62  					MediaType:   m.MediaType,
    63  					Size_:       m.Size,
    64  					Digest:      m.Digest,
    65  					Annotations: m.Annotations,
    66  				}
    67  				return nil
    68  			}
    69  		}
    70  		return fmt.Errorf("checkpoint not found in index %s", id)
    71  	}
    72  }
    73  
    74  func decodeIndex(ctx context.Context, store content.Provider, desc imagespec.Descriptor) (*imagespec.Index, error) {
    75  	var index imagespec.Index
    76  	p, err := content.ReadBlob(ctx, store, desc)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	if err := json.Unmarshal(p, &index); err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	return &index, nil
    85  }
    86  
    87  // WithCheckpointName sets the image name for the checkpoint
    88  func WithCheckpointName(name string) CheckpointTaskOpts {
    89  	return func(r *CheckpointTaskInfo) error {
    90  		r.Name = name
    91  		return nil
    92  	}
    93  }
    94  
    95  // WithCheckpointImagePath sets image path for checkpoint option
    96  func WithCheckpointImagePath(path string) CheckpointTaskOpts {
    97  	return func(r *CheckpointTaskInfo) error {
    98  		if CheckRuntime(r.Runtime(), "io.containerd.runc") {
    99  			if r.Options == nil {
   100  				r.Options = &options.CheckpointOptions{}
   101  			}
   102  			opts, ok := r.Options.(*options.CheckpointOptions)
   103  			if !ok {
   104  				return errors.New("invalid v2 shim checkpoint options format")
   105  			}
   106  			opts.ImagePath = path
   107  		} else {
   108  			if r.Options == nil {
   109  				r.Options = &runctypes.CheckpointOptions{}
   110  			}
   111  			opts, ok := r.Options.(*runctypes.CheckpointOptions)
   112  			if !ok {
   113  				return errors.New("invalid v1 shim checkpoint options format")
   114  			}
   115  			opts.ImagePath = path
   116  		}
   117  		return nil
   118  	}
   119  }
   120  
   121  // WithRestoreImagePath sets image path for create option
   122  func WithRestoreImagePath(path string) NewTaskOpts {
   123  	return func(ctx context.Context, c *Client, ti *TaskInfo) error {
   124  		if CheckRuntime(ti.Runtime(), "io.containerd.runc") {
   125  			if ti.Options == nil {
   126  				ti.Options = &options.Options{}
   127  			}
   128  			opts, ok := ti.Options.(*options.Options)
   129  			if !ok {
   130  				return errors.New("invalid v2 shim create options format")
   131  			}
   132  			opts.CriuImagePath = path
   133  		} else {
   134  			if ti.Options == nil {
   135  				ti.Options = &runctypes.CreateOptions{}
   136  			}
   137  			opts, ok := ti.Options.(*runctypes.CreateOptions)
   138  			if !ok {
   139  				return errors.New("invalid v1 shim create options format")
   140  			}
   141  			opts.CriuImagePath = path
   142  		}
   143  		return nil
   144  	}
   145  }
   146  
   147  // ProcessDeleteOpts allows the caller to set options for the deletion of a task
   148  type ProcessDeleteOpts func(context.Context, Process) error
   149  
   150  // WithProcessKill will forcefully kill and delete a process
   151  func WithProcessKill(ctx context.Context, p Process) error {
   152  	ctx, cancel := context.WithCancel(ctx)
   153  	defer cancel()
   154  	// ignore errors to wait and kill as we are forcefully killing
   155  	// the process and don't care about the exit status
   156  	s, err := p.Wait(ctx)
   157  	if err != nil {
   158  		return err
   159  	}
   160  	if err := p.Kill(ctx, syscall.SIGKILL, WithKillAll); err != nil {
   161  		if errdefs.IsFailedPrecondition(err) || errdefs.IsNotFound(err) {
   162  			return nil
   163  		}
   164  		return err
   165  	}
   166  	// wait for the process to fully stop before letting the rest of the deletion complete
   167  	<-s
   168  	return nil
   169  }
   170  
   171  // KillInfo contains information on how to process a Kill action
   172  type KillInfo struct {
   173  	// All kills all processes inside the task
   174  	// only valid on tasks, ignored on processes
   175  	All bool
   176  	// ExecID is the ID of a process to kill
   177  	ExecID string
   178  }
   179  
   180  // KillOpts allows options to be set for the killing of a process
   181  type KillOpts func(context.Context, *KillInfo) error
   182  
   183  // WithKillAll kills all processes for a task
   184  func WithKillAll(ctx context.Context, i *KillInfo) error {
   185  	i.All = true
   186  	return nil
   187  }
   188  
   189  // WithKillExecID specifies the process ID
   190  func WithKillExecID(execID string) KillOpts {
   191  	return func(ctx context.Context, i *KillInfo) error {
   192  		i.ExecID = execID
   193  		return nil
   194  	}
   195  }
   196  
   197  // WithResources sets the provided resources for task updates. Resources must be
   198  // either a *specs.LinuxResources or a *specs.WindowsResources
   199  func WithResources(resources interface{}) UpdateTaskOpts {
   200  	return func(ctx context.Context, client *Client, r *UpdateTaskInfo) error {
   201  		switch resources.(type) {
   202  		case *specs.LinuxResources:
   203  		case *specs.WindowsResources:
   204  		default:
   205  			return errors.New("WithResources requires a *specs.LinuxResources or *specs.WindowsResources")
   206  		}
   207  
   208  		r.Resources = resources
   209  		return nil
   210  	}
   211  }