
This removes the RuntimeEvent super proto with enums into separate runtime event protos to be inline with the other events that are output by containerd. This also renames the runtime events into Task* events. Fixes #1071 Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
315 lines
7.0 KiB
Go
315 lines
7.0 KiB
Go
// +build !windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"time"
|
|
|
|
gocontext "context"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/grpclog"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/containerd/console"
|
|
shim "github.com/containerd/containerd/linux/shim/v1"
|
|
"github.com/containerd/containerd/typeurl"
|
|
protobuf "github.com/gogo/protobuf/types"
|
|
google_protobuf "github.com/golang/protobuf/ptypes/empty"
|
|
"github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/pkg/errors"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var empty = &google_protobuf.Empty{}
|
|
|
|
var fifoFlags = []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "stdin",
|
|
Usage: "specify the path to the stdin fifo",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "stdout",
|
|
Usage: "specify the path to the stdout fifo",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "stderr",
|
|
Usage: "specify the path to the stderr fifo",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "tty,t",
|
|
Usage: "enable tty support",
|
|
},
|
|
}
|
|
|
|
var shimCommand = cli.Command{
|
|
Name: "shim",
|
|
Usage: "interact with a shim directly",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "socket",
|
|
Usage: "socket on which to connect to the shim",
|
|
},
|
|
},
|
|
Subcommands: []cli.Command{
|
|
shimCreateCommand,
|
|
shimStartCommand,
|
|
shimDeleteCommand,
|
|
shimStateCommand,
|
|
shimExecCommand,
|
|
},
|
|
}
|
|
|
|
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{
|
|
Name: "start",
|
|
Usage: "start a container with a shim",
|
|
Action: func(context *cli.Context) error {
|
|
service, err := getShimService(context)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = service.Start(gocontext.Background(), empty)
|
|
return err
|
|
},
|
|
}
|
|
|
|
var shimDeleteCommand = cli.Command{
|
|
Name: "delete",
|
|
Usage: "delete a container with a shim",
|
|
Action: func(context *cli.Context) error {
|
|
service, err := getShimService(context)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, err := service.Delete(gocontext.Background(), empty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("container deleted and returned exit status %d\n", r.ExitStatus)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var shimStateCommand = cli.Command{
|
|
Name: "state",
|
|
Usage: "get the state of all the processes of the shim",
|
|
Action: func(context *cli.Context) error {
|
|
service, err := getShimService(context)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, err := service.State(gocontext.Background(), &shim.StateRequest{
|
|
ID: context.Args().First(),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data, err := json.Marshal(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf := bytes.NewBuffer(nil)
|
|
if err := json.Indent(buf, data, " ", " "); err != nil {
|
|
return err
|
|
}
|
|
buf.WriteTo(os.Stdout)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var shimExecCommand = cli.Command{
|
|
Name: "exec",
|
|
Usage: "exec a new process in the shim's container",
|
|
Flags: append(fifoFlags,
|
|
cli.BoolFlag{
|
|
Name: "attach,a",
|
|
Usage: "stay attached to the container and open the fifos",
|
|
},
|
|
cli.StringSliceFlag{
|
|
Name: "env,e",
|
|
Usage: "add environment vars",
|
|
Value: &cli.StringSlice{},
|
|
},
|
|
cli.StringFlag{
|
|
Name: "cwd",
|
|
Usage: "current working directory",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "spec",
|
|
Usage: "runtime spec",
|
|
},
|
|
),
|
|
Action: func(context *cli.Context) error {
|
|
service, err := getShimService(context)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var (
|
|
id = context.Args().First()
|
|
ctx = gocontext.Background()
|
|
)
|
|
|
|
if id == "" {
|
|
return errors.New("exec id must be provided")
|
|
}
|
|
|
|
tty := context.Bool("tty")
|
|
wg, err := prepareStdio(context.String("stdin"), context.String("stdout"), context.String("stderr"), tty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// read spec file and extract Any object
|
|
spec, err := ioutil.ReadFile(context.String("spec"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
url, err := typeurl.TypeURL(specs.Process{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
rq := &shim.ExecProcessRequest{
|
|
ID: id,
|
|
Spec: &protobuf.Any{
|
|
TypeUrl: url,
|
|
Value: spec,
|
|
},
|
|
Stdin: context.String("stdin"),
|
|
Stdout: context.String("stdout"),
|
|
Stderr: context.String("stderr"),
|
|
Terminal: tty,
|
|
}
|
|
r, err := service.Exec(ctx, rq)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("exec running with pid %d\n", r.Pid)
|
|
if context.Bool("attach") {
|
|
logrus.Info("attaching")
|
|
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
|
|
},
|
|
}
|
|
|
|
func getShimService(context *cli.Context) (shim.ShimClient, error) {
|
|
bindSocket := context.GlobalString("socket")
|
|
if bindSocket == "" {
|
|
return nil, errors.New("socket path must be specified")
|
|
}
|
|
|
|
// reset the logger for grpc to log to dev/null so that it does not mess with our stdio
|
|
grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
|
|
dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithTimeout(100 * time.Second)}
|
|
dialOpts = append(dialOpts,
|
|
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
|
|
return net.DialTimeout("unix", "\x00"+bindSocket, timeout)
|
|
},
|
|
))
|
|
conn, err := grpc.Dial(fmt.Sprintf("unix://%s", bindSocket), dialOpts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return shim.NewShimClient(conn), nil
|
|
}
|