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 }