github.com/containerd/nerdctl@v1.7.7/pkg/cmd/container/kill.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 container 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "strings" 24 "syscall" 25 26 "github.com/containerd/containerd" 27 "github.com/containerd/containerd/cio" 28 "github.com/containerd/errdefs" 29 "github.com/containerd/log" 30 "github.com/containerd/nerdctl/pkg/api/types" 31 "github.com/containerd/nerdctl/pkg/containerutil" 32 "github.com/containerd/nerdctl/pkg/idutil/containerwalker" 33 "github.com/moby/sys/signal" 34 ) 35 36 // Kill kills a list of containers 37 func Kill(ctx context.Context, client *containerd.Client, reqs []string, options types.ContainerKillOptions) error { 38 if !strings.HasPrefix(options.KillSignal, "SIG") { 39 options.KillSignal = "SIG" + options.KillSignal 40 } 41 42 parsedSignal, err := signal.ParseSignal(options.KillSignal) 43 if err != nil { 44 return err 45 } 46 47 walker := &containerwalker.ContainerWalker{ 48 Client: client, 49 OnFound: func(ctx context.Context, found containerwalker.Found) error { 50 if found.MatchCount > 1 { 51 return fmt.Errorf("multiple IDs found with provided prefix: %s", found.Req) 52 } 53 if err := killContainer(ctx, found.Container, parsedSignal); err != nil { 54 if errdefs.IsNotFound(err) { 55 fmt.Fprintf(options.Stderr, "No such container: %s\n", found.Req) 56 os.Exit(1) 57 } 58 return err 59 } 60 _, err := fmt.Fprintln(options.Stdout, found.Container.ID()) 61 return err 62 }, 63 } 64 65 return walker.WalkAll(ctx, reqs, true) 66 } 67 68 func killContainer(ctx context.Context, container containerd.Container, signal syscall.Signal) (err error) { 69 defer func() { 70 if err != nil { 71 containerutil.UpdateErrorLabel(ctx, container, err) 72 } 73 }() 74 if err := containerutil.UpdateExplicitlyStoppedLabel(ctx, container, true); err != nil { 75 return err 76 } 77 task, err := container.Task(ctx, cio.Load) 78 if err != nil { 79 return err 80 } 81 82 status, err := task.Status(ctx) 83 if err != nil { 84 return err 85 } 86 87 paused := false 88 89 switch status.Status { 90 case containerd.Created, containerd.Stopped: 91 return fmt.Errorf("cannot kill container %s: container is not running", container.ID()) 92 case containerd.Paused, containerd.Pausing: 93 paused = true 94 default: 95 } 96 97 if err := task.Kill(ctx, signal); err != nil { 98 return err 99 } 100 101 // signal will be sent once resume is finished 102 if paused { 103 if err := task.Resume(ctx); err != nil { 104 log.G(ctx).Warnf("cannot unpause container %s: %s", container.ID(), err) 105 } 106 } 107 return nil 108 }