Merge pull request #25634 from darrenstahlmsft/RevendorHcsshim

Revendor hcsshim to v0.4.1
This commit is contained in:
Sebastiaan van Stijn 2016-08-17 10:50:00 +02:00 committed by GitHub
commit 5e2a519957
19 changed files with 239 additions and 371 deletions

View file

@ -43,7 +43,7 @@ esac
# the following lines are in sorted order, FYI
clone git github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
clone git github.com/Microsoft/hcsshim v0.3.6
clone git github.com/Microsoft/hcsshim v0.4.1
clone git github.com/Microsoft/go-winio v0.3.4
clone git github.com/Sirupsen/logrus v0.10.0 # logrus is a common dependency among multiple deps
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a

View file

@ -294,13 +294,13 @@ func (clnt *client) Signal(containerID string, sig int) error {
if syscall.Signal(sig) == syscall.SIGKILL {
// Terminate the compute system
if err := cont.hcsContainer.Terminate(); err != nil {
if err != hcsshim.ErrVmcomputeOperationPending {
if !hcsshim.IsPending(err) {
logrus.Errorf("libcontainerd: failed to terminate %s - %q", containerID, err)
}
}
} else {
// Terminate Process
if err := cont.hcsProcess.Kill(); err != nil {
if err := cont.hcsProcess.Kill(); err != nil && !hcsshim.IsAlreadyStopped(err) {
// ignore errors
logrus.Warnf("libcontainerd: failed to terminate pid %d in %s: %q", cont.systemPid, containerID, err)
}

View file

@ -281,10 +281,10 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
func (ctr *container) shutdown() error {
const shutdownTimeout = time.Minute * 5
err := ctr.hcsContainer.Shutdown()
if err == hcsshim.ErrVmcomputeOperationPending {
if hcsshim.IsPending(err) {
// Explicit timeout to avoid a (remote) possibility that shutdown hangs indefinitely.
err = ctr.hcsContainer.WaitTimeout(shutdownTimeout)
} else if err == hcsshim.ErrVmcomputeAlreadyStopped {
} else if hcsshim.IsAlreadyStopped(err) {
err = nil
}
@ -303,9 +303,9 @@ func (ctr *container) terminate() error {
const terminateTimeout = time.Minute * 5
err := ctr.hcsContainer.Terminate()
if err == hcsshim.ErrVmcomputeOperationPending {
if hcsshim.IsPending(err) {
err = ctr.hcsContainer.WaitTimeout(terminateTimeout)
} else if err == hcsshim.ErrVmcomputeAlreadyStopped {
} else if hcsshim.IsAlreadyStopped(err) {
err = nil
}

View file

@ -15,6 +15,12 @@ type baseLayerWriter struct {
bw *winio.BackupFileWriter
err error
hasUtilityVM bool
dirInfo []dirInfo
}
type dirInfo struct {
path string
fileInfo winio.FileBasicInfo
}
func (w *baseLayerWriter) closeCurrentFile() error {
@ -69,17 +75,20 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
return err
}
createmode = syscall.OPEN_EXISTING
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
w.dirInfo = append(w.dirInfo, dirInfo{path, *fileInfo})
}
}
mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode)
if err != nil {
return err
return makeError(err, "Failed to OpenForBackup", path)
}
err = winio.SetFileBasicInfo(f, fileInfo)
if err != nil {
return err
return makeError(err, "Failed to SetFileBasicInfo", path)
}
w.f = f
@ -131,6 +140,22 @@ func (w *baseLayerWriter) Close() error {
return err
}
if w.err == nil {
// Restore the file times of all the directories, since they may have
// been modified by creating child directories.
for i := range w.dirInfo {
di := &w.dirInfo[len(w.dirInfo)-i-1]
f, err := winio.OpenForBackup(di.path, uint32(syscall.GENERIC_READ|syscall.GENERIC_WRITE), syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING)
if err != nil {
return makeError(err, "Failed to OpenForBackup", di.path)
}
err = winio.SetFileBasicInfo(f, &di.fileInfo)
f.Close()
if err != nil {
return makeError(err, "Failed to SetFileBasicInfo", di.path)
}
}
err = ProcessBaseLayer(w.root)
if err != nil {
return err

View file

@ -0,0 +1,7 @@
package hcsshim
import "C"
// This import is needed to make the library compile as CGO because HCSSHIM
// only works with CGO due to callbacks from HCS comming back from a C thread
// which is not supported without CGO. See https://github.com/golang/go/issues/10973

View file

@ -13,7 +13,10 @@ var (
defaultTimeout = time.Minute * 4
)
const pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}`
const (
pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}`
statisticsQuery = `{ "PropertyTypes" : ["Statistics"]}`
)
type container struct {
handle hcsSystem
@ -26,12 +29,59 @@ type containerProperties struct {
Name string
SystemType string
Owner string
SiloGUID string `json:"SiloGuid,omitempty"`
IsDummy bool `json:",omitempty"`
RuntimeID string `json:"RuntimeId,omitempty"`
Stopped bool `json:",omitempty"`
ExitType string `json:",omitempty"`
AreUpdatesPending bool `json:",omitempty"`
SiloGUID string `json:"SiloGuid,omitempty"`
IsDummy bool `json:",omitempty"`
RuntimeID string `json:"RuntimeId,omitempty"`
Stopped bool `json:",omitempty"`
ExitType string `json:",omitempty"`
AreUpdatesPending bool `json:",omitempty"`
ObRoot string `json:",omitempty"`
Statistics Statistics `json:",omitempty"`
}
// MemoryStats holds the memory statistics for a container
type MemoryStats struct {
UsageCommitBytes uint64 `json:"MemoryUsageCommitBytes,omitempty"`
UsageCommitPeakBytes uint64 `json:"MemoryUsageCommitPeakBytes,omitempty"`
UsagePrivateWorkingSetBytes uint64 `json:"MemoryUsagePrivateWorkingSetBytes,omitempty"`
}
// ProcessorStats holds the processor statistics for a container
type ProcessorStats struct {
TotalRuntime100ns uint64 `json:",omitempty"`
RuntimeUser100ns uint64 `json:",omitempty"`
RuntimeKernel100ns uint64 `json:",omitempty"`
}
// StorageStats holds the storage statistics for a container
type StorageStats struct {
ReadCountNormalized uint64 `json:",omitempty"`
ReadSizeBytes uint64 `json:",omitempty"`
WriteCountNormalized uint64 `json:",omitempty"`
WriteSizeBytes uint64 `json:",omitempty"`
}
// NetworkStats holds the network statistics for a container
type NetworkStats struct {
BytesReceived uint64 `json:",omitempty"`
BytesSent uint64 `json:",omitempty"`
PacketsReceived uint64 `json:",omitempty"`
PacketsSent uint64 `json:",omitempty"`
DroppedPacketsIncoming uint64 `json:",omitempty"`
DroppedPacketsOutgoing uint64 `json:",omitempty"`
EndpointId string `json:",omitempty"`
InstanceId string `json:",omitempty"`
}
// Statistics is the structure returned by a statistics call on a container
type Statistics struct {
Timestamp time.Time `json:",omitempty"`
ContainerStartTime time.Time `json:",omitempty"`
Uptime100ns uint64 `json:",omitempty"`
Memory MemoryStats `json:",omitempty"`
Processor ProcessorStats `json:",omitempty"`
Storage StorageStats `json:",omitempty"`
Network []NetworkStats `json:",omitempty"`
}
// CreateContainer creates a new container with the given configuration but does not start it.
@ -59,7 +109,7 @@ func CreateContainer(id string, c *ContainerConfig) (Container, error) {
var identity syscall.Handle
createError = hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp)
if createError == nil || createError == ErrVmcomputeOperationPending {
if createError == nil || IsPending(createError) {
if err := container.registerCallback(); err != nil {
return nil, makeContainerError(container, operation, "", err)
}
@ -122,8 +172,8 @@ func (container *container) Start() error {
return nil
}
// Shutdown requests a container shutdown, but it may not actually be shut down until Wait() succeeds.
// It returns ErrVmcomputeOperationPending if the shutdown is in progress, nil if the shutdown is complete.
// Shutdown requests a container shutdown, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds.
func (container *container) Shutdown() error {
operation := "Shutdown"
title := "HCSShim::Container::" + operation
@ -133,9 +183,6 @@ func (container *container) Shutdown() error {
err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp)
err = processHcsResult(err, resultp)
if err != nil {
if err == ErrVmcomputeOperationPending {
return ErrVmcomputeOperationPending
}
return makeContainerError(container, operation, "", err)
}
@ -143,8 +190,8 @@ func (container *container) Shutdown() error {
return nil
}
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
// It returns ErrVmcomputeOperationPending if the shutdown is in progress, nil if the shutdown is complete.
// Terminate requests a container terminate, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds.
func (container *container) Terminate() error {
operation := "Terminate"
title := "HCSShim::Container::" + operation
@ -154,9 +201,6 @@ func (container *container) Terminate() error {
err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp)
err = processHcsResult(err, resultp)
if err != nil {
if err == ErrVmcomputeOperationPending {
return ErrVmcomputeOperationPending
}
return makeContainerError(container, operation, "", err)
}
@ -190,8 +234,8 @@ func (container *container) waitTimeoutInternal(timeout uint32) (bool, error) {
return waitTimeoutInternalHelper(container, timeout)
}
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It returns
// ErrTimeout if the timeout duration expires before the container is shut down.
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse.
// If the timeout expires, IsTimeout(err) == true
func (container *container) WaitTimeout(timeout time.Duration) error {
operation := "WaitTimeout"
title := "HCSShim::Container::" + operation
@ -205,8 +249,9 @@ func (container *container) WaitTimeout(timeout time.Duration) error {
} else {
finished, err := waitTimeoutHelper(container, timeout)
if !finished {
return ErrTimeout
} else if err != nil {
err = ErrTimeout
}
if err != nil {
return makeContainerError(container, operation, "", err)
}
}
@ -246,12 +291,10 @@ func (container *container) properties(query string) (*containerProperties, erro
return nil, ErrUnexpectedValue
}
propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
properties := &containerProperties{}
if err := json.Unmarshal(propertiesRaw, properties); err != nil {
return nil, err
}
return properties, nil
}
@ -269,6 +312,20 @@ func (container *container) HasPendingUpdates() (bool, error) {
return properties.AreUpdatesPending, nil
}
// Statistics returns statistics for the container
func (container *container) Statistics() (Statistics, error) {
operation := "Statistics"
title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id)
properties, err := container.properties(statisticsQuery)
if err != nil {
return Statistics{}, makeContainerError(container, operation, "", err)
}
logrus.Debugf(title+" succeeded id=%s", container.id)
return properties.Statistics, nil
}
// Pause pauses the execution of the container. This feature is not enabled in TP5.
func (container *container) Pause() error {
operation := "Pause"
@ -323,7 +380,7 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
configurationb, err := json.Marshal(c)
if err != nil {
return nil, err
return nil, makeContainerError(container, operation, "", err)
}
configuration := string(configurationb)

View file

@ -1,22 +0,0 @@
package hcsshim
import "github.com/Sirupsen/logrus"
// CreateComputeSystem creates a container, initializing its configuration in
// the Host Compute Service such that it can be started by a call to the
// StartComputeSystem method.
func CreateComputeSystem(id string, configuration string) error {
title := "HCSShim::CreateComputeSystem"
logrus.Debugln(title+" id=%s, configuration=%s", id, configuration)
err := createComputeSystem(id, configuration)
if err != nil {
err = makeErrorf(err, title, "id=%s configuration=%s", id, configuration)
logrus.Error(err)
return err
}
logrus.Debugf(title+"- succeeded %s", id)
return nil
}

View file

@ -1,101 +0,0 @@
package hcsshim
import (
"encoding/json"
"io"
"syscall"
"github.com/Microsoft/go-winio"
"github.com/Sirupsen/logrus"
)
// CreateProcessParams is used as both the input of CreateProcessInComputeSystem
// and to convert the parameters to JSON for passing onto the HCS
type CreateProcessParams struct {
ApplicationName string
CommandLine string
WorkingDirectory string
Environment map[string]string
EmulateConsole bool
ConsoleSize [2]int
}
// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles
// if there is an error.
func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
fs := make([]io.ReadWriteCloser, len(hs))
for i, h := range hs {
if h != syscall.Handle(0) {
if err == nil {
fs[i], err = winio.MakeOpenFile(h)
}
if err != nil {
syscall.Close(h)
}
}
}
if err != nil {
for _, f := range fs {
if f != nil {
f.Close()
}
}
return nil, err
}
return fs, nil
}
// CreateProcessInComputeSystem starts a process in a container. This is invoked, for example,
// as a result of docker run, docker exec, or RUN in Dockerfile. If successful,
// it returns the PID of the process.
func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useStderr bool, params CreateProcessParams) (_ uint32, _ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
title := "HCSShim::CreateProcessInComputeSystem"
logrus.Debugf(title+" id=%s", id)
// If we are not emulating a console, ignore any console size passed to us
if !params.EmulateConsole {
params.ConsoleSize[0] = 0
params.ConsoleSize[1] = 0
}
paramsJson, err := json.Marshal(params)
if err != nil {
return
}
logrus.Debugf(title+" - Calling Win32 %s %s", id, paramsJson)
var pid uint32
handles := make([]syscall.Handle, 3)
var stdinParam, stdoutParam, stderrParam *syscall.Handle
if useStdin {
stdinParam = &handles[0]
}
if useStdout {
stdoutParam = &handles[1]
}
if useStderr {
stderrParam = &handles[2]
}
err = createProcessWithStdHandlesInComputeSystem(id, string(paramsJson), &pid, stdinParam, stdoutParam, stderrParam)
if err != nil {
herr := makeErrorf(err, title, "id=%s params=%v", id, params)
// Windows TP4: Hyper-V Containers may return this error with more than one
// concurrent exec. Do not log it as an error
if err != WSAEINVAL {
logrus.Error(herr)
}
err = herr
return
}
pipes, err := makeOpenFiles(handles)
if err != nil {
return
}
logrus.Debugf(title+" - succeeded id=%s params=%s pid=%d", id, paramsJson, pid)
return pid, pipes[0], pipes[1], pipes[2], nil
}

View file

@ -4,12 +4,16 @@ import (
"errors"
"fmt"
"syscall"
"github.com/Sirupsen/logrus"
)
var (
// ErrHandleClose is an error returned when the handle generating the notification being waited on has been closed
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists
ErrComputeSystemDoesNotExist = syscall.Errno(0xc037010e)
// ErrElementNotFound is an error encountered when the object being referenced does not exist
ErrElementNotFound = syscall.Errno(0x490)
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
@ -21,22 +25,28 @@ var (
// ErrTimeout is an error encountered when waiting on a notification times out
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
// ErrUnexpectedContainerExit is the error returned when a container exits while waiting for
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
// a different expected notification
ErrUnexpectedContainerExit = errors.New("unexpected container exit")
// ErrUnexpectedProcessAbort is the error returned when communication with the compute service
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
// is lost while waiting for a notification
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
// ErrUnexpectedValue is an error returned when hcs returns an invalid value
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
// ErrVmcomputeAlreadyStopped is an error returned when a shutdown or terminate request is made on a stopped container
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
// ErrVmcomputeOperationPending is an error returned when the operation is being completed asynchronously
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105)
// ErrProcNotFound is an error encountered when the the process cannot be found
ErrProcNotFound = syscall.Errno(0x7f)
)
// ProcessError is an error encountered in HCS during an operation on a Process object
@ -55,23 +65,6 @@ type ContainerError struct {
Err error
}
func isKnownError(err error) bool {
// Don't wrap errors created in hcsshim
if err == ErrHandleClose ||
err == ErrInvalidNotificationType ||
err == ErrInvalidProcessState ||
err == ErrTimeout ||
err == ErrUnexpectedContainerExit ||
err == ErrUnexpectedProcessAbort ||
err == ErrUnexpectedValue ||
err == ErrVmcomputeAlreadyStopped ||
err == ErrVmcomputeOperationPending {
return true
}
return false
}
func (e *ContainerError) Error() string {
if e == nil {
return "<nil>"
@ -99,14 +92,11 @@ func (e *ContainerError) Error() string {
}
func makeContainerError(container *container, operation string, extraInfo string, err error) error {
// Return known errors to the client
if isKnownError(err) {
// Don't double wrap errors
if _, ok := err.(*ContainerError); ok {
return err
}
// Log any unexpected errors
containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
logrus.Error(containerError)
return containerError
}
@ -129,21 +119,72 @@ func (e *ProcessError) Error() string {
s += " " + e.Operation
}
if e.Err != nil {
switch e.Err.(type) {
case nil:
break
case syscall.Errno:
s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
default:
s += fmt.Sprintf(" failed: %s", e.Error())
}
return s
}
func makeProcessError(process *process, operation string, extraInfo string, err error) error {
// Return known errors to the client
if isKnownError(err) {
// Don't double wrap errors
if _, ok := err.(*ProcessError); ok {
return err
}
// Log any unexpected errors
processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
logrus.Error(processError)
return processError
}
// IsNotExist checks if an error is caused by the Container or Process not existing.
// Note: Currently, ErrElementNotFound can mean that a Process has either
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
func IsNotExist(err error) bool {
err = getInnerError(err)
return err == ErrComputeSystemDoesNotExist ||
err == ErrElementNotFound ||
err == ErrProcNotFound
}
// IsPending returns a boolean indicating whether the error is that
// the requested operation is being completed in the background.
func IsPending(err error) bool {
err = getInnerError(err)
return err == ErrVmcomputeOperationPending
}
// IsTimeout returns a boolean indicating whether the error is caused by
// a timeout waiting for the operation to complete.
func IsTimeout(err error) bool {
err = getInnerError(err)
return err == ErrTimeout
}
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
// a Container or Process being already stopped.
// Note: Currently, ErrElementNotFound can mean that a Process has either
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
func IsAlreadyStopped(err error) bool {
err = getInnerError(err)
return err == ErrVmcomputeAlreadyStopped ||
err == ErrElementNotFound ||
err == ErrProcNotFound
}
func getInnerError(err error) error {
switch pe := err.(type) {
case nil:
return nil
case *ContainerError:
err = pe.Err
case *ProcessError:
err = pe.Err
}
return err
}

View file

@ -1,43 +0,0 @@
package hcsshim
import (
"encoding/json"
"github.com/Sirupsen/logrus"
)
// ComputeSystemProperties is a struct describing the returned properties.
type ComputeSystemProperties struct {
ID string
Name string
Stopped bool
AreUpdatesPending bool
}
// GetComputeSystemProperties gets the properties for the compute system with the given ID.
func GetComputeSystemProperties(id string, flags uint32) (ComputeSystemProperties, error) {
title := "hcsshim::GetComputeSystemProperties "
csProps := ComputeSystemProperties{
Stopped: false,
AreUpdatesPending: false,
}
logrus.Debugf("Calling proc")
var buffer *uint16
err := getComputeSystemProperties(id, flags, &buffer)
if err != nil {
err = makeError(err, title, "")
logrus.Error(err)
return csProps, err
}
propData := convertAndFreeCoTaskMemString(buffer)
logrus.Debugf(title+" - succeeded output=%s", propData)
if err = json.Unmarshal([]byte(propData), &csProps); err != nil {
logrus.Error(err)
return csProps, err
}
return csProps, nil
}

View file

@ -90,6 +90,9 @@ type Container interface {
// HasPendingUpdates returns true if the container has updates pending to install.
HasPendingUpdates() (bool, error)
// Statistics returns statistics for a container.
Statistics() (Statistics, error)
// CreateProcess launches a new process within the container.
CreateProcess(c *ProcessConfig) (Process, error)

View file

@ -71,9 +71,7 @@ func (process *process) Kill() error {
var resultp *uint16
err := hcsTerminateProcess(process.handle, &resultp)
err = processHcsResult(err, resultp)
if err == ErrVmcomputeOperationPending {
return ErrVmcomputeOperationPending
} else if err != nil {
if err != nil {
return makeProcessError(process, operation, "", err)
}
@ -118,8 +116,9 @@ func (process *process) WaitTimeout(timeout time.Duration) error {
} else {
finished, err := waitTimeoutHelper(process, timeout)
if !finished {
return ErrTimeout
} else if err != nil {
err = ErrTimeout
}
if err != nil {
return makeProcessError(process, operation, "", err)
}
}
@ -160,7 +159,7 @@ func (process *process) ExitCode() (int, error) {
}
if properties.Exited == false {
return 0, ErrInvalidProcessState
return 0, makeProcessError(process, operation, "", ErrInvalidProcessState)
}
logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode)
@ -211,7 +210,7 @@ func (process *process) properties() (*processStatus, error) {
err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
err = processHcsResult(err, resultp)
if err != nil {
return nil, makeProcessError(process, operation, "", err)
return nil, err
}
if propertiesp == nil {
@ -260,7 +259,7 @@ func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e
pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr})
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, makeProcessError(process, operation, "", err)
}
logrus.Debugf(title+" succeeded processid=%d", process.processID)

View file

@ -1,22 +0,0 @@
package hcsshim
import "github.com/Sirupsen/logrus"
// ResizeConsoleInComputeSystem updates the height and width of the console
// session for the process with the given id in the container with the given id.
func ResizeConsoleInComputeSystem(id string, processid uint32, h, w int) error {
title := "HCSShim::ResizeConsoleInComputeSystem"
logrus.Debugf(title+" id=%s processid=%d (%d,%d)", id, processid, h, w)
err := resizeConsoleInComputeSystem(id, processid, uint16(h), uint16(w), 0)
if err != nil {
err = makeErrorf(err, title, "id=%s pid=%d", id, processid)
logrus.Error(err)
return err
}
logrus.Debugf(title+" succeeded id=%s processid=%d (%d,%d)", id, processid, h, w)
return nil
}

View file

@ -1,43 +0,0 @@
package hcsshim
import "github.com/Sirupsen/logrus"
// TerminateComputeSystem force terminates a container.
func TerminateComputeSystem(id string, timeout uint32, context string) error {
return shutdownTerminate(false, id, timeout, context)
}
// ShutdownComputeSystem shuts down a container by requesting a shutdown within
// the container operating system.
func ShutdownComputeSystem(id string, timeout uint32, context string) error {
return shutdownTerminate(true, id, timeout, context)
}
// shutdownTerminate is a wrapper for ShutdownComputeSystem and TerminateComputeSystem
// which have very similar calling semantics
func shutdownTerminate(shutdown bool, id string, timeout uint32, context string) error {
var (
title = "HCSShim::"
)
if shutdown {
title = title + "ShutdownComputeSystem"
} else {
title = title + "TerminateComputeSystem"
}
logrus.Debugf(title+" id=%s context=%s", id, context)
var err error
if shutdown {
err = shutdownComputeSystem(id, timeout)
} else {
err = terminateComputeSystem(id)
}
if err != nil {
return makeErrorf(err, title, "id=%s context=%s", id, context)
}
logrus.Debugf(title+" succeeded id=%s context=%s", id, context)
return nil
}

View file

@ -1,21 +0,0 @@
package hcsshim
import "github.com/Sirupsen/logrus"
// StartComputeSystem starts a container that has previously been created via
// CreateComputeSystem.
func StartComputeSystem(id string) error {
title := "HCSShim::StartComputeSystem"
logrus.Debugf(title+" id=%s", id)
err := startComputeSystem(id)
if err != nil {
err = makeErrorf(err, title, "id=%s", id)
logrus.Error(err)
return err
}
logrus.Debugf(title+" succeeded id=%s", id)
return nil
}

View file

@ -1,20 +0,0 @@
package hcsshim
import "github.com/Sirupsen/logrus"
// TerminateProcessInComputeSystem kills a process in a running container.
func TerminateProcessInComputeSystem(id string, processid uint32) (err error) {
title := "HCSShim::TerminateProcessInComputeSystem"
logrus.Debugf(title+" id=%s processid=%d", id, processid)
err = terminateProcessInComputeSystem(id, processid)
if err != nil {
err = makeErrorf(err, title, "err=%s id=%s", id)
logrus.Error(err)
return err
}
logrus.Debugf(title+" succeeded id=%s", id)
return nil
}

View file

@ -1,7 +1,10 @@
package hcsshim
import (
"io"
"syscall"
"github.com/Microsoft/go-winio"
)
var (
@ -9,3 +12,28 @@ var (
hcsCallbackAPI = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback")
hcsCallbacksSupported = hcsCallbackAPI.Find() == nil
)
// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles
// if there is an error.
func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
fs := make([]io.ReadWriteCloser, len(hs))
for i, h := range hs {
if h != syscall.Handle(0) {
if err == nil {
fs[i], err = winio.MakeOpenFile(h)
}
if err != nil {
syscall.Close(h)
}
}
}
if err != nil {
for _, f := range fs {
if f != nil {
f.Close()
}
}
return nil, err
}
return fs, nil
}

View file

@ -50,7 +50,7 @@ func waitForSingleObject(handle syscall.Handle, timeout uint32) (bool, error) {
func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
err = processHcsResult(err, resultp)
if err == ErrVmcomputeOperationPending {
if IsPending(err) {
return waitForNotification(callbackNumber, expectedNotification, timeout)
}

View file

@ -1,20 +0,0 @@
package hcsshim
import "github.com/Sirupsen/logrus"
// WaitForProcessInComputeSystem waits for a process ID to terminate and returns
// the exit code. Returns exitcode, error
func WaitForProcessInComputeSystem(id string, processid uint32, timeout uint32) (int32, error) {
title := "HCSShim::WaitForProcessInComputeSystem"
logrus.Debugf(title+" id=%s processid=%d", id, processid)
var exitCode uint32
err := waitForProcessInComputeSystem(id, processid, timeout, &exitCode)
if err != nil {
return 0, makeErrorf(err, title, "id=%s", id)
}
logrus.Debugf(title+" succeeded id=%s processid=%d exitcode=%d", id, processid, exitCode)
return int32(exitCode), nil
}