mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-28 20:15:51 +00:00
When force is true, ignore any guest related errors. This can be used to stop a sandbox when hypervisor process is dead. Signed-off-by: Peng Tao <bergwolf@hyper.sh>
194 lines
4.9 KiB
Go
194 lines
4.9 KiB
Go
// Copyright (c) 2014,2015,2016 Docker, Inc.
|
|
// Copyright (c) 2017 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"syscall"
|
|
|
|
"github.com/kata-containers/runtime/pkg/katautils"
|
|
vc "github.com/kata-containers/runtime/virtcontainers"
|
|
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
|
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var killCLICommand = cli.Command{
|
|
Name: "kill",
|
|
Usage: "Kill sends signals to the container's init process",
|
|
ArgsUsage: `<container-id> [signal]
|
|
|
|
<container-id> is the name for the instance of the container
|
|
[signal] is the signal to be sent to the init process (default: SIGTERM)
|
|
|
|
EXAMPLE:
|
|
If the container id is "ubuntu01" the following will send a "KILL" signal
|
|
to the init process of the "ubuntu01" container:
|
|
|
|
# ` + name + ` kill ubuntu01 KILL`,
|
|
Flags: []cli.Flag{
|
|
cli.BoolFlag{
|
|
Name: "all, a",
|
|
Usage: "send the specified signal to all processes inside the container",
|
|
},
|
|
},
|
|
Action: func(context *cli.Context) error {
|
|
ctx, err := cliContextToContext(context)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
args := context.Args()
|
|
if !args.Present() {
|
|
return fmt.Errorf("Missing container ID")
|
|
}
|
|
|
|
// If signal is provided, it has to be the second argument.
|
|
signal := args.Get(1)
|
|
if signal == "" {
|
|
signal = "SIGTERM"
|
|
}
|
|
|
|
return kill(ctx, args.First(), signal, context.Bool("all"))
|
|
},
|
|
}
|
|
|
|
var signalList = map[string]syscall.Signal{
|
|
"SIGABRT": syscall.SIGABRT,
|
|
"SIGALRM": syscall.SIGALRM,
|
|
"SIGBUS": syscall.SIGBUS,
|
|
"SIGCHLD": syscall.SIGCHLD,
|
|
"SIGCLD": syscall.SIGCLD,
|
|
"SIGCONT": syscall.SIGCONT,
|
|
"SIGFPE": syscall.SIGFPE,
|
|
"SIGHUP": syscall.SIGHUP,
|
|
"SIGILL": syscall.SIGILL,
|
|
"SIGINT": syscall.SIGINT,
|
|
"SIGIO": syscall.SIGIO,
|
|
"SIGIOT": syscall.SIGIOT,
|
|
"SIGKILL": syscall.SIGKILL,
|
|
"SIGPIPE": syscall.SIGPIPE,
|
|
"SIGPOLL": syscall.SIGPOLL,
|
|
"SIGPROF": syscall.SIGPROF,
|
|
"SIGPWR": syscall.SIGPWR,
|
|
"SIGQUIT": syscall.SIGQUIT,
|
|
"SIGSEGV": syscall.SIGSEGV,
|
|
"SIGSTKFLT": syscall.SIGSTKFLT,
|
|
"SIGSTOP": syscall.SIGSTOP,
|
|
"SIGSYS": syscall.SIGSYS,
|
|
"SIGTERM": syscall.SIGTERM,
|
|
"SIGTRAP": syscall.SIGTRAP,
|
|
"SIGTSTP": syscall.SIGTSTP,
|
|
"SIGTTIN": syscall.SIGTTIN,
|
|
"SIGTTOU": syscall.SIGTTOU,
|
|
"SIGUNUSED": syscall.SIGUNUSED,
|
|
"SIGURG": syscall.SIGURG,
|
|
"SIGUSR1": syscall.SIGUSR1,
|
|
"SIGUSR2": syscall.SIGUSR2,
|
|
"SIGVTALRM": syscall.SIGVTALRM,
|
|
"SIGWINCH": syscall.SIGWINCH,
|
|
"SIGXCPU": syscall.SIGXCPU,
|
|
"SIGXFSZ": syscall.SIGXFSZ,
|
|
}
|
|
|
|
func kill(ctx context.Context, containerID, signal string, all bool) error {
|
|
span, _ := katautils.Trace(ctx, "kill")
|
|
defer span.Finish()
|
|
|
|
kataLog = kataLog.WithField("container", containerID)
|
|
setExternalLoggers(ctx, kataLog)
|
|
span.SetTag("container", containerID)
|
|
|
|
// Checks the MUST and MUST NOT from OCI runtime specification
|
|
status, sandboxID, err := getExistingContainerInfo(ctx, containerID)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
containerID = status.ID
|
|
|
|
kataLog = kataLog.WithFields(logrus.Fields{
|
|
"container": containerID,
|
|
"sandbox": sandboxID,
|
|
})
|
|
|
|
span.SetTag("container", containerID)
|
|
span.SetTag("sandbox", sandboxID)
|
|
|
|
setExternalLoggers(ctx, kataLog)
|
|
|
|
signum, err := processSignal(signal)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
kataLog.WithField("signal", signal).WithField("container state", status.State.State).Info("kill")
|
|
|
|
// container MUST be created, running or paused
|
|
if status.State.State == types.StateReady || status.State.State == types.StateRunning || status.State.State == types.StatePaused {
|
|
if err := vci.KillContainer(ctx, sandboxID, containerID, signum, all); err != nil {
|
|
return err
|
|
}
|
|
} else if !all {
|
|
return fmt.Errorf("container not running")
|
|
}
|
|
|
|
if signum != syscall.SIGKILL && signum != syscall.SIGTERM {
|
|
return nil
|
|
}
|
|
|
|
containerType, err := oci.GetContainerType(status.Annotations)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch containerType {
|
|
case vc.PodSandbox:
|
|
_, err = vci.StopSandbox(ctx, sandboxID, signum == syscall.SIGKILL)
|
|
case vc.PodContainer:
|
|
_, err = vci.StopContainer(ctx, sandboxID, containerID)
|
|
default:
|
|
return fmt.Errorf("Invalid container type found")
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func processSignal(signal string) (syscall.Signal, error) {
|
|
signum, signalOk := signalList[signal]
|
|
if signalOk {
|
|
return signum, nil
|
|
}
|
|
|
|
// Support for short name signals (INT)
|
|
signum, signalOk = signalList["SIG"+signal]
|
|
if signalOk {
|
|
return signum, nil
|
|
}
|
|
|
|
// Support for numeric signals
|
|
s, err := strconv.Atoi(signal)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("Failed to convert signal %s to int", signal)
|
|
}
|
|
|
|
signum = syscall.Signal(s)
|
|
// Check whether signal is valid or not
|
|
for _, sig := range signalList {
|
|
if sig == signum {
|
|
// signal is a valid signal
|
|
return signum, nil
|
|
}
|
|
}
|
|
|
|
return 0, fmt.Errorf("Signal %s is not supported", signal)
|
|
}
|