Merge pull request #1704 from jessvalarezo/ctr-move-tasks
ctr: move commands (tasks, run, pprof, shim)
This commit is contained in:
commit
aa3516487c
@ -20,10 +20,10 @@ var Command = cli.Command{
|
||||
Usage: "manage containers",
|
||||
Aliases: []string{"c"},
|
||||
Subcommands: []cli.Command{
|
||||
listCommand,
|
||||
deleteCommand,
|
||||
setLabelsCommand,
|
||||
infoCommand,
|
||||
listCommand,
|
||||
setLabelsCommand,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -27,16 +27,16 @@ var (
|
||||
Name: "content",
|
||||
Usage: "manage content",
|
||||
Subcommands: cli.Commands{
|
||||
listCommand,
|
||||
ingestCommand,
|
||||
activeIngestCommand,
|
||||
getCommand,
|
||||
editCommand,
|
||||
deleteCommand,
|
||||
setLabelsCommand,
|
||||
editCommand,
|
||||
fetchCommand,
|
||||
fetchObjectCommand,
|
||||
getCommand,
|
||||
ingestCommand,
|
||||
listCommand,
|
||||
pushObjectCommand,
|
||||
setLabelsCommand,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,9 @@ var Command = cli.Command{
|
||||
Usage: "manage namespaces",
|
||||
Subcommands: cli.Commands{
|
||||
createCommand,
|
||||
setLabelsCommand,
|
||||
listCommand,
|
||||
removeCommand,
|
||||
setLabelsCommand,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -17,7 +17,8 @@ type pprofDialer struct {
|
||||
addr string
|
||||
}
|
||||
|
||||
var pprofCommand = cli.Command{
|
||||
// Command is the cli command for providing golang pprof outputs for containerd
|
||||
var Command = cli.Command{
|
||||
Name: "pprof",
|
||||
Usage: "provide golang pprof outputs for containerd",
|
||||
Flags: []cli.Flag{
|
||||
@ -28,12 +29,12 @@ var pprofCommand = cli.Command{
|
||||
},
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
pprofBlockCommand,
|
||||
pprofGoroutinesCommand,
|
||||
pprofHeapCommand,
|
||||
pprofProfileCommand,
|
||||
pprofTraceCommand,
|
||||
pprofBlockCommand,
|
||||
pprofThreadcreateCommand,
|
||||
pprofTraceCommand,
|
||||
},
|
||||
}
|
||||
|
||||
@ -91,7 +92,7 @@ var pprofTraceCommand = cli.Command{
|
||||
Flags: []cli.Flag{
|
||||
cli.DurationFlag{
|
||||
Name: "seconds,s",
|
||||
Usage: "Trace time (seconds)",
|
||||
Usage: "trace time (seconds)",
|
||||
Value: time.Duration(5 * time.Second),
|
||||
},
|
||||
},
|
@ -1,6 +1,6 @@
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
package pprof
|
||||
|
||||
import "net"
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"net"
|
@ -1,13 +1,16 @@
|
||||
package main
|
||||
package run
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/tasks"
|
||||
"github.com/containerd/containerd/containers"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
@ -15,10 +18,6 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type resizer interface {
|
||||
Resize(ctx gocontext.Context, w, h uint32) error
|
||||
}
|
||||
|
||||
func withEnv(context *cli.Context) containerd.SpecOpts {
|
||||
return func(_ gocontext.Context, _ *containerd.Client, _ *containers.Container, s *specs.Spec) error {
|
||||
env := context.StringSlice("env")
|
||||
@ -42,10 +41,84 @@ func withMounts(context *cli.Context) containerd.SpecOpts {
|
||||
}
|
||||
}
|
||||
|
||||
var runCommand = cli.Command{
|
||||
// parseMountFlag parses a mount string in the form "type=foo,source=/path,destination=/target,options=rbind:rw"
|
||||
func parseMountFlag(m string) (specs.Mount, error) {
|
||||
mount := specs.Mount{}
|
||||
r := csv.NewReader(strings.NewReader(m))
|
||||
|
||||
fields, err := r.Read()
|
||||
if err != nil {
|
||||
return mount, err
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
v := strings.Split(field, "=")
|
||||
if len(v) != 2 {
|
||||
return mount, fmt.Errorf("invalid mount specification: expected key=val")
|
||||
}
|
||||
|
||||
key := v[0]
|
||||
val := v[1]
|
||||
switch key {
|
||||
case "type":
|
||||
mount.Type = val
|
||||
case "source", "src":
|
||||
mount.Source = val
|
||||
case "destination", "dst":
|
||||
mount.Destination = val
|
||||
case "options":
|
||||
mount.Options = strings.Split(val, ":")
|
||||
default:
|
||||
return mount, fmt.Errorf("mount option %q not supported", key)
|
||||
}
|
||||
}
|
||||
|
||||
return mount, nil
|
||||
}
|
||||
|
||||
// replaceOrAppendEnvValues returns the defaults with the overrides either
|
||||
// replaced by env key or appended to the list
|
||||
func replaceOrAppendEnvValues(defaults, overrides []string) []string {
|
||||
cache := make(map[string]int, len(defaults))
|
||||
for i, e := range defaults {
|
||||
parts := strings.SplitN(e, "=", 2)
|
||||
cache[parts[0]] = i
|
||||
}
|
||||
|
||||
for _, value := range overrides {
|
||||
// Values w/o = means they want this env to be removed/unset.
|
||||
if !strings.Contains(value, "=") {
|
||||
if i, exists := cache[value]; exists {
|
||||
defaults[i] = "" // Used to indicate it should be removed
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Just do a normal set/update
|
||||
parts := strings.SplitN(value, "=", 2)
|
||||
if i, exists := cache[parts[0]]; exists {
|
||||
defaults[i] = value
|
||||
} else {
|
||||
defaults = append(defaults, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove all entries that we want to "unset"
|
||||
for i := 0; i < len(defaults); i++ {
|
||||
if defaults[i] == "" {
|
||||
defaults = append(defaults[:i], defaults[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
return defaults
|
||||
}
|
||||
|
||||
// Command runs a container
|
||||
var Command = cli.Command{
|
||||
Name: "run",
|
||||
Usage: "run a container",
|
||||
ArgsUsage: "Image|RootFS ID [COMMAND] [ARG...]",
|
||||
ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]",
|
||||
Flags: append([]cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "tty,t",
|
||||
@ -125,7 +198,7 @@ var runCommand = cli.Command{
|
||||
if context.Bool("rm") && !detach {
|
||||
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
}
|
||||
task, err := newTask(ctx, client, container, context.String("checkpoint"), tty, context.Bool("null-io"))
|
||||
task, err := tasks.NewTask(ctx, client, container, context.String("checkpoint"), tty, context.Bool("null-io"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -151,7 +224,7 @@ var runCommand = cli.Command{
|
||||
return nil
|
||||
}
|
||||
if tty {
|
||||
if err := handleConsoleResize(ctx, task, con); err != nil {
|
||||
if err := tasks.HandleConsoleResize(ctx, task, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
@ -1,56 +1,23 @@
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
package run
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func init() {
|
||||
runCommand.Flags = append(runCommand.Flags, cli.BoolFlag{
|
||||
Command.Flags = append(Command.Flags, cli.BoolFlag{
|
||||
Name: "rootfs",
|
||||
Usage: "use custom rootfs that is not managed by containerd snapshotter.",
|
||||
Usage: "use custom rootfs that is not managed by containerd snapshotter",
|
||||
})
|
||||
}
|
||||
|
||||
func handleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
|
||||
// do an initial resize of the console
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
logrus.WithError(err).Error("resize pty")
|
||||
}
|
||||
s := make(chan os.Signal, 16)
|
||||
signal.Notify(s, unix.SIGWINCH)
|
||||
go func() {
|
||||
for range s {
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("get pty size")
|
||||
continue
|
||||
}
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
logrus.WithError(err).Error("resize pty")
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func withTTY() containerd.SpecOpts {
|
||||
return containerd.WithTTY
|
||||
}
|
||||
@ -115,24 +82,3 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
||||
cOpts = append([]containerd.NewContainerOpts{containerd.WithNewSpec(opts...)}, cOpts...)
|
||||
return client.NewContainer(ctx, id, cOpts...)
|
||||
}
|
||||
|
||||
func newTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, tty, nullIO bool) (containerd.Task, error) {
|
||||
if checkpoint == "" {
|
||||
io := containerd.Stdio
|
||||
if tty {
|
||||
io = containerd.StdioTerminal
|
||||
}
|
||||
if nullIO {
|
||||
if tty {
|
||||
return nil, errors.New("tty and null-io cannot be used together")
|
||||
}
|
||||
io = containerd.NullIO
|
||||
}
|
||||
return container.NewTask(ctx, io)
|
||||
}
|
||||
im, err := client.GetImage(ctx, checkpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return container.NewTask(ctx, containerd.Stdio, containerd.WithTaskCheckpoint(im))
|
||||
}
|
@ -1,15 +1,13 @@
|
||||
package main
|
||||
package run
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -19,7 +17,7 @@ import (
|
||||
const pipeRoot = `\\.\pipe`
|
||||
|
||||
func init() {
|
||||
runCommand.Flags = append(runCommand.Flags, cli.StringSliceFlag{
|
||||
Command.Flags = append(Command.Flags, cli.StringSliceFlag{
|
||||
Name: "layer",
|
||||
Usage: "HCSSHIM Layers to be used",
|
||||
})
|
||||
@ -36,34 +34,6 @@ func withLayers(context *cli.Context) containerd.SpecOpts {
|
||||
}
|
||||
}
|
||||
|
||||
func handleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
|
||||
// do an initial resize of the console
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
prevSize := size
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("get pty size")
|
||||
continue
|
||||
}
|
||||
|
||||
if size.Width != prevSize.Width || size.Height != prevSize.Height {
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
logrus.WithError(err).Error("resize pty")
|
||||
}
|
||||
prevSize = size
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func withTTY(terminal bool) containerd.SpecOpts {
|
||||
if !terminal {
|
||||
return func(ctx gocontext.Context, client *containerd.Client, c *containers.Container, s *specs.Spec) error {
|
||||
@ -117,17 +87,3 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
||||
// TODO(mlaventure): containerd.WithImage(image),
|
||||
)
|
||||
}
|
||||
|
||||
func newTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, _ string, tty, nullIO bool) (containerd.Task, error) {
|
||||
io := containerd.Stdio
|
||||
if tty {
|
||||
io = containerd.StdioTerminal
|
||||
}
|
||||
if nullIO {
|
||||
if tty {
|
||||
return nil, errors.New("tty and null-io cannot be used together")
|
||||
}
|
||||
io = containerd.NullIO
|
||||
}
|
||||
return container.NewTask(ctx, io)
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
package shim
|
||||
|
||||
import (
|
||||
gocontext "context"
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package shim
|
||||
|
||||
import (
|
||||
"io"
|
@ -1,6 +1,6 @@
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
package shim
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -45,7 +45,8 @@ var fifoFlags = []cli.Flag{
|
||||
},
|
||||
}
|
||||
|
||||
var shimCommand = cli.Command{
|
||||
// Command is the cli command for interacting with a shim
|
||||
var Command = cli.Command{
|
||||
Name: "shim",
|
||||
Usage: "interact with a shim directly",
|
||||
Flags: []cli.Flag{
|
||||
@ -55,89 +56,14 @@ var shimCommand = cli.Command{
|
||||
},
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
shimCreateCommand,
|
||||
shimStartCommand,
|
||||
shimDeleteCommand,
|
||||
shimStateCommand,
|
||||
shimExecCommand,
|
||||
deleteCommand,
|
||||
execCommand,
|
||||
startCommand,
|
||||
stateCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var shimCreateCommand = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "create a container with a shim",
|
||||
Flags: append(fifoFlags,
|
||||
cli.StringFlag{
|
||||
Name: "bundle",
|
||||
Usage: "bundle path for the container",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Value: "runc",
|
||||
Usage: "runtime to use for the container",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "attach,a",
|
||||
Usage: "stay attached to the container and open the fifos",
|
||||
},
|
||||
),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
id = context.Args().First()
|
||||
ctx = gocontext.Background()
|
||||
)
|
||||
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
service, err := getShimService(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tty := context.Bool("tty")
|
||||
wg, err := prepareStdio(context.String("stdin"), context.String("stdout"), context.String("stderr"), tty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := service.Create(ctx, &shim.CreateTaskRequest{
|
||||
ID: id,
|
||||
Bundle: context.String("bundle"),
|
||||
Runtime: context.String("runtime"),
|
||||
Stdin: context.String("stdin"),
|
||||
Stdout: context.String("stdout"),
|
||||
Stderr: context.String("stderr"),
|
||||
Terminal: tty,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("container created with id %s and pid %d\n", id, r.Pid)
|
||||
if context.Bool("attach") {
|
||||
if tty {
|
||||
current := console.Current()
|
||||
defer current.Reset()
|
||||
if err := current.SetRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
size, err := current.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := service.ResizePty(ctx, &shim.ResizePtyRequest{
|
||||
ID: id,
|
||||
Width: uint32(size.Width),
|
||||
Height: uint32(size.Height),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var shimStartCommand = cli.Command{
|
||||
var startCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start a container with a shim",
|
||||
Action: func(context *cli.Context) error {
|
||||
@ -152,7 +78,7 @@ var shimStartCommand = cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var shimDeleteCommand = cli.Command{
|
||||
var deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "delete a container with a shim",
|
||||
Action: func(context *cli.Context) error {
|
||||
@ -169,7 +95,7 @@ var shimDeleteCommand = cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var shimStateCommand = cli.Command{
|
||||
var stateCommand = cli.Command{
|
||||
Name: "state",
|
||||
Usage: "get the state of all the processes of the shim",
|
||||
Action: func(context *cli.Context) error {
|
||||
@ -188,7 +114,7 @@ var shimStateCommand = cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var shimExecCommand = cli.Command{
|
||||
var execCommand = cli.Command{
|
||||
Name: "exec",
|
||||
Usage: "exec a new process in the shim's container",
|
||||
Flags: append(fifoFlags,
|
@ -23,17 +23,17 @@ var Command = cli.Command{
|
||||
Usage: "manage snapshots",
|
||||
Flags: commands.SnapshotterFlags,
|
||||
Subcommands: cli.Commands{
|
||||
listCommand,
|
||||
usageCommand,
|
||||
removeCommand,
|
||||
prepareCommand,
|
||||
viewCommand,
|
||||
treeCommand,
|
||||
mountCommand,
|
||||
commitCommand,
|
||||
infoCommand,
|
||||
listCommand,
|
||||
mountCommand,
|
||||
prepareCommand,
|
||||
removeCommand,
|
||||
setLabelCommand,
|
||||
treeCommand,
|
||||
unpackCommand,
|
||||
usageCommand,
|
||||
viewCommand,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"os"
|
||||
@ -10,7 +10,7 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var taskAttachCommand = cli.Command{
|
||||
var attachCommand = cli.Command{
|
||||
Name: "attach",
|
||||
Usage: "attach to the IO of a running container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
@ -51,7 +51,7 @@ var taskAttachCommand = cli.Command{
|
||||
}
|
||||
|
||||
if tty {
|
||||
if err := handleConsoleResize(ctx, task, con); err != nil {
|
||||
if err := HandleConsoleResize(ctx, task, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -9,10 +9,10 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var taskCheckpointCommand = cli.Command{
|
||||
var checkpointCommand = cli.Command{
|
||||
Name: "checkpoint",
|
||||
Usage: "checkpoint a container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
ArgsUsage: "[flags] CONTAINER",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "exit",
|
@ -1,11 +1,11 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var taskDeleteCommand = cli.Command{
|
||||
var deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "delete a task",
|
||||
ArgsUsage: "CONTAINER",
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@ -11,10 +11,10 @@ import (
|
||||
)
|
||||
|
||||
//TODO:(jessvalarezo) exec-id is optional here, update to required arg
|
||||
var taskExecCommand = cli.Command{
|
||||
var execCommand = cli.Command{
|
||||
Name: "exec",
|
||||
Usage: "execute additional processes in an existing container",
|
||||
ArgsUsage: "CONTAINER CMD [ARG...]",
|
||||
ArgsUsage: "[flags] CONTAINER CMD [ARG...]",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "cwd",
|
||||
@ -84,7 +84,7 @@ var taskExecCommand = cli.Command{
|
||||
}
|
||||
}
|
||||
if tty {
|
||||
if err := handleConsoleResize(ctx, process, con); err != nil {
|
||||
if err := HandleConsoleResize(ctx, process, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
@ -8,10 +8,10 @@ import (
|
||||
|
||||
// TODO:(jessvalarezo) the pid flag is not used here
|
||||
// update to be able to signal given pid
|
||||
var taskKillCommand = cli.Command{
|
||||
var killCommand = cli.Command{
|
||||
Name: "kill",
|
||||
Usage: "signal a container (default: SIGTERM)",
|
||||
ArgsUsage: "CONTAINER",
|
||||
ArgsUsage: "[flags] CONTAINER",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "signal, s",
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -10,28 +10,11 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var tasksCommand = cli.Command{
|
||||
Name: "tasks",
|
||||
Usage: "manage tasks",
|
||||
Aliases: []string{"t"},
|
||||
Subcommands: []cli.Command{
|
||||
taskAttachCommand,
|
||||
taskCheckpointCommand,
|
||||
taskExecCommand,
|
||||
taskKillCommand,
|
||||
taskPauseCommand,
|
||||
taskPsCommand,
|
||||
taskResumeCommand,
|
||||
taskStartCommand,
|
||||
taskDeleteCommand,
|
||||
taskListCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var taskListCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list tasks",
|
||||
Aliases: []string{"ls"},
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list tasks",
|
||||
Aliases: []string{"ls"},
|
||||
ArgsUsage: "[flags]",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
@ -1,11 +1,11 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var taskPauseCommand = cli.Command{
|
||||
var pauseCommand = cli.Command{
|
||||
Name: "pause",
|
||||
Usage: "pause an existing container",
|
||||
ArgsUsage: "CONTAINER",
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var taskPsCommand = cli.Command{
|
||||
var psCommand = cli.Command{
|
||||
Name: "ps",
|
||||
Usage: "list processes for container",
|
||||
ArgsUsage: "CONTAINER",
|
@ -1,11 +1,11 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var taskResumeCommand = cli.Command{
|
||||
var resumeCommand = cli.Command{
|
||||
Name: "resume",
|
||||
Usage: "resume a paused container",
|
||||
ArgsUsage: "CONTAINER",
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/console"
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var taskStartCommand = cli.Command{
|
||||
var startCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start a container that have been created",
|
||||
ArgsUsage: "CONTAINER",
|
||||
@ -43,7 +43,7 @@ var taskStartCommand = cli.Command{
|
||||
|
||||
tty := spec.Process.Terminal
|
||||
|
||||
task, err := newTask(ctx, client, container, "", tty, context.Bool("null-io"))
|
||||
task, err := NewTask(ctx, client, container, "", tty, context.Bool("null-io"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -66,7 +66,7 @@ var taskStartCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
if tty {
|
||||
if err := handleConsoleResize(ctx, task, con); err != nil {
|
||||
if err := HandleConsoleResize(ctx, task, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
30
cmd/ctr/commands/tasks/tasks.go
Normal file
30
cmd/ctr/commands/tasks/tasks.go
Normal file
@ -0,0 +1,30 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type resizer interface {
|
||||
Resize(ctx gocontext.Context, w, h uint32) error
|
||||
}
|
||||
|
||||
// Command is the cli command for managing tasks
|
||||
var Command = cli.Command{
|
||||
Name: "tasks",
|
||||
Usage: "manage tasks",
|
||||
Aliases: []string{"t"},
|
||||
Subcommands: []cli.Command{
|
||||
attachCommand,
|
||||
checkpointCommand,
|
||||
deleteCommand,
|
||||
execCommand,
|
||||
listCommand,
|
||||
killCommand,
|
||||
pauseCommand,
|
||||
psCommand,
|
||||
resumeCommand,
|
||||
startCommand,
|
||||
},
|
||||
}
|
64
cmd/ctr/commands/tasks/tasks_unix.go
Normal file
64
cmd/ctr/commands/tasks/tasks_unix.go
Normal file
@ -0,0 +1,64 @@
|
||||
// +build !windows
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// HandleConsoleResize resizes the console
|
||||
func HandleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
|
||||
// do an initial resize of the console
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
log.G(ctx).WithError(err).Error("resize pty")
|
||||
}
|
||||
s := make(chan os.Signal, 16)
|
||||
signal.Notify(s, unix.SIGWINCH)
|
||||
go func() {
|
||||
for range s {
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("get pty size")
|
||||
continue
|
||||
}
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
log.G(ctx).WithError(err).Error("resize pty")
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewTask creates a new task
|
||||
func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, tty, nullIO bool) (containerd.Task, error) {
|
||||
if checkpoint == "" {
|
||||
io := containerd.Stdio
|
||||
if tty {
|
||||
io = containerd.StdioTerminal
|
||||
}
|
||||
if nullIO {
|
||||
if tty {
|
||||
return nil, errors.New("tty and null-io cannot be used together")
|
||||
}
|
||||
io = containerd.NullIO
|
||||
}
|
||||
return container.NewTask(ctx, io)
|
||||
}
|
||||
im, err := client.GetImage(ctx, checkpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return container.NewTask(ctx, containerd.Stdio, containerd.WithTaskCheckpoint(im))
|
||||
}
|
55
cmd/ctr/commands/tasks/tasks_windows.go
Normal file
55
cmd/ctr/commands/tasks/tasks_windows.go
Normal file
@ -0,0 +1,55 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// HandleConsoleResize resizes the console
|
||||
func HandleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
|
||||
// do an initial resize of the console
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
prevSize := size
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("get pty size")
|
||||
continue
|
||||
}
|
||||
|
||||
if size.Width != prevSize.Width || size.Height != prevSize.Height {
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
log.G(ctx).WithError(err).Error("resize pty")
|
||||
}
|
||||
prevSize = size
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewTask creates a new task
|
||||
func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, _ string, tty, nullIO bool) (containerd.Task, error) {
|
||||
io := containerd.Stdio
|
||||
if tty {
|
||||
io = containerd.StdioTerminal
|
||||
}
|
||||
if nullIO {
|
||||
if tty {
|
||||
return nil, errors.New("tty and null-io cannot be used together")
|
||||
}
|
||||
io = containerd.NullIO
|
||||
}
|
||||
return container.NewTask(ctx, io)
|
||||
}
|
@ -12,7 +12,10 @@ import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/images"
|
||||
namespacesCmd "github.com/containerd/containerd/cmd/ctr/commands/namespaces"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/plugins"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/pprof"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/run"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/snapshot"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/tasks"
|
||||
versionCmd "github.com/containerd/containerd/cmd/ctr/commands/version"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/server"
|
||||
@ -79,10 +82,10 @@ containerd CLI
|
||||
events.Command,
|
||||
images.Command,
|
||||
namespacesCmd.Command,
|
||||
pprofCommand,
|
||||
runCommand,
|
||||
pprof.Command,
|
||||
run.Command,
|
||||
snapshot.Command,
|
||||
tasksCommand,
|
||||
tasks.Command,
|
||||
}, extraCmds...)
|
||||
app.Before = func(context *cli.Context) error {
|
||||
if context.GlobalBool("debug") {
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/containerd/containerd/cmd/ctr/commands/shim"
|
||||
|
||||
func init() {
|
||||
extraCmds = append(extraCmds, shimCommand)
|
||||
extraCmds = append(extraCmds, shim.Command)
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// parseMountFlag parses a mount string in the form "type=foo,source=/path,destination=/target,options=rbind:rw"
|
||||
func parseMountFlag(m string) (specs.Mount, error) {
|
||||
mount := specs.Mount{}
|
||||
r := csv.NewReader(strings.NewReader(m))
|
||||
|
||||
fields, err := r.Read()
|
||||
if err != nil {
|
||||
return mount, err
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
v := strings.Split(field, "=")
|
||||
if len(v) != 2 {
|
||||
return mount, fmt.Errorf("invalid mount specification: expected key=val")
|
||||
}
|
||||
|
||||
key := v[0]
|
||||
val := v[1]
|
||||
switch key {
|
||||
case "type":
|
||||
mount.Type = val
|
||||
case "source", "src":
|
||||
mount.Source = val
|
||||
case "destination", "dst":
|
||||
mount.Destination = val
|
||||
case "options":
|
||||
mount.Options = strings.Split(val, ":")
|
||||
default:
|
||||
return mount, fmt.Errorf("mount option %q not supported", key)
|
||||
}
|
||||
}
|
||||
|
||||
return mount, nil
|
||||
}
|
||||
|
||||
// replaceOrAppendEnvValues returns the defaults with the overrides either
|
||||
// replaced by env key or appended to the list
|
||||
func replaceOrAppendEnvValues(defaults, overrides []string) []string {
|
||||
cache := make(map[string]int, len(defaults))
|
||||
for i, e := range defaults {
|
||||
parts := strings.SplitN(e, "=", 2)
|
||||
cache[parts[0]] = i
|
||||
}
|
||||
|
||||
for _, value := range overrides {
|
||||
// Values w/o = means they want this env to be removed/unset.
|
||||
if !strings.Contains(value, "=") {
|
||||
if i, exists := cache[value]; exists {
|
||||
defaults[i] = "" // Used to indicate it should be removed
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Just do a normal set/update
|
||||
parts := strings.SplitN(value, "=", 2)
|
||||
if i, exists := cache[parts[0]]; exists {
|
||||
defaults[i] = value
|
||||
} else {
|
||||
defaults = append(defaults, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove all entries that we want to "unset"
|
||||
for i := 0; i < len(defaults); i++ {
|
||||
if defaults[i] == "" {
|
||||
defaults = append(defaults[:i], defaults[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
return defaults
|
||||
}
|
Loading…
Reference in New Issue
Block a user