-
Notifications
You must be signed in to change notification settings - Fork 950
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: cli support add kill command
Signed-off-by: Lang Chi <21860405@zju.edu.cn>
- Loading branch information
Showing
10 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"github.com/spf13/cobra" | ||
"strings" | ||
) | ||
|
||
// killDescription is used to describe kill command in detail and auto generate command doc. | ||
var killDescription = "Kill one or more running container objects in Pouchd. " + | ||
"You can kill a container using the container’s ID, ID-prefix, or name. " + | ||
"This is useful when you wish to kill a container which is running." | ||
|
||
// KillCommand use to implement 'kill' command, it kill one or more containers. | ||
type KillCommand struct { | ||
baseCommand | ||
signal string | ||
} | ||
|
||
// Init initialize kill command. | ||
func (s *KillCommand) Init(c *Cli) { | ||
s.cli = c | ||
s.cmd = &cobra.Command{ | ||
Use: "kill [OPTIONS] CONTAINER [CONTAINER...]", | ||
Short: "kill one or more running containers", | ||
Long: killDescription, | ||
Args: cobra.MinimumNArgs(1), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return s.runKill(args) | ||
}, | ||
Example: killExample(), | ||
} | ||
s.addFlags() | ||
} | ||
|
||
// addFlags adds flags for specific command. | ||
func (s *KillCommand) addFlags() { | ||
flagSet := s.cmd.Flags() | ||
flagSet.StringVarP(&s.signal, "signal", "s", "KILL", "Signal to send to the container") | ||
|
||
} | ||
|
||
// runKill is the entry of kill command. | ||
func (s *KillCommand) runKill(args []string) error { | ||
ctx := context.Background() | ||
apiClient := s.cli.Client() | ||
|
||
var errs []string | ||
for _, name := range args { | ||
if err := apiClient.ContainerKill(ctx, name, s.signal); err != nil { | ||
errs = append(errs, err.Error()) | ||
continue | ||
} | ||
fmt.Printf("%s\n", name) | ||
} | ||
|
||
if len(errs) > 0 { | ||
return errors.New(strings.Join(errs, "\n")) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// killExample shows examples in kill command, and is used in auto-generated cli docs. | ||
func killExample() string { | ||
return `$ pouch ps -a | ||
Name ID Status Created Image Runtime | ||
foo2 5a0ede Up 2 seconds 3 second ago registry.hub.docker.com/library/busybox:latest runc | ||
foo1 e05637 Up 6 seconds 7 seconds ago registry.hub.docker.com/library/busybox:latest runc | ||
$ pouch kill foo1 | ||
foo1 | ||
$ pouch ps | ||
Name ID Status Created Image Runtime | ||
foo2 5a0ede Up 11 seconds 12 seconds ago registry.hub.docker.com/library/busybox:latest runc | ||
` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package client | ||
|
||
import ( | ||
"context" | ||
"net/url" | ||
) | ||
|
||
func (client *APIClient) ContainerKill(ctx context.Context, name, signal string) error { | ||
q := url.Values{} | ||
q.Add("signal", signal) | ||
|
||
resp, err := client.post(ctx, "/containers/"+name+"/kill", q, nil, nil) | ||
ensureCloseReader(resp) | ||
|
||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package mgr | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"github.com/sirupsen/logrus" | ||
"strings" | ||
"syscall" | ||
) | ||
|
||
type errNoSuchProcess struct { | ||
pid int64 | ||
signal int | ||
} | ||
|
||
func isErrNoSuchProcess(err error) bool { | ||
_, ok := err.(errNoSuchProcess) | ||
return ok | ||
} | ||
|
||
func (e errNoSuchProcess) Error() string { | ||
return fmt.Sprintf("Cannot kill process (pid=%d) with signal %d: no such process.", e.pid, e.signal) | ||
} | ||
|
||
// Kill one or more running containers | ||
func (mgr *ContainerManager) Kill(ctx context.Context, name string, signal uint64) (err error) { | ||
c, err := mgr.container(name) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if signal == 0 || syscall.Signal(signal) == syscall.SIGKILL { | ||
return mgr.kill(ctx, c) | ||
} | ||
return mgr.killWithSignal(ctx, c, int(signal)) | ||
} | ||
|
||
func (mgr *ContainerManager) kill(ctx context.Context, c *Container) error { | ||
if !c.IsRunning() { | ||
return fmt.Errorf("Container %s is not running", c.ID) | ||
} | ||
|
||
if err := mgr.killDeadProcess(ctx, c, int(syscall.SIGKILL)); err != nil { | ||
if isErrNoSuchProcess(err) { | ||
return nil | ||
} | ||
|
||
if c.IsRunning() { | ||
return err | ||
} | ||
} | ||
|
||
if pid := c.State.Pid; pid != 0 { | ||
if err := syscall.Kill(int(pid), 9); err != nil { | ||
if err != syscall.ESRCH { | ||
return err | ||
} | ||
e := errNoSuchProcess{pid, 9} | ||
logrus.Debug(e) | ||
return nil | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (mgr *ContainerManager) killDeadProcess(ctx context.Context, c *Container, signal int) error { | ||
err := mgr.killWithSignal(ctx, c, signal) | ||
if err == syscall.ESRCH { | ||
e := errNoSuchProcess{c.State.Pid, signal} | ||
logrus.Debug(e) | ||
return e | ||
} | ||
return err | ||
} | ||
|
||
func (mgr *ContainerManager) killWithSignal(ctx context.Context, c *Container, signal int) error { | ||
logrus.Debugf("Sending %d to %s", signal, c.ID) | ||
c.Lock() | ||
defer c.Unlock() | ||
|
||
if c.State.Paused { | ||
return fmt.Errorf("Container %s is paused. Unpause the container before stopping", c.ID) | ||
} | ||
|
||
if !c.State.Running { | ||
return fmt.Errorf("Container %s is not running", c.ID) | ||
} | ||
|
||
msg, err := mgr.Client.DestroyContainer(ctx, c.ID, 10) | ||
if err != nil { | ||
err = fmt.Errorf("Cannot kill container %s: %s", c.ID, err) | ||
if strings.Contains(err.Error(), "container not found") || | ||
strings.Contains(err.Error(), "no such process") { | ||
logrus.Warnf("container kill failed because of 'container not found' or 'no such process': %s", err.Error()) | ||
} else { | ||
return err | ||
} | ||
} | ||
|
||
attributes := map[string]string{ | ||
"signal": fmt.Sprintf("%d", signal), | ||
} | ||
mgr.LogContainerEventWithAttributes(ctx, c, "kill", attributes) | ||
|
||
return mgr.markStoppedAndRelease(c, msg) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.