From 84aa0bfde626cd7a5d067c80dbe4ac343bc097bf Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Wed, 26 Sep 2018 13:49:53 -0700 Subject: [PATCH 1/4] Forward containerd debug to shim invocation Signed-off-by: Justin Terry (VM) --- runtime/v2/binary.go | 10 +++++++-- runtime/v2/runhcs/service.go | 7 ++++++- runtime/v2/shim/shim.go | 9 +++++++++ runtime/v2/shim/shim_test.go | 39 ++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 runtime/v2/shim/shim_test.go diff --git a/runtime/v2/binary.go b/runtime/v2/binary.go index 0743c4ed9..a27289369 100644 --- a/runtime/v2/binary.go +++ b/runtime/v2/binary.go @@ -31,6 +31,7 @@ import ( "github.com/containerd/containerd/runtime/v2/task" "github.com/containerd/ttrpc" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) func shimBinary(ctx context.Context, bundle *Bundle, runtime, containerdAddress string, events *exchange.Exchange, rt *runtime.TaskList) *binary { @@ -52,13 +53,18 @@ type binary struct { } func (b *binary) Start(ctx context.Context) (_ *shim, err error) { + args := []string{"-id", b.bundle.ID} + if logrus.GetLevel() == logrus.DebugLevel { + args = append(args, "-debug") + } + args = append(args, "start") + cmd, err := client.Command( ctx, b.runtime, b.containerdAddress, b.bundle.Path, - "-id", b.bundle.ID, - "start", + args..., ) if err != nil { return nil, err diff --git a/runtime/v2/runhcs/service.go b/runtime/v2/runhcs/service.go index 9334a1168..895bcead9 100644 --- a/runtime/v2/runhcs/service.go +++ b/runtime/v2/runhcs/service.go @@ -160,8 +160,13 @@ func (s *service) StartShim(ctx context.Context, id, containerdBinary, container "-address", containerdAddress, "-publish-binary", containerdBinary, "-socket", socketAddress, - "-debug", } + + opts, ok := ctx.Value(shim.OptsKey{}).(shim.Opts) + if ok && opts.Debug { + args = append(args, "-debug") + } + cmd := exec.Command(self, args...) cmd.Dir = cwd cmd.Env = append(os.Environ(), "GOMAXPROCS=2") diff --git a/runtime/v2/shim/shim.go b/runtime/v2/shim/shim.go index da2a2e887..f2ebf7e1e 100644 --- a/runtime/v2/shim/shim.go +++ b/runtime/v2/shim/shim.go @@ -53,6 +53,14 @@ type Shim interface { StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error) } +// OptsKey is the context key for the Opts value. +type OptsKey struct{} + +// Opts are context options associated with the shim invocation. +type Opts struct { + Debug bool +} + var ( debugFlag bool idFlag string @@ -133,6 +141,7 @@ func run(id string, initFunc Init) error { return fmt.Errorf("shim namespace cannot be empty") } ctx := namespaces.WithNamespace(context.Background(), namespaceFlag) + ctx = context.WithValue(ctx, OptsKey{}, Opts{Debug: debugFlag}) ctx = log.WithLogger(ctx, log.G(ctx).WithField("runtime", id)) service, err := initFunc(ctx, idFlag, publisher) diff --git a/runtime/v2/shim/shim_test.go b/runtime/v2/shim/shim_test.go new file mode 100644 index 000000000..282059c76 --- /dev/null +++ b/runtime/v2/shim/shim_test.go @@ -0,0 +1,39 @@ +/* + 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 shim + +import ( + "context" + "testing" +) + +func TestShimOptWithValue(t *testing.T) { + ctx := context.TODO() + ctx = context.WithValue(ctx, OptsKey{}, Opts{Debug: true}) + + o := ctx.Value(OptsKey{}) + if o == nil { + t.Fatal("opts nil") + } + op, ok := o.(Opts) + if !ok { + t.Fatal("opts not of type Opts") + } + if !op.Debug { + t.Fatal("opts.Debug should be true") + } +} From 83437ef646eb61fbe3788d0e66004b904c0272fd Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Wed, 26 Sep 2018 13:54:57 -0700 Subject: [PATCH 2/4] Fixes containerd-shim-runhcs Delete on exec id Signed-off-by: Justin Terry (VM) --- runtime/v2/runhcs/service.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/runtime/v2/runhcs/service.go b/runtime/v2/runhcs/service.go index 895bcead9..7d302b477 100644 --- a/runtime/v2/runhcs/service.go +++ b/runtime/v2/runhcs/service.go @@ -486,13 +486,15 @@ func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAP return nil, err } - rhs := newRunhcs(p.bundle) - - dopts := &runhcs.DeleteOpts{ - Force: true, - } - if err := rhs.Delete(ctx, p.id, dopts); err != nil { - return nil, errors.Wrapf(err, "failed to delete container: %s", p.id) + // This is a container + if p.cid == p.id { + rhs := newRunhcs(p.bundle) + dopts := &runhcs.DeleteOpts{ + Force: true, + } + if err := rhs.Delete(ctx, p.id, dopts); err != nil { + return nil, errors.Wrapf(err, "failed to delete container: %s", p.id) + } } select { From 772644e978a5f7a95cca419e3894d39b5a468b2c Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Wed, 26 Sep 2018 13:57:15 -0700 Subject: [PATCH 3/4] Fixes containerd-shim-runhcs State on exec id Signed-off-by: Justin Terry (VM) --- runtime/v2/runhcs/service.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/runtime/v2/runhcs/service.go b/runtime/v2/runhcs/service.go index 7d302b477..02e833d33 100644 --- a/runtime/v2/runhcs/service.go +++ b/runtime/v2/runhcs/service.go @@ -204,14 +204,26 @@ func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI. return nil, err } - rhcs := newRunhcs(p.bundle) - cs, err := rhcs.State(ctx, p.id) - if err != nil { - return nil, err + var tstatus string + + // This is a container + if p.cid == p.id { + rhcs := newRunhcs(p.bundle) + cs, err := rhcs.State(ctx, p.id) + if err != nil { + return nil, err + } + tstatus = cs.Status + } else { + if p.started { + tstatus = "running" + } else { + tstatus = "created" + } } status := task.StatusUnknown - switch cs.Status { + switch tstatus { case "created": status = task.StatusCreated case "running": @@ -224,8 +236,8 @@ func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI. pe := p.stat() return &taskAPI.StateResponse{ ID: p.id, - Bundle: cs.Bundle, - Pid: uint32(cs.InitProcessPid), + Bundle: p.bundle, + Pid: p.pid, Status: status, Stdin: p.stdin, Stdout: p.stdout, From 81eb40fabfcbc010947fc0b9e8083e682536aea9 Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Mon, 24 Sep 2018 16:09:16 -0700 Subject: [PATCH 4/4] Adds containerd-shim-runhcs verbose logging support Revendors to Microsoft/hcsshim v0.7.5 that added support for logging all runhcs.exe commands via Windows named pipes. This now launches all runhcs.exe commands and forwards debug logging to the containerd-shim-runhcs log when with --debug. Signed-off-by: Justin Terry (VM) --- runtime/v2/runhcs/service.go | 240 ++++++++++++++++-- vendor.conf | 2 +- .../Microsoft/hcsshim/cmd/go-runhcs/runhcs.go | 17 +- .../hcsshim/cmd/go-runhcs/runhcs_create.go | 29 ++- .../hcsshim/cmd/go-runhcs/runhcs_exec.go | 15 +- .../Microsoft/hcsshim/hnsendpoint.go | 2 + 6 files changed, 264 insertions(+), 41 deletions(-) diff --git a/runtime/v2/runhcs/service.go b/runtime/v2/runhcs/service.go index 02e833d33..c5d92edaf 100644 --- a/runtime/v2/runhcs/service.go +++ b/runtime/v2/runhcs/service.go @@ -22,15 +22,19 @@ import ( "context" "encoding/json" "fmt" + "io" + "io/ioutil" + "net" "os" "os/exec" "path" - "path/filepath" "strconv" "strings" "sync" + "syscall" "time" + winio "github.com/Microsoft/go-winio" "github.com/Microsoft/hcsshim/cmd/go-runhcs" containerd_types "github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types/task" @@ -50,24 +54,87 @@ import ( const ( runhcsShimVersion = "0.0.1" + safePipePrefix = `\\.\pipe\ProtectedPrefix\Administrators\` + + errorConnectionAborted syscall.Errno = 1236 ) var ( empty = &ptypes.Empty{} ) -func newRunhcs(bundle string) *runhcs.Runhcs { +func newRunhcs(debugLog string) *runhcs.Runhcs { rhs := &runhcs.Runhcs{ - Debug: logrus.GetLevel() == logrus.DebugLevel, + Debug: debugLog != "", LogFormat: runhcs.JSON, Owner: "containerd-runhcs-shim-v1", } if rhs.Debug { - rhs.Log = filepath.Join(bundle, "runhcs-debug.log") + rhs.Log = debugLog } return rhs } +// forwardRunhcsLogs copies logs from c and writes them to the ctx logger +// upstream. +func forwardRunhcsLogs(ctx context.Context, c net.Conn, fields logrus.Fields) { + defer c.Close() + j := json.NewDecoder(c) + + for { + e := logrus.Entry{} + err := j.Decode(&e.Data) + if err == io.EOF || err == errorConnectionAborted { + break + } + if err != nil { + // Likely the last message wasn't complete at closure. Just read all + // data and forward as error. + data, _ := ioutil.ReadAll(io.MultiReader(j.Buffered(), c)) + if len(data) != 0 { + log.G(ctx).WithFields(fields).Error(string(data)) + } + break + } + + msg := e.Data[logrus.FieldKeyMsg] + delete(e.Data, logrus.FieldKeyMsg) + + level, err := logrus.ParseLevel(e.Data[logrus.FieldKeyLevel].(string)) + if err != nil { + log.G(ctx).WithFields(fields).WithError(err).Debug("invalid log level") + level = logrus.DebugLevel + } + delete(e.Data, logrus.FieldKeyLevel) + + // TODO: JTERRY75 maybe we need to make this configurable so we know + // that runhcs is using the same one we are deserializing. + ti, err := time.Parse(logrus.DefaultTimestampFormat, e.Data[logrus.FieldKeyTime].(string)) + if err != nil { + log.G(ctx).WithFields(fields).WithError(err).Debug("invalid time stamp format") + ti = time.Time{} + } + delete(e.Data, logrus.FieldKeyTime) + + etr := log.G(ctx).WithFields(fields).WithFields(e.Data) + etr.Time = ti + switch level { + case logrus.PanicLevel: + etr.Panic(msg) + case logrus.FatalLevel: + etr.Fatal(msg) + case logrus.ErrorLevel: + etr.Error(msg) + case logrus.WarnLevel: + etr.Warn(msg) + case logrus.InfoLevel: + etr.Info(msg) + case logrus.DebugLevel: + etr.Debug(msg) + } + } +} + // New returns a new runhcs shim service that can be used via GRPC func New(ctx context.Context, id string, publisher events.Publisher) (shim.Shim, error) { return &service{ @@ -87,6 +154,10 @@ type service struct { context context.Context + // debugLog if not "" indicates the log pipe path for runhcs.exe to write its logs to. + debugLog string + debugListener net.Listener + id string processes map[string]*process @@ -195,6 +266,8 @@ func (s *service) StartShim(ctx context.Context, id, containerdBinary, container // State returns runtime state information for a process func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { + log.G(ctx).Debugf("State: %s: %s", r.ID, r.ExecID) + s.mu.Lock() defer s.mu.Unlock() @@ -208,7 +281,7 @@ func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI. // This is a container if p.cid == p.id { - rhcs := newRunhcs(p.bundle) + rhcs := newRunhcs(s.debugLog) cs, err := rhcs.State(ctx, p.id) if err != nil { return nil, err @@ -318,7 +391,7 @@ func writeMountsToConfig(bundle string, mounts []*containerd_types.Mount) error // Create a new initial process and container with runhcs func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (*taskAPI.CreateTaskResponse, error) { - log.G(ctx).Infof("Create: %s", r.ID) + log.G(ctx).Debugf("Create: %s", r.ID) // Hold the lock for the entire duration to avoid duplicate process creation. s.mu.Lock() @@ -363,16 +436,84 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (*ta pr.close() } }() + // TODO: Parse the real RunHcs Opts r.Options + opts, ok := ctx.Value(shim.OptsKey{}).(shim.Opts) + if ok && opts.Debug { + if s.debugLog == "" { + logPath := safePipePrefix + fmt.Sprintf("runhcs-log-%s", r.ID) + l, err := winio.ListenPipe(logPath, nil) + if err != nil { + return nil, err + } + s.debugLog = logPath + s.debugListener = l + + // Accept connections and forward all logs for each runhcs.exe + // invocation + go func() { + for { + c, err := s.debugListener.Accept() + if err != nil { + if err == errorConnectionAborted { + break + } + log.G(ctx).WithError(err).Debug("log accept failure") + // Logrus error locally? + continue + } + fields := map[string]interface{}{ + "log-source": "runhcs", + "task-id": r.ID, + } + go forwardRunhcsLogs(ctx, c, fields) + } + }() + } + } pidfilePath := path.Join(r.Bundle, "runhcs-pidfile.pid") copts := &runhcs.CreateOpts{ IO: io, PidFile: pidfilePath, - ShimLog: path.Join(r.Bundle, "runhcs-shim.log"), - VMLog: path.Join(r.Bundle, "runhcs-vm-shim.log"), } + rhcs := newRunhcs(s.debugLog) + if rhcs.Debug { + doForwardLogs := func(source, logPipeFmt string, opt *string) error { + pipeName := fmt.Sprintf(logPipeFmt, r.ID) + *opt = safePipePrefix + pipeName + l, err := winio.ListenPipe(*opt, nil) + if err != nil { + return err + } + go func() { + defer l.Close() + c, err := l.Accept() + if err != nil { + log.G(ctx). + WithField("task-id", r.ID). + WithError(err). + Errorf("failed to accept %s", pipeName) + } else { + fields := map[string]interface{}{ + "log-source": source, + "task-id": r.ID, + } + go forwardRunhcsLogs(ctx, c, fields) + } + }() + return nil + } - rhcs := newRunhcs(r.Bundle) + err = doForwardLogs("runhcs-shim", "runhcs-shim-log-%s", &copts.ShimLog) + if err != nil { + return nil, err + } + + err = doForwardLogs("runhcs--vm-shim", "runhcs-vm-shim-log-%s", &copts.VMLog) + if err != nil { + return nil, err + } + } err = rhcs.Create(ctx, r.ID, r.Bundle, copts) if err != nil { return nil, err @@ -408,7 +549,7 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (*ta // Start a process func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { - log.G(ctx).Infof("Start: %s: %s", r.ID, r.ExecID) + log.G(ctx).Debugf("Start: %s: %s", r.ID, r.ExecID) var p *process var err error if p, err = s.getProcess(r.ID, r.ExecID); err != nil { @@ -421,7 +562,7 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI. return nil, errors.New("cannot start already started container or process") } - rhcs := newRunhcs(p.bundle) + rhcs := newRunhcs(s.debugLog) // This is a start/exec if r.ExecID != "" { @@ -431,10 +572,43 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI. eopts := &runhcs.ExecOpts{ IO: p.relay.io, PidFile: pidfilePath, - ShimLog: path.Join(p.bundle, fmt.Sprintf("runhcs-%s-shim.log", execFmt)), Detach: true, } + if rhcs.Debug { + doForwardLogs := func(source, pipeName string, opt *string) error { + *opt = safePipePrefix + pipeName + l, err := winio.ListenPipe(*opt, nil) + if err != nil { + return err + } + go func() { + defer l.Close() + c, err := l.Accept() + if err != nil { + log.G(ctx). + WithField("task-id", r.ID). + WithField("exec-id", r.ExecID). + WithError(err). + Errorf("failed to accept %s", pipeName) + } else { + fields := map[string]interface{}{ + "log-source": source, + "task-id": r.ID, + "exec-id": r.ExecID, + } + go forwardRunhcsLogs(ctx, c, fields) + } + }() + return nil + } + + err = doForwardLogs("runhcs-shim-exec", "runhcs-shim-log-"+execFmt, &eopts.ShimLog) + if err != nil { + return nil, err + } + } + // ID here is the containerID to exec the process in. err = rhcs.Exec(ctx, r.ID, procConfig, eopts) if err != nil { @@ -490,7 +664,7 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI. // Delete the initial process and container func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { - log.G(ctx).Infof("Delete: %s: %s", r.ID, r.ExecID) + log.G(ctx).Debugf("Delete: %s: %s", r.ID, r.ExecID) var p *process var err error @@ -500,7 +674,7 @@ func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAP // This is a container if p.cid == p.id { - rhs := newRunhcs(p.bundle) + rhs := newRunhcs(s.debugLog) dopts := &runhcs.DeleteOpts{ Force: true, } @@ -530,11 +704,15 @@ func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAP // Pids returns all pids inside the container func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { + log.G(ctx).Debugf("Pids: %s", r.ID) + return nil, errdefs.ErrNotImplemented } // Pause the container func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) { + log.G(ctx).Debugf("Pause: %s", r.ID) + // TODO: Validate that 'id' is actually a valid parent container ID var p *process var err error @@ -542,7 +720,7 @@ func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.E return nil, err } - rhcs := newRunhcs(p.bundle) + rhcs := newRunhcs(s.debugLog) if err = rhcs.Pause(ctx, p.id); err != nil { return nil, err } @@ -552,6 +730,8 @@ func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.E // Resume the container func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { + log.G(ctx).Debugf("Resume: %s", r.ID) + // TODO: Validate that 'id' is actually a valid parent container ID var p *process var err error @@ -559,7 +739,7 @@ func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes return nil, err } - rhcs := newRunhcs(p.bundle) + rhcs := newRunhcs(s.debugLog) if err = rhcs.Resume(ctx, p.id); err != nil { return nil, err } @@ -569,12 +749,14 @@ func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes // Checkpoint the container func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { + log.G(ctx).Debugf("Checkpoint: %s", r.ID) + return nil, errdefs.ErrNotImplemented } // Kill a process with the provided signal func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { - log.G(ctx).Infof("Kill: %s: %s", r.ID, r.ExecID) + log.G(ctx).Debugf("Kill: %s: %s", r.ID, r.ExecID) var p *process var err error @@ -584,7 +766,7 @@ func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Emp // TODO: JTERRY75 runhcs needs r.Signal in string form // TODO: JTERRY75 runhcs support for r.All? - rhcs := newRunhcs(p.bundle) + rhcs := newRunhcs(s.debugLog) if err = rhcs.Kill(ctx, p.id, strconv.FormatUint(uint64(r.Signal), 10)); err != nil { if !strings.Contains(err.Error(), "container is stopped") { return nil, err @@ -596,7 +778,7 @@ func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Emp // Exec an additional process inside the container func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { - log.G(ctx).Infof("Exec: %s: %s", r.ID, r.ExecID) + log.G(ctx).Debugf("Exec: %s: %s", r.ID, r.ExecID) s.mu.Lock() defer s.mu.Unlock() @@ -679,6 +861,8 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*pty // ResizePty of a process func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { + log.G(ctx).Debugf("ResizePty: %s: %s", r.ID, r.ExecID) + var p *process var err error if p, err = s.getProcess(r.ID, r.ExecID); err != nil { @@ -689,7 +873,7 @@ func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (* opts := runhcs.ResizeTTYOpts{ Pid: &pid, } - rhcs := newRunhcs(p.bundle) + rhcs := newRunhcs(s.debugLog) if err = rhcs.ResizeTTY(ctx, p.cid, uint16(r.Width), uint16(r.Height), &opts); err != nil { return nil, err } @@ -699,6 +883,8 @@ func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (* // CloseIO of a process func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { + log.G(ctx).Debugf("CloseIO: %s: %s", r.ID, r.ExecID) + var p *process var err error if p, err = s.getProcess(r.ID, r.ExecID); err != nil { @@ -710,11 +896,15 @@ func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptyp // Update a running container func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { + log.G(ctx).Debugf("Update: %s", r.ID) + return nil, errdefs.ErrNotImplemented } // Wait for a process to exit func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { + log.G(ctx).Debugf("Wait: %s: %s", r.ID, r.ExecID) + var p *process var err error if p, err = s.getProcess(r.ID, r.ExecID); err != nil { @@ -729,11 +919,15 @@ func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.Wa // Stats returns statistics about the running container func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + log.G(ctx).Debugf("Stats: %s", r.ID) + return nil, errdefs.ErrNotImplemented } // Connect returns the runhcs shim information func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { + log.G(ctx).Debugf("Connect: %s", r.ID) + return &taskAPI.ConnectResponse{ ShimPid: uint32(os.Getpid()), TaskPid: s.processes[s.id].pid, @@ -743,7 +937,11 @@ func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*task // Shutdown stops this instance of the runhcs shim func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*ptypes.Empty, error) { - log.G(ctx).Infof("Shutdown: %s", r.ID) + log.G(ctx).Debugf("Shutdown: %s", r.ID) + + if s.debugListener != nil { + s.debugListener.Close() + } os.Exit(0) return empty, nil diff --git a/vendor.conf b/vendor.conf index 4f1229c82..83ee7b90c 100644 --- a/vendor.conf +++ b/vendor.conf @@ -33,7 +33,7 @@ golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 github.com/Microsoft/go-winio v0.4.10 -github.com/Microsoft/hcsshim v0.7.4 +github.com/Microsoft/hcsshim v0.7.6 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go index df580248e..d3bae8abe 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go @@ -6,6 +6,8 @@ import ( "fmt" "os" "os/exec" + "path/filepath" + "strings" "sync" "github.com/containerd/go-runc" @@ -21,7 +23,8 @@ const ( // JSON is the JSON formatted log output. JSON Format = "json" - command = "runhcs" + command = "runhcs" + safePipePrefix = `\\.\pipe\ProtectedPrefix\Administrators\` ) var bytesBufferPool = sync.Pool{ @@ -43,7 +46,7 @@ func putBuf(b *bytes.Buffer) { type Runhcs struct { // Debug enables debug output for logging. Debug bool - // Log sets the log file path where internal debug information is written. + // Log sets the log file path or named pipe (e.g. \\.\pipe\ProtectedPrefix\Administrators\runhcs-log) where internal debug information is written. Log string // LogFormat sets the format used by logs. LogFormat Format @@ -59,8 +62,14 @@ func (r *Runhcs) args() []string { out = append(out, "--debug") } if r.Log != "" { - // TODO: JTERRY75 - Should we do abs here? - out = append(out, "--log", r.Log) + if strings.HasPrefix(r.Log, safePipePrefix) { + out = append(out, "--log", r.Log) + } else { + abs, err := filepath.Abs(r.Log) + if err == nil { + out = append(out, "--log", abs) + } + } } if r.LogFormat != none { out = append(out, "--log-format", string(r.LogFormat)) diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go index 601eab8b2..5a8d1d5e6 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "path/filepath" + "strings" runc "github.com/containerd/go-runc" ) @@ -13,9 +14,9 @@ type CreateOpts struct { runc.IO // PidFile is the path to the file to write the process id to. PidFile string - // ShimLog is the path to the log file for the launched shim process. + // ShimLog is the path to the log file or named pipe (e.g. \\.\pipe\ProtectedPrefix\Administrators\runhcs--shim-log) for the launched shim process. ShimLog string - // VMLog is the path to the log file for the launched VM shim process. + // VMLog is the path to the log file or named pipe (e.g. \\.\pipe\ProtectedPrefix\Administrators\runhcs--vm-log) for the launched VM shim process. VMLog string // VMConsole is the path to the pipe for the VM's console (e.g. \\.\pipe\debugpipe) VMConsole string @@ -31,18 +32,26 @@ func (opt *CreateOpts) args() ([]string, error) { out = append(out, "--pid-file", abs) } if opt.ShimLog != "" { - abs, err := filepath.Abs(opt.ShimLog) - if err != nil { - return nil, err + if strings.HasPrefix(opt.ShimLog, safePipePrefix) { + out = append(out, "--shim-log", opt.ShimLog) + } else { + abs, err := filepath.Abs(opt.ShimLog) + if err != nil { + return nil, err + } + out = append(out, "--shim-log", abs) } - out = append(out, "--shim-log", abs) } if opt.VMLog != "" { - abs, err := filepath.Abs(opt.VMLog) - if err != nil { - return nil, err + if strings.HasPrefix(opt.VMLog, safePipePrefix) { + out = append(out, "--vm-log", opt.VMLog) + } else { + abs, err := filepath.Abs(opt.VMLog) + if err != nil { + return nil, err + } + out = append(out, "--vm-log", abs) } - out = append(out, "--vm-log", abs) } if opt.VMConsole != "" { out = append(out, "--vm-console", opt.VMConsole) diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go index d2f69a3f2..34f4b7a58 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "path/filepath" + "strings" "github.com/containerd/go-runc" ) @@ -15,7 +16,7 @@ type ExecOpts struct { Detach bool // PidFile is the path to the file to write the process id to. PidFile string - // ShimLog is the path to the log file for the launched shim process. + // ShimLog is the path to the log file or named pipe (e.g. \\.\pipe\ProtectedPrefix\Administrators\runhcs---log) for the launched shim process. ShimLog string } @@ -32,11 +33,15 @@ func (opt *ExecOpts) args() ([]string, error) { out = append(out, "--pid-file", abs) } if opt.ShimLog != "" { - abs, err := filepath.Abs(opt.ShimLog) - if err != nil { - return nil, err + if strings.HasPrefix(opt.ShimLog, safePipePrefix) { + out = append(out, "--shim-log", opt.ShimLog) + } else { + abs, err := filepath.Abs(opt.ShimLog) + if err != nil { + return nil, err + } + out = append(out, "--shim-log", abs) } - out = append(out, "--shim-log", abs) } return out, nil } diff --git a/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go b/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go index 5f0dcfe75..f2eedbe3d 100644 --- a/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go +++ b/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go @@ -6,6 +6,8 @@ import ( // HNSEndpoint represents a network endpoint in HNS type HNSEndpoint = hns.HNSEndpoint +// Namespace represents a Compartment. +type Namespace = hns.Namespace //SystemType represents the type of the system on which actions are done type SystemType string