From e49e9be06402883c5aedcce82f342156246ee6ce Mon Sep 17 00:00:00 2001 From: Laitron Date: Thu, 12 Jan 2023 23:49:09 +0800 Subject: [PATCH] [Refactor] Refactor the kill command flagging process. Signed-off-by: Laitron --- cmd/nerdctl/kill.go | 95 ++------------------------ pkg/api/types/container_types.go | 24 +++++++ pkg/cmd/container/kill.go | 112 +++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 88 deletions(-) create mode 100644 pkg/api/types/container_types.go create mode 100644 pkg/cmd/container/kill.go diff --git a/cmd/nerdctl/kill.go b/cmd/nerdctl/kill.go index f6593be2581..0e916dda0b5 100644 --- a/cmd/nerdctl/kill.go +++ b/cmd/nerdctl/kill.go @@ -17,20 +17,9 @@ package main import ( - "context" - "fmt" - "os" - "strings" - "syscall" - "github.com/containerd/containerd" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/nerdctl/pkg/clientutil" - "github.com/containerd/nerdctl/pkg/idutil/containerwalker" - - "github.com/moby/sys/signal" - "github.com/sirupsen/logrus" + "github.com/containerd/nerdctl/pkg/api/types" + "github.com/containerd/nerdctl/pkg/cmd/container" "github.com/spf13/cobra" ) @@ -57,87 +46,17 @@ func killAction(cmd *cobra.Command, args []string) error { if err != nil { return err } - if !strings.HasPrefix(killSignal, "SIG") { - killSignal = "SIG" + killSignal - } - - signal, err := signal.ParseSignal(killSignal) - if err != nil { - return err - } - client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) - if err != nil { - return err - } - defer cancel() - - walker := &containerwalker.ContainerWalker{ - Client: client, - OnFound: func(ctx context.Context, found containerwalker.Found) error { - if found.MatchCount > 1 { - return fmt.Errorf("multiple IDs found with provided prefix: %s", found.Req) - } - if err := killContainer(ctx, found.Container, signal); err != nil { - if errdefs.IsNotFound(err) { - fmt.Fprintf(cmd.ErrOrStderr(), "No such container: %s\n", found.Req) - os.Exit(1) - } - return err - } - _, err := fmt.Fprintf(cmd.OutOrStdout(), "%s\n", found.Container.ID()) - return err - }, - } - for _, req := range args { - n, err := walker.Walk(ctx, req) - if err != nil { - return err - } else if n == 0 { - return fmt.Errorf("no such container %s", req) - } - } - return nil -} - -func killContainer(ctx context.Context, container containerd.Container, signal syscall.Signal) error { - task, err := container.Task(ctx, cio.Load) - if err != nil { - return err - } - - status, err := task.Status(ctx) - if err != nil { - return err + options := types.KillCommandOptions{ + GOptions: globalOptions, + KillSignal: killSignal, } - - paused := false - - switch status.Status { - case containerd.Created, containerd.Stopped: - return fmt.Errorf("cannot kill container: %s: Container %s is not running", container.ID(), container.ID()) - case containerd.Paused, containerd.Pausing: - paused = true - default: - } - - if err := task.Kill(ctx, signal); err != nil { - return err - } - - // signal will be sent once resume is finished - if paused { - if err := task.Resume(ctx); err != nil { - logrus.Warnf("Cannot unpause container %s: %s", container.ID(), err) - } - } - return nil + return container.Kill(cmd.Context(), args, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) } -func killShellComplete(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { +func killShellComplete(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { // show non-stopped container names statusFilterFn := func(st containerd.ProcessStatus) bool { return st != containerd.Stopped && st != containerd.Created && st != containerd.Unknown } return shellCompleteContainerNames(cmd, statusFilterFn) - } diff --git a/pkg/api/types/container_types.go b/pkg/api/types/container_types.go new file mode 100644 index 00000000000..3ea334e9923 --- /dev/null +++ b/pkg/api/types/container_types.go @@ -0,0 +1,24 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package types + +type KillCommandOptions struct { + // GOptions is the global options + GOptions GlobalCommandOptions + // KillSignal is the signal to send to the container + KillSignal string +} diff --git a/pkg/cmd/container/kill.go b/pkg/cmd/container/kill.go new file mode 100644 index 00000000000..f43d8593b38 --- /dev/null +++ b/pkg/cmd/container/kill.go @@ -0,0 +1,112 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import ( + "context" + "fmt" + "io" + "os" + "strings" + "syscall" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/nerdctl/pkg/api/types" + "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/idutil/containerwalker" + "github.com/moby/sys/signal" + "github.com/sirupsen/logrus" +) + +func Kill(ctx context.Context, reqs []string, opt types.KillCommandOptions, stdout, stderr io.Writer) error { + if !strings.HasPrefix(opt.KillSignal, "SIG") { + opt.KillSignal = "SIG" + opt.KillSignal + } + + parsedSignal, err := signal.ParseSignal(opt.KillSignal) + if err != nil { + return err + } + client, ctx, cancel, err := clientutil.NewClient(ctx, opt.GOptions.Namespace, opt.GOptions.Address) + if err != nil { + return err + } + defer cancel() + + walker := &containerwalker.ContainerWalker{ + Client: client, + OnFound: func(ctx context.Context, found containerwalker.Found) error { + if found.MatchCount > 1 { + return fmt.Errorf("multiple IDs found with provided prefix: %s", found.Req) + } + if err := killContainer(ctx, found.Container, parsedSignal); err != nil { + if errdefs.IsNotFound(err) { + fmt.Fprintf(stderr, "No such container: %s\n", found.Req) + os.Exit(1) + } + return err + } + _, err := fmt.Fprintf(stdout, "%s\n", found.Container.ID()) + return err + }, + } + for _, req := range reqs { + n, err := walker.Walk(ctx, req) + if err != nil { + return err + } else if n == 0 { + return fmt.Errorf("no such container %s", req) + } + } + return nil +} + +func killContainer(ctx context.Context, container containerd.Container, signal syscall.Signal) error { + task, err := container.Task(ctx, cio.Load) + if err != nil { + return err + } + + status, err := task.Status(ctx) + if err != nil { + return err + } + + paused := false + + switch status.Status { + case containerd.Created, containerd.Stopped: + return fmt.Errorf("cannot kill container %s: container is not running", container.ID()) + case containerd.Paused, containerd.Pausing: + paused = true + default: + } + + if err := task.Kill(ctx, signal); err != nil { + return err + } + + // signal will be sent once resume is finished + if paused { + if err := task.Resume(ctx); err != nil { + logrus.Warnf("cannot unpause container %s: %s", container.ID(), err) + } + } + return nil +}