...

Source file src/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/exec_wcow_podsandbox.go

Documentation: github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1

     1  //go:build windows
     2  
     3  package main
     4  
     5  import (
     6  	"context"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/Microsoft/hcsshim/internal/log"
    11  	eventstypes "github.com/containerd/containerd/api/events"
    12  	containerd_v1_types "github.com/containerd/containerd/api/types/task"
    13  	"github.com/containerd/containerd/errdefs"
    14  	"github.com/containerd/containerd/runtime"
    15  	"github.com/containerd/containerd/runtime/v2/task"
    16  	"github.com/pkg/errors"
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  func newWcowPodSandboxExec(ctx context.Context, events publisher, tid, bundle string) *wcowPodSandboxExec {
    21  	log.G(ctx).WithFields(logrus.Fields{
    22  		"tid":    tid,
    23  		"eid":    tid, // Init exec ID is always same as Task ID
    24  		"bundle": bundle,
    25  	}).Debug("newWcowPodSandboxExec")
    26  
    27  	wpse := &wcowPodSandboxExec{
    28  		events:     events,
    29  		tid:        tid,
    30  		bundle:     bundle,
    31  		state:      shimExecStateCreated,
    32  		exitStatus: 255, // By design for non-exited process status.
    33  		exited:     make(chan struct{}),
    34  	}
    35  	return wpse
    36  }
    37  
    38  var _ = (shimExec)(&wcowPodSandboxExec{})
    39  
    40  // wcowPodSandboxExec is a special exec type that actually holds no real
    41  // resources. The WCOW model has two services the HCS/HNS that actually hold
    42  // open any shared namespace outside of the container/process itself. So we
    43  // don't actually need to create them in the case of a POD for the sandbox
    44  // container.
    45  //
    46  // Note: This is only true today because CRI defines an API that allows for no
    47  // query/state/exec/io operations against the POD sandbox container itself. If
    48  // this changes we need to rethink this.
    49  //
    50  // Note 2: This is only true today because Windows contains only a shared
    51  // `NetworkNamespace` controlled via CNI in the CRI layer and held open by the
    52  // HNS and not by any container runtime attribute. If we ever have a shared
    53  // namespace that requires a container we will have to rethink this.
    54  type wcowPodSandboxExec struct {
    55  	events publisher
    56  	// tid is the task id of the container hosting this process.
    57  	//
    58  	// This MUST be treated as read only in the lifetime of the exec.
    59  	tid string
    60  	// bundle is typically the on disk path to the folder containing the
    61  	// `process.json` describing this process. In the `wcowPodSandboxExec` this
    62  	// will always be the init exec and thus the process is described in the
    63  	// `config.json`.
    64  	//
    65  	// This MUST be treated as read only in the lifetime of the exec.
    66  	bundle string
    67  
    68  	// sl is the state lock that MUST be held to safely read/write any of the
    69  	// following members.
    70  	sl         sync.Mutex
    71  	state      shimExecState
    72  	pid        int
    73  	exitStatus uint32
    74  	exitedAt   time.Time
    75  
    76  	// exited is a wait block which waits async for the process to exit.
    77  	exited chan struct{}
    78  }
    79  
    80  func (wpse *wcowPodSandboxExec) ID() string {
    81  	return wpse.tid
    82  }
    83  
    84  func (wpse *wcowPodSandboxExec) Pid() int {
    85  	wpse.sl.Lock()
    86  	defer wpse.sl.Unlock()
    87  	return wpse.pid
    88  }
    89  
    90  func (wpse *wcowPodSandboxExec) State() shimExecState {
    91  	wpse.sl.Lock()
    92  	defer wpse.sl.Unlock()
    93  	return wpse.state
    94  }
    95  
    96  func (wpse *wcowPodSandboxExec) Status() *task.StateResponse {
    97  	wpse.sl.Lock()
    98  	defer wpse.sl.Unlock()
    99  
   100  	var s containerd_v1_types.Status
   101  	switch wpse.state {
   102  	case shimExecStateCreated:
   103  		s = containerd_v1_types.StatusCreated
   104  	case shimExecStateRunning:
   105  		s = containerd_v1_types.StatusRunning
   106  	case shimExecStateExited:
   107  		s = containerd_v1_types.StatusStopped
   108  	}
   109  
   110  	return &task.StateResponse{
   111  		ID:         wpse.tid,
   112  		ExecID:     wpse.tid, // Init exec ID is always same as Task ID
   113  		Bundle:     wpse.bundle,
   114  		Pid:        uint32(wpse.pid),
   115  		Status:     s,
   116  		Stdin:      "", // NilIO
   117  		Stdout:     "", // NilIO
   118  		Stderr:     "", // NilIO
   119  		Terminal:   false,
   120  		ExitStatus: wpse.exitStatus,
   121  		ExitedAt:   wpse.exitedAt,
   122  	}
   123  }
   124  
   125  func (wpse *wcowPodSandboxExec) Start(ctx context.Context) error {
   126  	wpse.sl.Lock()
   127  	defer wpse.sl.Unlock()
   128  	if wpse.state != shimExecStateCreated {
   129  		return newExecInvalidStateError(wpse.tid, wpse.tid, wpse.state, "start")
   130  	}
   131  	// Transition the state
   132  	wpse.state = shimExecStateRunning
   133  	wpse.pid = 1 // Fake but init pid is always 1
   134  
   135  	// Publish the task start event. We never have an exec for the WCOW
   136  	// PodSandbox.
   137  	return wpse.events.publishEvent(
   138  		ctx,
   139  		runtime.TaskStartEventTopic,
   140  		&eventstypes.TaskStart{
   141  			ContainerID: wpse.tid,
   142  			Pid:         uint32(wpse.pid),
   143  		})
   144  }
   145  
   146  func (wpse *wcowPodSandboxExec) Kill(ctx context.Context, signal uint32) error {
   147  	wpse.sl.Lock()
   148  	defer wpse.sl.Unlock()
   149  	switch wpse.state {
   150  	case shimExecStateCreated:
   151  		wpse.state = shimExecStateExited
   152  		wpse.exitStatus = 1
   153  		wpse.exitedAt = time.Now()
   154  		close(wpse.exited)
   155  		return nil
   156  	case shimExecStateRunning:
   157  		// TODO: Should we verify that the signal would of killed the WCOW Process?
   158  		wpse.state = shimExecStateExited
   159  		wpse.exitStatus = 0
   160  		wpse.exitedAt = time.Now()
   161  
   162  		// NOTE: We do not support a non `init` exec for this "fake" init
   163  		// process. Skip any exited event which will be sent by the task.
   164  
   165  		close(wpse.exited)
   166  		return nil
   167  	case shimExecStateExited:
   168  		return errors.Wrapf(errdefs.ErrNotFound, "exec: '%s' in task: '%s' not found", wpse.tid, wpse.tid)
   169  	default:
   170  		return newExecInvalidStateError(wpse.tid, wpse.tid, wpse.state, "kill")
   171  	}
   172  }
   173  
   174  func (wpse *wcowPodSandboxExec) ResizePty(ctx context.Context, width, height uint32) error {
   175  	wpse.sl.Lock()
   176  	defer wpse.sl.Unlock()
   177  	// We will never have IO for a sandbox container so we wont have a tty
   178  	// either.
   179  	return errors.Wrapf(errdefs.ErrFailedPrecondition, "exec: '%s' in task: '%s' is not a tty", wpse.tid, wpse.tid)
   180  }
   181  
   182  func (wpse *wcowPodSandboxExec) CloseIO(ctx context.Context, stdin bool) error {
   183  	return nil
   184  }
   185  
   186  func (wpse *wcowPodSandboxExec) Wait() *task.StateResponse {
   187  	<-wpse.exited
   188  	return wpse.Status()
   189  }
   190  
   191  func (wpse *wcowPodSandboxExec) ForceExit(ctx context.Context, status int) {
   192  	wpse.sl.Lock()
   193  	defer wpse.sl.Unlock()
   194  	if wpse.state != shimExecStateExited {
   195  		// Avoid logging the force if we already exited gracefully
   196  		log.G(ctx).WithField("status", status).Debug("wcowPodSandboxExec::ForceExit")
   197  
   198  		wpse.state = shimExecStateExited
   199  		wpse.exitStatus = 1
   200  		wpse.exitedAt = time.Now()
   201  
   202  		// NOTE: We do not support a non `init` exec for this "fake" init
   203  		// process. Skip any exited event which will be sent by the task.
   204  
   205  		close(wpse.exited)
   206  	}
   207  }
   208  

View as plain text