diff --git a/hack/vendor.sh b/hack/vendor.sh index 8e5ceeb7f9..31964d813c 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -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.2.2 +clone git github.com/Microsoft/hcsshim v0.3.0 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 diff --git a/libcontainerd/client_windows.go b/libcontainerd/client_windows.go index ddf8543e33..c362bccaa4 100644 --- a/libcontainerd/client_windows.go +++ b/libcontainerd/client_windows.go @@ -1,7 +1,6 @@ package libcontainerd import ( - "encoding/json" "errors" "fmt" "io" @@ -29,76 +28,6 @@ const ( ErrorInvalidObject = syscall.Errno(0x800710D8) // The object identifier does not represent a valid object ) -type layer struct { - ID string - Path string -} - -type defConfig struct { - DefFile string -} - -type portBinding struct { - Protocol string - InternalPort int - ExternalPort int -} - -type natSettings struct { - Name string - PortBindings []portBinding -} - -type networkConnection struct { - NetworkName string - Nat natSettings -} -type networkSettings struct { - MacAddress string -} - -type device struct { - DeviceType string - Connection interface{} - Settings interface{} -} - -type mappedDir struct { - HostPath string - ContainerPath string - ReadOnly bool -} - -type hvRuntime struct { - ImagePath string `json:",omitempty"` -} - -// TODO Windows: @darrenstahlmsft Add ProcessorCount -type containerInit struct { - SystemType string // HCS requires this to be hard-coded to "Container" - Name string // Name of the container. We use the docker ID. - Owner string // The management platform that created this container - IsDummy bool // Used for development purposes. - VolumePath string // Windows volume path for scratch space - Devices []device // Devices used by the container - IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows - LayerFolderPath string // Where the layer folders are located - Layers []layer // List of storage layers - ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default. - ProcessorMaximum int64 `json:",omitempty"` // CPU maximum usage percent 1..100 - StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS - StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second - StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller - MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes - HostName string // Hostname - MappedDirectories []mappedDir // List of mapped directories (volumes/mounts) - SandboxPath string // Location of unmounted sandbox (used for Hyper-V containers) - HvPartition bool // True if it a Hyper-V Container - EndpointList []string // List of networking endpoints to be attached to container - HvRuntime *hvRuntime // Hyper-V container settings - Servicing bool // True if this container is for servicing -} - // defaultOwner is a tag passed to HCS to allow it to differentiate between // container creator management stacks. We hard code "docker" in the case // of docker. @@ -109,7 +38,7 @@ const defaultOwner = "docker" func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) error { logrus.Debugln("LCD client.Create() with spec", spec) - cu := &containerInit{ + configuration := &hcsshim.ContainerConfig{ SystemType: "Container", Name: containerID, Owner: defaultOwner, @@ -121,55 +50,55 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio } if spec.Windows.Networking != nil { - cu.EndpointList = spec.Windows.Networking.EndpointList + configuration.EndpointList = spec.Windows.Networking.EndpointList } if spec.Windows.Resources != nil { if spec.Windows.Resources.CPU != nil { if spec.Windows.Resources.CPU.Shares != nil { - cu.ProcessorWeight = *spec.Windows.Resources.CPU.Shares + configuration.ProcessorWeight = *spec.Windows.Resources.CPU.Shares } if spec.Windows.Resources.CPU.Percent != nil { - cu.ProcessorMaximum = *spec.Windows.Resources.CPU.Percent * 100 // ProcessorMaximum is a value between 1 and 10000 + configuration.ProcessorMaximum = *spec.Windows.Resources.CPU.Percent * 100 // ProcessorMaximum is a value between 1 and 10000 } } if spec.Windows.Resources.Memory != nil { if spec.Windows.Resources.Memory.Limit != nil { - cu.MemoryMaximumInMB = *spec.Windows.Resources.Memory.Limit / 1024 / 1024 + configuration.MemoryMaximumInMB = *spec.Windows.Resources.Memory.Limit / 1024 / 1024 } } if spec.Windows.Resources.Storage != nil { if spec.Windows.Resources.Storage.Bps != nil { - cu.StorageBandwidthMaximum = *spec.Windows.Resources.Storage.Bps + configuration.StorageBandwidthMaximum = *spec.Windows.Resources.Storage.Bps } if spec.Windows.Resources.Storage.Iops != nil { - cu.StorageIOPSMaximum = *spec.Windows.Resources.Storage.Iops + configuration.StorageIOPSMaximum = *spec.Windows.Resources.Storage.Iops } if spec.Windows.Resources.Storage.SandboxSize != nil { - cu.StorageSandboxSize = *spec.Windows.Resources.Storage.SandboxSize + configuration.StorageSandboxSize = *spec.Windows.Resources.Storage.SandboxSize } } } if spec.Windows.HvRuntime != nil { - cu.HvPartition = true - cu.HvRuntime = &hvRuntime{ + configuration.HvPartition = true + configuration.HvRuntime = &hcsshim.HvRuntime{ ImagePath: spec.Windows.HvRuntime.ImagePath, } } - for _, option := range options { - if s, ok := option.(*ServicingOption); ok { - cu.Servicing = s.IsServicing - break - } + if configuration.HvPartition { + configuration.SandboxPath = filepath.Dir(spec.Windows.LayerFolder) + } else { + configuration.VolumePath = spec.Root.Path + configuration.LayerFolderPath = spec.Windows.LayerFolder } - if cu.HvPartition { - cu.SandboxPath = filepath.Dir(spec.Windows.LayerFolder) - } else { - cu.VolumePath = spec.Root.Path - cu.LayerFolderPath = spec.Windows.LayerFolder + for _, option := range options { + if s, ok := option.(*ServicingOption); ok { + configuration.Servicing = s.IsServicing + break + } } for _, layerPath := range spec.Windows.LayerPaths { @@ -178,33 +107,27 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio if err != nil { return err } - cu.Layers = append(cu.Layers, layer{ + configuration.Layers = append(configuration.Layers, hcsshim.Layer{ ID: g.ToString(), Path: layerPath, }) } // Add the mounts (volumes, bind mounts etc) to the structure - mds := make([]mappedDir, len(spec.Mounts)) + mds := make([]hcsshim.MappedDir, len(spec.Mounts)) for i, mount := range spec.Mounts { - mds[i] = mappedDir{ + mds[i] = hcsshim.MappedDir{ HostPath: mount.Source, ContainerPath: mount.Destination, ReadOnly: mount.Readonly} } - cu.MappedDirectories = mds + configuration.MappedDirectories = mds - configurationb, err := json.Marshal(cu) + hcsContainer, err := hcsshim.CreateContainer(containerID, configuration) if err != nil { return err } - // Create the compute system - configuration := string(configurationb) - if err := hcsshim.CreateComputeSystem(containerID, configuration); err != nil { - return err - } - // Construct a container object for calling start on it. container := &container{ containerCommon: containerCommon{ @@ -218,7 +141,8 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio }, processes: make(map[string]*process), }, - ociSpec: spec, + ociSpec: spec, + hcsContainer: hcsContainer, } container.options = options @@ -252,10 +176,17 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd if err != nil { return err } - - createProcessParms := hcsshim.CreateProcessParams{ - EmulateConsole: procToAdd.Terminal, - ConsoleSize: procToAdd.InitialConsoleSize, + // Note we always tell HCS to + // create stdout as it's required regardless of '-i' or '-t' options, so that + // docker can always grab the output through logs. We also tell HCS to always + // create stdin, even if it's not used - it will be closed shortly. Stderr + // is only created if it we're not -t. + createProcessParms := hcsshim.ProcessConfig{ + EmulateConsole: procToAdd.Terminal, + ConsoleSize: procToAdd.InitialConsoleSize, + CreateStdInPipe: true, + CreateStdOutPipe: true, + CreateStdErrPipe: !procToAdd.Terminal, } // Take working directory from the process to add if it is defined, @@ -272,25 +203,24 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd logrus.Debugf("commandLine: %s", createProcessParms.CommandLine) - // Start the command running in the container. Note we always tell HCS to - // create stdout as it's required regardless of '-i' or '-t' options, so that - // docker can always grab the output through logs. We also tell HCS to always - // create stdin, even if it's not used - it will be closed shortly. Stderr - // is only created if it we're not -t. + // Start the command running in the container. var stdout, stderr io.ReadCloser - var pid uint32 - iopipe := &IOPipe{Terminal: procToAdd.Terminal} - pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem( - containerID, - true, - true, - !procToAdd.Terminal, - createProcessParms) + var stdin io.WriteCloser + newProcess, err := container.hcsContainer.CreateProcess(&createProcessParms) if err != nil { - logrus.Errorf("AddProcess %s CreateProcessInComputeSystem() failed %s", containerID, err) + logrus.Errorf("AddProcess %s CreateProcess() failed %s", containerID, err) return err } + stdin, stdout, stderr, err = newProcess.Stdio() + if err != nil { + logrus.Errorf("%s getting std pipes failed %s", containerID, err) + return err + } + + iopipe := &IOPipe{Terminal: procToAdd.Terminal} + iopipe.Stdin = createStdInCloser(stdin, newProcess) + // TEMP: Work around Windows BS/DEL behavior. iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, procToAdd.Terminal) @@ -302,17 +232,21 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd iopipe.Stderr = openReaderFromPipe(stderr) } - // Add the process to the containers list of processes - container.processes[processFriendlyName] = - &process{ - processCommon: processCommon{ - containerID: containerID, - friendlyName: processFriendlyName, - client: clnt, - systemPid: pid, - }, - commandLine: createProcessParms.CommandLine, - } + pid := newProcess.Pid() + + proc := &process{ + processCommon: processCommon{ + containerID: containerID, + friendlyName: processFriendlyName, + client: clnt, + systemPid: uint32(pid), + }, + commandLine: createProcessParms.CommandLine, + hcsProcess: newProcess, + } + + // Add the process to the container's list of processes + container.processes[processFriendlyName] = proc // Make sure the lock is not held while calling back into the daemon clnt.unlock(containerID) @@ -326,7 +260,7 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd clnt.lock(containerID) // Spin up a go routine waiting for exit to handle cleanup - go container.waitExit(pid, processFriendlyName, false) + go container.waitExit(proc, false) return nil } @@ -350,16 +284,17 @@ func (clnt *client) Signal(containerID string, sig int) error { cont.manualStopRequested = true logrus.Debugf("lcd: Signal() containerID=%s sig=%d pid=%d", containerID, sig, cont.systemPid) - context := fmt.Sprintf("Signal: sig=%d pid=%d", sig, cont.systemPid) if syscall.Signal(sig) == syscall.SIGKILL { // Terminate the compute system - if err := hcsshim.TerminateComputeSystem(containerID, hcsshim.TimeoutInfinite, context); err != nil { - logrus.Errorf("Failed to terminate %s - %q", containerID, err) + if err := cont.hcsContainer.Terminate(); err != nil { + if err != hcsshim.ErrVmcomputeOperationPending { + logrus.Errorf("Failed to terminate %s - %q", containerID, err) + } } } else { // Terminate Process - if err = hcsshim.TerminateProcessInComputeSystem(containerID, cont.systemPid); err != nil { + if err := cont.hcsProcess.Kill(); err != nil { logrus.Warnf("Failed to terminate pid %d in %s: %q", cont.systemPid, containerID, err) // Ignore errors err = nil @@ -380,15 +315,17 @@ func (clnt *client) Resize(containerID, processFriendlyName string, width, heigh return err } + h, w := uint16(height), uint16(width) + if processFriendlyName == InitFriendlyName { logrus.Debugln("Resizing systemPID in", containerID, cont.process.systemPid) - return hcsshim.ResizeConsoleInComputeSystem(containerID, cont.process.systemPid, height, width) + return cont.process.hcsProcess.ResizeConsole(w, h) } for _, p := range cont.processes { if p.friendlyName == processFriendlyName { logrus.Debugln("Resizing exec'd process", containerID, p.systemPid) - return hcsshim.ResizeConsoleInComputeSystem(containerID, p.systemPid, height, width) + return p.hcsProcess.ResizeConsole(w, h) } } diff --git a/libcontainerd/container_windows.go b/libcontainerd/container_windows.go index e1f64a1704..d772130354 100644 --- a/libcontainerd/container_windows.go +++ b/libcontainerd/container_windows.go @@ -22,6 +22,7 @@ type container struct { ociSpec Spec manualStopRequested bool + hcsContainer hcsshim.Container } func (ctr *container) newProcess(friendlyName string) *process { @@ -40,7 +41,7 @@ func (ctr *container) start() error { // Start the container. If this is a servicing container, this call will block // until the container is done with the servicing execution. logrus.Debugln("Starting container ", ctr.containerID) - if err = hcsshim.StartComputeSystem(ctr.containerID); err != nil { + if err = ctr.hcsContainer.Start(); err != nil { logrus.Errorf("Failed to start compute system: %s", err) return err } @@ -49,59 +50,61 @@ func (ctr *container) start() error { if s, ok := option.(*ServicingOption); ok && s.IsServicing { // Since the servicing operation is complete when StartCommputeSystem returns without error, // we can shutdown (which triggers merge) and exit early. - const shutdownTimeout = 5 * 60 * 1000 // 4 minutes - const terminateTimeout = 1 * 60 * 1000 // 1 minute - if err := hcsshim.ShutdownComputeSystem(ctr.containerID, shutdownTimeout, ""); err != nil { - logrus.Errorf("Failed during cleanup of servicing container: %s", err) - // Terminate the container, ignoring errors. - if err2 := hcsshim.TerminateComputeSystem(ctr.containerID, terminateTimeout, ""); err2 != nil { - logrus.Errorf("Failed to terminate container %s after shutdown failure: %q", ctr.containerID, err2) - } - return err - } - return nil + return ctr.shutdown() } } - createProcessParms := hcsshim.CreateProcessParams{ + // Note we always tell HCS to + // create stdout as it's required regardless of '-i' or '-t' options, so that + // docker can always grab the output through logs. We also tell HCS to always + // create stdin, even if it's not used - it will be closed shortly. Stderr + // is only created if it we're not -t. + createProcessParms := &hcsshim.ProcessConfig{ EmulateConsole: ctr.ociSpec.Process.Terminal, WorkingDirectory: ctr.ociSpec.Process.Cwd, ConsoleSize: ctr.ociSpec.Process.InitialConsoleSize, + CreateStdInPipe: true, + CreateStdOutPipe: true, + CreateStdErrPipe: !ctr.ociSpec.Process.Terminal, } // Configure the environment for the process createProcessParms.Environment = setupEnvironmentVariables(ctr.ociSpec.Process.Env) createProcessParms.CommandLine = strings.Join(ctr.ociSpec.Process.Args, " ") - iopipe := &IOPipe{Terminal: ctr.ociSpec.Process.Terminal} - - // Start the command running in the container. Note we always tell HCS to - // create stdout as it's required regardless of '-i' or '-t' options, so that - // docker can always grab the output through logs. We also tell HCS to always - // create stdin, even if it's not used - it will be closed shortly. Stderr - // is only created if it we're not -t. - var pid uint32 - var stdout, stderr io.ReadCloser - pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem( - ctr.containerID, - true, - true, - !ctr.ociSpec.Process.Terminal, - createProcessParms) + // Start the command running in the container. + hcsProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms) if err != nil { - logrus.Errorf("CreateProcessInComputeSystem() failed %s", err) - - // Explicitly terminate the compute system here. - if err2 := hcsshim.TerminateComputeSystem(ctr.containerID, hcsshim.TimeoutInfinite, "CreateProcessInComputeSystem failed"); err2 != nil { - // Ignore this error, there's not a lot we can do except log it - logrus.Warnf("Failed to TerminateComputeSystem after a failed CreateProcessInComputeSystem. Ignoring this.", err2) + logrus.Errorf("CreateProcess() failed %s", err) + if err2 := ctr.terminate(); err2 != nil { + logrus.Debugf("Failed to cleanup after a failed CreateProcess. Ignoring this. %s", err2) } else { - logrus.Debugln("Cleaned up after failed CreateProcessInComputeSystem by calling TerminateComputeSystem") + logrus.Debugln("Cleaned up after failed CreateProcess by calling Terminate") } return err } ctr.startedAt = time.Now() + // Save the hcs Process and PID + ctr.process.friendlyName = InitFriendlyName + pid := hcsProcess.Pid() + ctr.process.hcsProcess = hcsProcess + + var stdout, stderr io.ReadCloser + var stdin io.WriteCloser + stdin, stdout, stderr, err = hcsProcess.Stdio() + if err != nil { + logrus.Errorf("failed to get stdio pipes: %s", err) + if err := ctr.terminate(); err != nil { + logrus.Debugf("Failed to cleanup after a failed CreateProcess. Ignoring this. %s", err) + } + return err + } + + iopipe := &IOPipe{Terminal: ctr.ociSpec.Process.Terminal} + + iopipe.Stdin = createStdInCloser(stdin, hcsProcess) + // TEMP: Work around Windows BS/DEL behavior. iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, ctr.ociSpec.Process.Terminal) @@ -118,7 +121,7 @@ func (ctr *container) start() error { ctr.systemPid = uint32(pid) // Spin up a go routine waiting for exit to handle cleanup - go ctr.waitExit(pid, InitFriendlyName, true) + go ctr.waitExit(&ctr.process, true) ctr.client.appendContainer(ctr) @@ -140,17 +143,27 @@ func (ctr *container) start() error { // waitExit runs as a goroutine waiting for the process to exit. It's // equivalent to (in the linux containerd world) where events come in for // state change notifications from containerd. -func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstProcessToStart bool) error { - logrus.Debugln("waitExit on pid", pid) +func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) error { + logrus.Debugln("waitExit on pid", process.systemPid) // Block indefinitely for the process to exit. - exitCode, err := hcsshim.WaitForProcessInComputeSystem(ctr.containerID, pid, hcsshim.TimeoutInfinite) + err := process.hcsProcess.Wait() if err != nil { - if herr, ok := err.(*hcsshim.HcsError); ok && herr.Err != syscall.ERROR_BROKEN_PIPE { + if herr, ok := err.(*hcsshim.ProcessError); ok && herr.Err != syscall.ERROR_BROKEN_PIPE { logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): %s", err) } // Fall through here, do not return. This ensures we attempt to continue the - // shutdown in HCS nad tell the docker engine that the process/container + // shutdown in HCS and tell the docker engine that the process/container + // has exited to avoid a container being dropped on the floor. + } + + exitCode, err := process.hcsProcess.ExitCode() + if err != nil { + if herr, ok := err.(*hcsshim.ProcessError); ok && herr.Err != syscall.ERROR_BROKEN_PIPE { + logrus.Warnf("Unable to get exit code from container %s", ctr.containerID) + } + // Fall through here, do not return. This ensures we attempt to continue the + // shutdown in HCS and tell the docker engine that the process/container // has exited to avoid a container being dropped on the floor. } @@ -159,46 +172,35 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr CommonStateInfo: CommonStateInfo{ State: StateExit, ExitCode: uint32(exitCode), - Pid: pid, - ProcessID: processFriendlyName, + Pid: process.systemPid, + ProcessID: process.friendlyName, }, UpdatePending: false, } // But it could have been an exec'd process which exited if !isFirstProcessToStart { + if err := process.hcsProcess.Close(); err != nil { + logrus.Error(err) + } si.State = StateExitProcess } else { - // Since this is the init process, always call into vmcompute.dll to - // shutdown the container after we have completed. - - propertyCheckFlag := 1 // Include update pending check. - csProperties, err := hcsshim.GetComputeSystemProperties(ctr.containerID, uint32(propertyCheckFlag)) + updatePending, err := ctr.hcsContainer.HasPendingUpdates() if err != nil { - logrus.Warnf("GetComputeSystemProperties failed (container may have been killed): %s", err) + logrus.Warnf("HasPendingUpdates failed (container may have been killed): %s", err) } else { - si.UpdatePending = csProperties.AreUpdatesPending + si.UpdatePending = updatePending } logrus.Debugf("Shutting down container %s", ctr.containerID) - // Explicit timeout here rather than hcsshim.TimeoutInfinte to avoid a - // (remote) possibility that ShutdownComputeSystem hangs indefinitely. - const shutdownTimeout = 5 * 60 * 1000 // 5 minutes - if err := hcsshim.ShutdownComputeSystem(ctr.containerID, shutdownTimeout, "waitExit"); err != nil { - if herr, ok := err.(*hcsshim.HcsError); !ok || - (herr.Err != hcsshim.ERROR_SHUTDOWN_IN_PROGRESS && - herr.Err != ErrorBadPathname && - herr.Err != syscall.ERROR_PATH_NOT_FOUND) { - logrus.Debugf("waitExit - error from ShutdownComputeSystem on %s %v. Calling TerminateComputeSystem", ctr.containerCommon, err) - if err := hcsshim.TerminateComputeSystem(ctr.containerID, shutdownTimeout, "waitExit"); err != nil { - logrus.Debugf("waitExit - ignoring error from TerminateComputeSystem %s %v", ctr.containerID, err) - } else { - logrus.Debugf("Successful TerminateComputeSystem after failed ShutdownComputeSystem on %s in waitExit", ctr.containerID) - } - } + if err := ctr.shutdown(); err != nil { + logrus.Debugf("Failed to shutdown container %s", ctr.containerID) } else { logrus.Debugf("Completed shutting down container %s", ctr.containerID) } + if err := ctr.hcsContainer.Close(); err != nil { + logrus.Error(err) + } if !ctr.manualStopRequested && ctr.restartManager != nil { restart, wait, err := ctr.restartManager.ShouldRestart(uint32(exitCode), false, time.Since(ctr.startedAt)) @@ -227,6 +229,9 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr // Remove process from list if we have exited // We need to do so here in case the Message Handler decides to restart it. if si.State == StateExit { + if err := ctr.hcsContainer.Close(); err != nil { + logrus.Error(err) + } ctr.client.deleteContainer(ctr.friendlyName) } } @@ -240,3 +245,37 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr logrus.Debugln("waitExit() completed OK") return nil } + +func (ctr *container) shutdown() error { + const shutdownTimeout = time.Minute * 5 + err := ctr.hcsContainer.Shutdown() + if err == hcsshim.ErrVmcomputeOperationPending { + // Explicit timeout to avoid a (remote) possibility that shutdown hangs indefinitely. + err = ctr.hcsContainer.WaitTimeout(shutdownTimeout) + } + + if err != nil { + logrus.Debugf("error shutting down container %s %v calling terminate", ctr.containerID, err) + if err := ctr.terminate(); err != nil { + return err + } + return err + } + + return nil +} + +func (ctr *container) terminate() error { + const terminateTimeout = time.Minute * 5 + err := ctr.hcsContainer.Terminate() + + if err == hcsshim.ErrVmcomputeOperationPending { + err = ctr.hcsContainer.WaitTimeout(terminateTimeout) + } + + if err != nil { + return err + } + + return nil +} diff --git a/libcontainerd/process_windows.go b/libcontainerd/process_windows.go index 12593bba67..119dac9852 100644 --- a/libcontainerd/process_windows.go +++ b/libcontainerd/process_windows.go @@ -3,6 +3,7 @@ package libcontainerd import ( "io" + "github.com/Microsoft/hcsshim" "github.com/docker/docker/pkg/system" ) @@ -14,6 +15,7 @@ type process struct { // commandLine is to support returning summary information for docker top commandLine string + hcsProcess hcsshim.Process } func openReaderFromPipe(p io.ReadCloser) io.Reader { @@ -57,3 +59,27 @@ func (w *delToBsWriter) Write(b []byte) (int, error) { } return w.WriteCloser.Write(bc) } + +type stdInCloser struct { + io.WriteCloser + hcsshim.Process +} + +func createStdInCloser(pipe io.WriteCloser, process hcsshim.Process) *stdInCloser { + return &stdInCloser{ + WriteCloser: pipe, + Process: process, + } +} + +func (stdin *stdInCloser) Close() error { + if err := stdin.WriteCloser.Close(); err != nil { + return err + } + + return stdin.Process.CloseStdin() +} + +func (stdin *stdInCloser) Write(p []byte) (n int, err error) { + return stdin.WriteCloser.Write(p) +} diff --git a/vendor/src/github.com/Microsoft/hcsshim/baselayer.go b/vendor/src/github.com/Microsoft/hcsshim/baselayer.go index 4e88c76501..63bde87a4b 100644 --- a/vendor/src/github.com/Microsoft/hcsshim/baselayer.go +++ b/vendor/src/github.com/Microsoft/hcsshim/baselayer.go @@ -62,20 +62,17 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e } }() - err = winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) { - createmode := uint32(syscall.CREATE_NEW) - if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - err := os.Mkdir(path, 0) - if err != nil && !os.IsExist(err) { - return err - } - createmode = syscall.OPEN_EXISTING + createmode := uint32(syscall.CREATE_NEW) + if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + err := os.Mkdir(path, 0) + if err != nil && !os.IsExist(err) { + return err } + createmode = syscall.OPEN_EXISTING + } - 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) - return - }) + 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 } @@ -113,9 +110,7 @@ func (w *baseLayerWriter) AddLink(name string, target string) (err error) { return err } - return winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) { - return os.Link(linktarget, linkpath) - }) + return os.Link(linktarget, linkpath) } func (w *baseLayerWriter) Remove(name string) error { @@ -123,11 +118,7 @@ func (w *baseLayerWriter) Remove(name string) error { } func (w *baseLayerWriter) Write(b []byte) (int, error) { - var n int - err := winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) { - n, err = w.bw.Write(b) - return - }) + n, err := w.bw.Write(b) if err != nil { w.err = err } diff --git a/vendor/src/github.com/Microsoft/hcsshim/callback.go b/vendor/src/github.com/Microsoft/hcsshim/callback.go new file mode 100644 index 0000000000..122db1db18 --- /dev/null +++ b/vendor/src/github.com/Microsoft/hcsshim/callback.go @@ -0,0 +1,78 @@ +package hcsshim + +import ( + "errors" + "sync" + "syscall" +) + +var ( + nextCallback uintptr + callbackMap = map[uintptr]*notifcationWatcherContext{} + callbackMapLock = sync.RWMutex{} + + notificationWatcherCallback = syscall.NewCallback(notificationWatcher) + + // Notifications for HCS_SYSTEM handles + hcsNotificationSystemExited hcsNotification = 0x00000001 + hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002 + hcsNotificationSystemStartCompleted hcsNotification = 0x00000003 + hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004 + hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005 + + // Notifications for HCS_PROCESS handles + hcsNotificationProcessExited hcsNotification = 0x00010000 + + // Common notifications + hcsNotificationInvalid hcsNotification = 0x00000000 + hcsNotificationServiceDisconnect hcsNotification = 0x01000000 + + // ErrUnexpectedContainerExit is the error returned 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 + // is lost while waiting for a notification + ErrUnexpectedProcessAbort = errors.New("lost communication with compute service") +) + +type hcsNotification uint32 +type notificationChannel chan error + +type notifcationWatcherContext struct { + channel notificationChannel + expectedNotification hcsNotification + handle hcsCallback +} + +func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr { + var ( + result error + completeWait = false + ) + + callbackMapLock.RLock() + context := callbackMap[callbackNumber] + callbackMapLock.RUnlock() + + if notificationType == context.expectedNotification { + if int32(notificationStatus) < 0 { + result = syscall.Errno(win32FromHresult(notificationStatus)) + } else { + result = nil + } + completeWait = true + } else if notificationType == hcsNotificationSystemExited { + result = ErrUnexpectedContainerExit + completeWait = true + } else if notificationType == hcsNotificationServiceDisconnect { + result = ErrUnexpectedProcessAbort + completeWait = true + } + + if completeWait { + context.channel <- result + } + + return 0 +} diff --git a/vendor/src/github.com/Microsoft/hcsshim/container.go b/vendor/src/github.com/Microsoft/hcsshim/container.go new file mode 100644 index 0000000000..24b2327ddf --- /dev/null +++ b/vendor/src/github.com/Microsoft/hcsshim/container.go @@ -0,0 +1,513 @@ +package hcsshim + +import ( + "encoding/json" + "errors" + "fmt" + "runtime" + "syscall" + "time" + + "github.com/Sirupsen/logrus" +) + +var ( + defaultTimeout = time.Minute * 4 + + // ErrTimeout is an error encountered when waiting on a notification times out + ErrTimeout = errors.New("hcsshim: timeout waiting for notification") +) + +type ContainerError struct { + Container *container + Operation string + ExtraInfo string + Err error +} + +type container struct { + handle hcsSystem + id string +} + +type containerProperties struct { + ID string `json:"Id"` + 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"` +} + +// CreateContainer creates a new container with the given configuration but does not start it. +func CreateContainer(id string, c *ContainerConfig) (Container, error) { + operation := "CreateContainer" + title := "HCSShim::" + operation + logrus.Debugf(title+" id=%s", id) + + container := &container{ + id: id, + } + + configurationb, err := json.Marshal(c) + if err != nil { + return nil, err + } + + configuration := string(configurationb) + + var ( + handle hcsSystem + resultp *uint16 + createError error + ) + if hcsCallbacksSupported { + var identity syscall.Handle + createError = hcsCreateComputeSystem(id, configuration, identity, &handle, &resultp) + } else { + createError = hcsCreateComputeSystemTP5(id, configuration, &handle, &resultp) + } + container.handle = handle + + err = processAsyncHcsResult(container, createError, resultp, hcsNotificationSystemCreateCompleted, &defaultTimeout) + if err != nil { + err := &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err} + logrus.Error(err) + return nil, err + } + + logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle) + runtime.SetFinalizer(container, closeContainer) + return container, nil +} + +// OpenContainer opens an existing container by ID. +func OpenContainer(id string) (Container, error) { + operation := "OpenContainer" + title := "HCSShim::" + operation + logrus.Debugf(title+" id=%s", id) + + container := &container{ + id: id, + } + + var ( + handle hcsSystem + resultp *uint16 + ) + err := hcsOpenComputeSystem(id, &handle, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + err = &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return nil, err + } + + container.handle = handle + + logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle) + runtime.SetFinalizer(container, closeContainer) + return container, nil +} + +// Start synchronously starts the container. +func (container *container) Start() error { + operation := "Start" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsStartComputeSystemTP5(container.handle, nil, &resultp) + err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemStartCompleted, &defaultTimeout) + if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + 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. +func (container *container) Shutdown() error { + operation := "Shutdown" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + if err == ErrVmcomputeOperationPending { + return ErrVmcomputeOperationPending + } + err = &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + 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. +func (container *container) Terminate() error { + operation := "Terminate" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + if err == ErrVmcomputeOperationPending { + return ErrVmcomputeOperationPending + } + err = &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// Wait synchronously waits for the container to shutdown or terminate. +func (container *container) Wait() error { + operation := "Wait" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + if hcsCallbacksSupported { + err := registerAndWaitForCallback(container, hcsNotificationSystemExited) + if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + } else { + _, err := container.waitTimeoutInternal(syscall.INFINITE) + if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +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. +func (container *container) WaitTimeout(timeout time.Duration) error { + operation := "WaitTimeout" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + if hcsCallbacksSupported { + err := registerAndWaitForCallbackTimeout(container, hcsNotificationSystemExited, timeout) + if err == ErrTimeout { + return ErrTimeout + } else if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + } else { + finished, err := waitTimeoutHelper(container, timeout) + if !finished { + return ErrTimeout + } else if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +func (container *container) hcsWait(timeout uint32) (bool, error) { + var ( + resultp *uint16 + exitEvent syscall.Handle + ) + + err := hcsCreateComputeSystemWait(container.handle, &exitEvent, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return false, err + } + defer syscall.CloseHandle(exitEvent) + + return waitForSingleObject(exitEvent, timeout) +} + +func (container *container) properties() (*containerProperties, error) { + var ( + resultp *uint16 + propertiesp *uint16 + ) + err := hcsGetComputeSystemProperties(container.handle, "", &propertiesp, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return nil, err + } + + if propertiesp == nil { + return nil, errors.New("Unexpected result from hcsGetComputeSystemProperties, properties should never be nil") + } + propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) + + properties := &containerProperties{} + if err := json.Unmarshal(propertiesRaw, properties); err != nil { + return nil, err + } + + return properties, nil +} + +// HasPendingUpdates returns true if the container has updates pending to install +func (container *container) HasPendingUpdates() (bool, error) { + operation := "HasPendingUpdates" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + properties, err := container.properties() + if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return false, err + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return properties.AreUpdatesPending, nil +} + +// Pause pauses the execution of the container. This feature is not enabled in TP5. +func (container *container) Pause() error { + operation := "Pause" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + var resultp *uint16 + err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp) + err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemPauseCompleted, &defaultTimeout) + if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// Resume resumes the execution of the container. This feature is not enabled in TP5. +func (container *container) Resume() error { + operation := "Resume" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + var ( + resultp *uint16 + ) + + err := hcsResumeComputeSystemTP5(container.handle, nil, &resultp) + err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemResumeCompleted, &defaultTimeout) + if err != nil { + err := &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// CreateProcess launches a new process within the container. +func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { + operation := "CreateProcess" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + var ( + processInfo hcsProcessInformation + processHandle hcsProcess + resultp *uint16 + ) + + // If we are not emulating a console, ignore any console size passed to us + if !c.EmulateConsole { + c.ConsoleSize[0] = 0 + c.ConsoleSize[1] = 0 + } + + configurationb, err := json.Marshal(c) + if err != nil { + return nil, err + } + + configuration := string(configurationb) + + err = hcsCreateProcess(container.handle, configuration, &processInfo, &processHandle, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + err = &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err} + logrus.Error(err) + return nil, err + } + + process := &process{ + handle: processHandle, + processID: int(processInfo.ProcessId), + container: container, + cachedPipes: &cachedPipes{ + stdIn: processInfo.StdInput, + stdOut: processInfo.StdOutput, + stdErr: processInfo.StdError, + }, + } + + logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) + runtime.SetFinalizer(process, closeProcess) + return process, nil +} + +// OpenProcess gets an interface to an existing process within the container. +func (container *container) OpenProcess(pid int) (Process, error) { + operation := "OpenProcess" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s, processid=%d", container.id, pid) + var ( + processHandle hcsProcess + resultp *uint16 + ) + + err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + err = &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return nil, err + } + + process := &process{ + handle: processHandle, + processID: pid, + container: container, + } + + logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) + runtime.SetFinalizer(process, closeProcess) + return process, nil +} + +// Close cleans up any state associated with the container but does not terminate or wait for it. +func (container *container) Close() error { + operation := "Close" + title := "HCSShim::Container::" + operation + logrus.Debugf(title+" id=%s", container.id) + + // Don't double free this + if container.handle == 0 { + return nil + } + + if err := hcsCloseComputeSystem(container.handle); err != nil { + err = &ContainerError{Container: container, Operation: operation, Err: err} + logrus.Error(err) + return err + } + + container.handle = 0 + + logrus.Debugf(title+" succeeded id=%s", container.id) + return nil +} + +// closeContainer wraps container.Close for use by a finalizer +func closeContainer(container *container) { + container.Close() +} + +func (container *container) registerCallback(expectedNotification hcsNotification) (uintptr, error) { + callbackMapLock.Lock() + defer callbackMapLock.Unlock() + + callbackNumber := nextCallback + nextCallback++ + + context := ¬ifcationWatcherContext{ + expectedNotification: expectedNotification, + channel: make(chan error, 1), + } + callbackMap[callbackNumber] = context + + var callbackHandle hcsCallback + err := hcsRegisterComputeSystemCallback(container.handle, notificationWatcherCallback, callbackNumber, &callbackHandle) + if err != nil { + return 0, err + } + context.handle = callbackHandle + + return callbackNumber, nil +} + +func (container *container) unregisterCallback(callbackNumber uintptr) error { + callbackMapLock.Lock() + defer callbackMapLock.Unlock() + + handle := callbackMap[callbackNumber].handle + + if handle == 0 { + return nil + } + + err := hcsUnregisterComputeSystemCallback(handle) + if err != nil { + return err + } + + callbackMap[callbackNumber] = nil + + handle = 0 + + return nil +} + +func (e *ContainerError) Error() string { + if e == nil { + return "" + } + + if e.Container == nil { + return "unexpected nil container for error: " + e.Err.Error() + } + + s := "container " + e.Container.id + + if e.Operation != "" { + s += " encountered an error during " + e.Operation + } + + if e.Err != nil { + s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) + } + + if e.ExtraInfo != "" { + s += " extra info: " + e.ExtraInfo + } + + return s +} diff --git a/vendor/src/github.com/Microsoft/hcsshim/exportlayer.go b/vendor/src/github.com/Microsoft/hcsshim/exportlayer.go index b7615b4c68..903e08519d 100644 --- a/vendor/src/github.com/Microsoft/hcsshim/exportlayer.go +++ b/vendor/src/github.com/Microsoft/hcsshim/exportlayer.go @@ -112,7 +112,9 @@ func (r *FilterLayerReader) Close() (err error) { } // NewLayerReader returns a new layer reader for reading the contents of an on-disk layer. -func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) (LayerReader, error) { +// The caller must have taken the SeBackupPrivilege privilege +// to call this and any methods on the resulting LayerReader. +func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string) (LayerReader, error) { if procExportLayerBegin.Find() != nil { // The new layer reader is not available on this Windows build. Fall back to the // legacy export code path. @@ -120,7 +122,7 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) if err != nil { return nil, err } - err = ExportLayer(info, layerId, path, parentLayerPaths) + err = ExportLayer(info, layerID, path, parentLayerPaths) if err != nil { os.RemoveAll(path) return nil, err @@ -137,7 +139,7 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) return nil, err } r := &FilterLayerReader{} - err = exportLayerBegin(&infop, layerId, layers, &r.context) + err = exportLayerBegin(&infop, layerID, layers, &r.context) if err != nil { return nil, makeError(err, "ExportLayerBegin", "") } diff --git a/vendor/src/github.com/Microsoft/hcsshim/hcsshim.go b/vendor/src/github.com/Microsoft/hcsshim/hcsshim.go index 1ea04e06bd..e077844838 100644 --- a/vendor/src/github.com/Microsoft/hcsshim/hcsshim.go +++ b/vendor/src/github.com/Microsoft/hcsshim/hcsshim.go @@ -7,6 +7,8 @@ import ( "fmt" "syscall" "unsafe" + + "github.com/Sirupsen/logrus" ) //go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go @@ -50,6 +52,40 @@ import ( //sys waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) = vmcompute.WaitForProcessInComputeSystem? //sys getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) = vmcompute.GetComputeSystemProperties? +//sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems? +//sys hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem? +//sys hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem? +//sys hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) = vmcompute.HcsCloseComputeSystem? +//sys hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem? +//sys hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem? +//sys hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem? +//sys hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem? +//sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? +//sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties? +//sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem? +//sys hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystemWait? +//sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess? +//sys hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess? +//sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess? +//sys hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) = vmcompute.HcsTerminateProcess? +//sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo? +//sys hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties? +//sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess? +//sys hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateProcessWait? +//sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties? +//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings? + +//sys hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem? +//sys hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem? +//sys hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem? +//sys hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem? +//sys hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem? +//sys hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? +//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback? +//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback? +//sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback? +//sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback? + //sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall? const ( @@ -60,6 +96,8 @@ const ( ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115) WSAEINVAL = syscall.Errno(10022) + ErrVmcomputeOperationPending = syscall.Errno(0xC0370103) + // Timeout on wait calls TimeoutInfinite = 0xFFFFFFFF ) @@ -70,6 +108,18 @@ type HcsError struct { Err error } +type hcsSystem syscall.Handle +type hcsProcess syscall.Handle +type hcsCallback syscall.Handle + +type hcsProcessInformation struct { + ProcessId uint32 + Reserved uint32 + StdInput syscall.Handle + StdOutput syscall.Handle + StdError syscall.Handle +} + func makeError(err error, title, rest string) error { // Pass through DLL errors directly since they do not originate from HCS. if _, ok := err.(*syscall.DLLError); ok { @@ -119,3 +169,15 @@ func convertAndFreeCoTaskMemString(buffer *uint16) string { coTaskMemFree(unsafe.Pointer(buffer)) return str } + +func convertAndFreeCoTaskMemBytes(buffer *uint16) []byte { + return []byte(convertAndFreeCoTaskMemString(buffer)) +} + +func processHcsResult(err error, resultp *uint16) error { + if resultp != nil { + result := convertAndFreeCoTaskMemString(resultp) + logrus.Debugf("Result: %s", result) + } + return err +} diff --git a/vendor/src/github.com/Microsoft/hcsshim/importlayer.go b/vendor/src/github.com/Microsoft/hcsshim/importlayer.go index d108cb3797..42d7270448 100644 --- a/vendor/src/github.com/Microsoft/hcsshim/importlayer.go +++ b/vendor/src/github.com/Microsoft/hcsshim/importlayer.go @@ -148,6 +148,8 @@ func (r *legacyLayerWriterWrapper) Close() error { } // NewLayerWriter returns a new layer writer for creating a layer on disk. +// The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges +// to call this and any methods on the resulting LayerWriter. func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) { if len(parentLayerPaths) == 0 { // This is a base layer. It gets imported differently. diff --git a/vendor/src/github.com/Microsoft/hcsshim/interface.go b/vendor/src/github.com/Microsoft/hcsshim/interface.go new file mode 100644 index 0000000000..74270d39f8 --- /dev/null +++ b/vendor/src/github.com/Microsoft/hcsshim/interface.go @@ -0,0 +1,147 @@ +package hcsshim + +import ( + "io" + "time" +) + +// ProcessConfig is used as both the input of Container.CreateProcess +// and to convert the parameters to JSON for passing onto the HCS +type ProcessConfig struct { + ApplicationName string + CommandLine string + WorkingDirectory string + Environment map[string]string + EmulateConsole bool + CreateStdInPipe bool + CreateStdOutPipe bool + CreateStdErrPipe bool + ConsoleSize [2]int +} + +type Layer struct { + ID string + Path string +} + +type MappedDir struct { + HostPath string + ContainerPath string + ReadOnly bool +} + +type HvRuntime struct { + ImagePath string `json:",omitempty"` +} + +// ContainerConfig is used as both the input of CreateContainer +// and to convert the parameters to JSON for passing onto the HCS +// TODO Windows: @darrenstahlmsft Add ProcessorCount +type ContainerConfig struct { + SystemType string // HCS requires this to be hard-coded to "Container" + Name string // Name of the container. We use the docker ID. + Owner string // The management platform that created this container + IsDummy bool // Used for development purposes. + VolumePath string // Windows volume path for scratch space + IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows + LayerFolderPath string // Where the layer folders are located + Layers []Layer // List of storage layers + ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default. + ProcessorMaximum int64 `json:",omitempty"` // CPU maximum usage percent 1..100 + StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS + StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second + StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller + MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes + HostName string // Hostname + MappedDirectories []MappedDir // List of mapped directories (volumes/mounts) + SandboxPath string // Location of unmounted sandbox (used for Hyper-V containers) + HvPartition bool // True if it a Hyper-V Container + EndpointList []string // List of networking endpoints to be attached to container + HvRuntime *HvRuntime // Hyper-V container settings + Servicing bool // True if this container is for servicing +} + +const ( + notificationTypeNone string = "None" + notificationTypeGracefulExit string = "GracefulExit" + notificationTypeForcedExit string = "ForcedExit" + notificationTypeUnexpectedExit string = "UnexpectedExit" + notificationTypeReboot string = "Reboot" + notificationTypeConstructed string = "Constructed" + notificationTypeStarted string = "Started" + notificationTypePaused string = "Paused" + notificationTypeUnknown string = "Unknown" +) + +// Container represents a created (but not necessarily running) container. +type Container interface { + // Start synchronously starts the container. + Start() error + + // Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds. + Shutdown() error + + // Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds. + Terminate() error + + // Waits synchronously waits for the container to shutdown or terminate. + Wait() error + + // WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It + // returns false if timeout occurs. + WaitTimeout(time.Duration) error + + // Pause pauses the execution of a container. + Pause() error + + // Resume resumes the execution of a container. + Resume() error + + // HasPendingUpdates returns true if the container has updates pending to install. + HasPendingUpdates() (bool, error) + + // CreateProcess launches a new process within the container. + CreateProcess(c *ProcessConfig) (Process, error) + + // OpenProcess gets an interface to an existing process within the container. + OpenProcess(pid int) (Process, error) + + // Close cleans up any state associated with the container but does not terminate or wait for it. + Close() error +} + +// Process represents a running or exited process. +type Process interface { + // Pid returns the process ID of the process within the container. + Pid() int + + // Kill signals the process to terminate but does not wait for it to finish terminating. + Kill() error + + // Wait waits for the process to exit. + Wait() error + + // WaitTimeout waits for the process to exit or the duration to elapse. It returns + // false if timeout occurs. + WaitTimeout(time.Duration) error + + // ExitCode returns the exit code of the process. The process must have + // already terminated. + ExitCode() (int, error) + + // ResizeConsole resizes the console of the process. + ResizeConsole(width, height uint16) error + + // Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing + // these pipes does not close the underlying pipes; it should be possible to + // call this multiple times to get multiple interfaces. + Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) + + // CloseStdin closes the write side of the stdin pipe so that the process is + // notified on the read side that there is no more data in stdin. + CloseStdin() error + + // Close cleans up any state associated with the process but does not kill + // or wait on it. + Close() error +} diff --git a/vendor/src/github.com/Microsoft/hcsshim/mksyscall_windows.go b/vendor/src/github.com/Microsoft/hcsshim/mksyscall_windows.go index 7c9a00110a..a76bb4414c 100644 --- a/vendor/src/github.com/Microsoft/hcsshim/mksyscall_windows.go +++ b/vendor/src/github.com/Microsoft/hcsshim/mksyscall_windows.go @@ -598,6 +598,19 @@ func (f *Fn) HasStringParam() bool { return false } +var uniqDllFuncName = make(map[string]bool) + +// IsNotDuplicate is true if f is not a duplicated function +func (f *Fn) IsNotDuplicate() bool { + funcName := f.DLLFuncName() + if uniqDllFuncName[funcName] == false { + uniqDllFuncName[funcName] = true + return true + } + + return false +} + // HelperName returns name of function f helper. func (f *Fn) HelperName() string { if !f.HasStringParam() { @@ -748,6 +761,7 @@ const srcTemplate = ` package {{packagename}} +import "github.com/Microsoft/go-winio" import "unsafe"{{if syscalldot}} import "syscall"{{end}} @@ -764,7 +778,7 @@ var ( {{define "dlls"}}{{range .DLLs}} mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll") {{end}}{{end}} -{{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}") +{{define "funcnames"}}{{range .Funcs}}{{if .IsNotDuplicate}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}"){{end}} {{end}}{{end}} {{define "helperbody"}} diff --git a/vendor/src/github.com/Microsoft/hcsshim/process.go b/vendor/src/github.com/Microsoft/hcsshim/process.go new file mode 100644 index 0000000000..a6941939f6 --- /dev/null +++ b/vendor/src/github.com/Microsoft/hcsshim/process.go @@ -0,0 +1,432 @@ +package hcsshim + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "syscall" + "time" + + "github.com/Sirupsen/logrus" +) + +var ( + ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation") +) + +type ProcessError struct { + Process *process + Operation string + Err error +} + +type process struct { + handle hcsProcess + processID int + container *container + cachedPipes *cachedPipes + killCallbackNumber uintptr +} + +type cachedPipes struct { + stdIn syscall.Handle + stdOut syscall.Handle + stdErr syscall.Handle +} + +type processModifyRequest struct { + Operation string + ConsoleSize *consoleSize `json:",omitempty"` + CloseHandle *closeHandle `json:",omitempty"` +} + +type consoleSize struct { + Height uint16 + Width uint16 +} + +type closeHandle struct { + Handle string +} + +type processStatus struct { + ProcessId uint32 + Exited bool + ExitCode uint32 + LastWaitResult int32 +} + +const ( + stdIn string = "StdIn" + stdOut string = "StdOut" + stdErr string = "StdErr" +) + +const ( + modifyConsoleSize string = "ConsoleSize" + modifyCloseHandle string = "CloseHandle" +) + +// Pid returns the process ID of the process within the container. +func (process *process) Pid() int { + return process.processID +} + +// Kill signals the process to terminate but does not wait for it to finish terminating. +func (process *process) Kill() error { + operation := "Kill" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + var resultp *uint16 + err := hcsTerminateProcess(process.handle, &resultp) + err = processHcsResult(err, resultp) + if err == ErrVmcomputeOperationPending { + return ErrVmcomputeOperationPending + } else if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// Wait waits for the process to exit. +func (process *process) Wait() error { + operation := "Wait" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + if hcsCallbacksSupported { + err := registerAndWaitForCallback(process, hcsNotificationProcessExited) + if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + } else { + _, err := process.waitTimeoutInternal(syscall.INFINITE) + if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// WaitTimeout waits for the process to exit or the duration to elapse. It returns +// false if timeout occurs. +func (process *process) WaitTimeout(timeout time.Duration) error { + operation := "WaitTimeout" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + if hcsCallbacksSupported { + err := registerAndWaitForCallbackTimeout(process, hcsNotificationProcessExited, timeout) + if err == ErrTimeout { + return ErrTimeout + } else if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + } else { + finished, err := waitTimeoutHelper(process, timeout) + if !finished { + return ErrTimeout + } else if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +func (process *process) hcsWait(timeout uint32) (bool, error) { + var ( + resultp *uint16 + exitEvent syscall.Handle + ) + err := hcsCreateProcessWait(process.handle, &exitEvent, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + return false, err + } + defer syscall.CloseHandle(exitEvent) + + return waitForSingleObject(exitEvent, timeout) +} + +func (process *process) waitTimeoutInternal(timeout uint32) (bool, error) { + return waitTimeoutInternalHelper(process, timeout) +} + +// ExitCode returns the exit code of the process. The process must have +// already terminated. +func (process *process) ExitCode() (int, error) { + operation := "ExitCode" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + properties, err := process.properties() + if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return 0, err + } + + if properties.Exited == false { + return 0, ErrInvalidProcessState + } + + logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode) + return int(properties.ExitCode), nil +} + +// ResizeConsole resizes the console of the process. +func (process *process) ResizeConsole(width, height uint16) error { + operation := "ResizeConsole" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + modifyRequest := processModifyRequest{ + Operation: modifyConsoleSize, + ConsoleSize: &consoleSize{ + Height: height, + Width: width, + }, + } + + modifyRequestb, err := json.Marshal(modifyRequest) + if err != nil { + return err + } + + modifyRequestStr := string(modifyRequestb) + + var resultp *uint16 + err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +func (process *process) properties() (*processStatus, error) { + operation := "properties" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + var ( + resultp *uint16 + propertiesp *uint16 + ) + err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + err := &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return nil, err + } + + if propertiesp == nil { + return nil, errors.New("Unexpected result from hcsGetProcessProperties, properties should never be nil") + } + propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) + + properties := &processStatus{} + if err := json.Unmarshal(propertiesRaw, properties); err != nil { + return nil, err + } + + logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw) + return properties, nil +} + +// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing +// these pipes does not close the underlying pipes; it should be possible to +// call this multiple times to get multiple interfaces. +func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { + operation := "Stdio" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + var stdIn, stdOut, stdErr syscall.Handle + + if process.cachedPipes == nil { + var ( + processInfo hcsProcessInformation + resultp *uint16 + ) + err := hcsGetProcessInfo(process.handle, &processInfo, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + err = &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return nil, nil, nil, err + } + + stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError + } else { + // Use cached pipes + stdIn, stdOut, stdErr = process.cachedPipes.stdIn, process.cachedPipes.stdOut, process.cachedPipes.stdErr + + // Invalidate the cache + process.cachedPipes = nil + } + + pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr}) + if err != nil { + return nil, nil, nil, err + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return pipes[0], pipes[1], pipes[2], nil +} + +// CloseStdin closes the write side of the stdin pipe so that the process is +// notified on the read side that there is no more data in stdin. +func (process *process) CloseStdin() error { + operation := "CloseStdin" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + modifyRequest := processModifyRequest{ + Operation: modifyCloseHandle, + CloseHandle: &closeHandle{ + Handle: stdIn, + }, + } + + modifyRequestb, err := json.Marshal(modifyRequest) + if err != nil { + return err + } + + modifyRequestStr := string(modifyRequestb) + + var resultp *uint16 + err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp) + err = processHcsResult(err, resultp) + if err != nil { + err = &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// Close cleans up any state associated with the process but does not kill +// or wait on it. +func (process *process) Close() error { + operation := "Close" + title := "HCSShim::Process::" + operation + logrus.Debugf(title+" processid=%d", process.processID) + + // Don't double free this + if process.handle == 0 { + return nil + } + + if err := hcsCloseProcess(process.handle); err != nil { + err = &ProcessError{Operation: operation, Process: process, Err: err} + logrus.Error(err) + return err + } + + process.handle = 0 + + logrus.Debugf(title+" succeeded processid=%d", process.processID) + return nil +} + +// closeProcess wraps process.Close for use by a finalizer +func closeProcess(process *process) { + process.Close() +} + +func (process *process) registerCallback(expectedNotification hcsNotification) (uintptr, error) { + callbackMapLock.Lock() + defer callbackMapLock.Unlock() + + callbackNumber := nextCallback + nextCallback++ + + context := ¬ifcationWatcherContext{ + expectedNotification: expectedNotification, + channel: make(chan error, 1), + } + callbackMap[callbackNumber] = context + + var callbackHandle hcsCallback + err := hcsRegisterProcessCallback(process.handle, notificationWatcherCallback, callbackNumber, &callbackHandle) + if err != nil { + return 0, err + } + context.handle = callbackHandle + + return callbackNumber, nil +} + +func (process *process) unregisterCallback(callbackNumber uintptr) error { + callbackMapLock.Lock() + defer callbackMapLock.Unlock() + handle := callbackMap[callbackNumber].handle + + if handle == 0 { + return nil + } + + err := hcsUnregisterProcessCallback(handle) + if err != nil { + return err + } + + callbackMap[callbackNumber] = nil + + handle = 0 + + return nil +} + +func (e *ProcessError) Error() string { + if e == nil { + return "" + } + + if e.Process == nil { + return "Unexpected nil process for error: " + e.Err.Error() + } + + s := fmt.Sprintf("process %d", e.Process.processID) + + if e.Process.container != nil { + s += " in container " + e.Process.container.id + } + + if e.Operation != "" { + s += " " + e.Operation + } + + if e.Err != nil { + s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) + } + + return s +} diff --git a/vendor/src/github.com/Microsoft/hcsshim/utils.go b/vendor/src/github.com/Microsoft/hcsshim/utils.go new file mode 100644 index 0000000000..694b001977 --- /dev/null +++ b/vendor/src/github.com/Microsoft/hcsshim/utils.go @@ -0,0 +1,11 @@ +package hcsshim + +import ( + "syscall" +) + +var ( + vmcomputedll = syscall.NewLazyDLL("vmcompute.dll") + hcsCallbackAPI = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback") + hcsCallbacksSupported = hcsCallbackAPI.Find() == nil +) diff --git a/vendor/src/github.com/Microsoft/hcsshim/waithelper.go b/vendor/src/github.com/Microsoft/hcsshim/waithelper.go new file mode 100644 index 0000000000..d36325a2df --- /dev/null +++ b/vendor/src/github.com/Microsoft/hcsshim/waithelper.go @@ -0,0 +1,113 @@ +package hcsshim + +import ( + "syscall" + "time" +) + +type waitable interface { + waitTimeoutInternal(timeout uint32) (bool, error) + hcsWait(timeout uint32) (bool, error) +} + +type callbackable interface { + registerCallback(expectedNotification hcsNotification) (uintptr, error) + unregisterCallback(callbackNumber uintptr) error +} + +func waitTimeoutHelper(object waitable, timeout time.Duration) (bool, error) { + var ( + millis uint32 + ) + + for totalMillis := uint64(timeout / time.Millisecond); totalMillis > 0; totalMillis = totalMillis - uint64(millis) { + if totalMillis >= syscall.INFINITE { + millis = syscall.INFINITE - 1 + } else { + millis = uint32(totalMillis) + } + + result, err := object.waitTimeoutInternal(millis) + + if err != nil { + return result, err + } + } + return true, nil +} + +func waitTimeoutInternalHelper(object waitable, timeout uint32) (bool, error) { + return object.hcsWait(timeout) +} + +func waitForSingleObject(handle syscall.Handle, timeout uint32) (bool, error) { + s, e := syscall.WaitForSingleObject(handle, timeout) + switch s { + case syscall.WAIT_OBJECT_0: + return true, nil + case syscall.WAIT_TIMEOUT: + return false, nil + default: + return false, e + } +} + +func processAsyncHcsResult(object callbackable, err error, resultp *uint16, expectedNotification hcsNotification, timeout *time.Duration) error { + err = processHcsResult(err, resultp) + if err == ErrVmcomputeOperationPending { + if timeout != nil { + err = registerAndWaitForCallbackTimeout(object, expectedNotification, *timeout) + } else { + err = registerAndWaitForCallback(object, expectedNotification) + } + } + + return err +} + +func registerAndWaitForCallbackTimeout(object callbackable, expectedNotification hcsNotification, timeout time.Duration) error { + callbackNumber, err := object.registerCallback(expectedNotification) + if err != nil { + return err + } + defer object.unregisterCallback(callbackNumber) + + return waitForNotificationTimeout(callbackNumber, timeout) +} + +func registerAndWaitForCallback(object callbackable, expectedNotification hcsNotification) error { + callbackNumber, err := object.registerCallback(expectedNotification) + if err != nil { + return err + } + defer object.unregisterCallback(callbackNumber) + + return waitForNotification(callbackNumber) +} + +func waitForNotificationTimeout(callbackNumber uintptr, timeout time.Duration) error { + callbackMapLock.RLock() + channel := callbackMap[callbackNumber].channel + callbackMapLock.RUnlock() + + timer := time.NewTimer(timeout) + defer timer.Stop() + + select { + case err := <-channel: + return err + case <-timer.C: + return ErrTimeout + } +} + +func waitForNotification(callbackNumber uintptr) error { + callbackMapLock.RLock() + channel := callbackMap[callbackNumber].channel + callbackMapLock.RUnlock() + + select { + case err := <-channel: + return err + } +} diff --git a/vendor/src/github.com/Microsoft/hcsshim/zhcsshim.go b/vendor/src/github.com/Microsoft/hcsshim/zhcsshim.go index f5eb2d68b4..da5a8e9852 100644 --- a/vendor/src/github.com/Microsoft/hcsshim/zhcsshim.go +++ b/vendor/src/github.com/Microsoft/hcsshim/zhcsshim.go @@ -2,11 +2,8 @@ package hcsshim -import ( - "unsafe" - - "github.com/Microsoft/go-winio" -) +import "github.com/Microsoft/go-winio" +import "unsafe" import "syscall" var _ unsafe.Pointer @@ -49,7 +46,34 @@ var ( procTerminateProcessInComputeSystem = modvmcompute.NewProc("TerminateProcessInComputeSystem") procWaitForProcessInComputeSystem = modvmcompute.NewProc("WaitForProcessInComputeSystem") procGetComputeSystemProperties = modvmcompute.NewProc("GetComputeSystemProperties") - procHNSCall = modvmcompute.NewProc("HNSCall") + procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems") + procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem") + procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem") + procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem") + procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem") + procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem") + procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem") + procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem") + procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem") + procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties") + procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem") + procHcsCreateComputeSystemWait = modvmcompute.NewProc("HcsCreateComputeSystemWait") + procHcsCreateProcess = modvmcompute.NewProc("HcsCreateProcess") + procHcsOpenProcess = modvmcompute.NewProc("HcsOpenProcess") + procHcsCloseProcess = modvmcompute.NewProc("HcsCloseProcess") + procHcsTerminateProcess = modvmcompute.NewProc("HcsTerminateProcess") + procHcsGetProcessInfo = modvmcompute.NewProc("HcsGetProcessInfo") + procHcsGetProcessProperties = modvmcompute.NewProc("HcsGetProcessProperties") + procHcsModifyProcess = modvmcompute.NewProc("HcsModifyProcess") + procHcsCreateProcessWait = modvmcompute.NewProc("HcsCreateProcessWait") + procHcsGetServiceProperties = modvmcompute.NewProc("HcsGetServiceProperties") + procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") + + procHcsRegisterComputeSystemCallback = modvmcompute.NewProc("HcsRegisterComputeSystemCallback") + procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback") + procHcsRegisterProcessCallback = modvmcompute.NewProc("HcsRegisterProcessCallback") + procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback") + procHNSCall = modvmcompute.NewProc("HNSCall") ) func coTaskMemFree(buffer unsafe.Pointer) { @@ -734,6 +758,503 @@ func _getComputeSystemProperties(id *uint16, flags uint32, properties **uint16) return } +func hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(query) + if hr != nil { + return + } + return _hcsEnumerateComputeSystems(_p0, computeSystems, result) +} + +func _hcsEnumerateComputeSystems(query *uint16, computeSystems **uint16, result **uint16) (hr error) { + if hr = procHcsEnumerateComputeSystems.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + var _p1 *uint16 + _p1, hr = syscall.UTF16PtrFromString(configuration) + if hr != nil { + return + } + return _hcsCreateComputeSystem(_p0, _p1, identity, computeSystem, result) +} + +func _hcsCreateComputeSystem(id *uint16, configuration *uint16, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) { + if hr = procHcsCreateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + return _hcsOpenComputeSystem(_p0, computeSystem, result) +} + +func _hcsOpenComputeSystem(id *uint16, computeSystem *hcsSystem, result **uint16) (hr error) { + if hr = procHcsOpenComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) { + if hr = procHcsCloseComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsStartComputeSystem(computeSystem, _p0, result) +} + +func _hcsStartComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsStartComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsShutdownComputeSystem(computeSystem, _p0, result) +} + +func _hcsShutdownComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsShutdownComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsTerminateComputeSystem(computeSystem, _p0, result) +} + +func _hcsTerminateComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsTerminateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsPauseComputeSystem(computeSystem, _p0, result) +} + +func _hcsPauseComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsPauseComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(options) + if hr != nil { + return + } + return _hcsResumeComputeSystem(computeSystem, _p0, result) +} + +func _hcsResumeComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsResumeComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(propertyQuery) + if hr != nil { + return + } + return _hcsGetComputeSystemProperties(computeSystem, _p0, properties, result) +} + +func _hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery *uint16, properties **uint16, result **uint16) (hr error) { + if hr = procHcsGetComputeSystemProperties.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(configuration) + if hr != nil { + return + } + return _hcsModifyComputeSystem(computeSystem, _p0, result) +} + +func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, result **uint16) (hr error) { + if hr = procHcsModifyComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) { + if hr = procHcsCreateComputeSystemWait.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCreateComputeSystemWait.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(exitEvent)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(processParameters) + if hr != nil { + return + } + return _hcsCreateProcess(computeSystem, _p0, processInformation, process, result) +} + +func _hcsCreateProcess(computeSystem hcsSystem, processParameters *uint16, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) { + if hr = procHcsCreateProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) { + if hr = procHcsOpenProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCloseProcess(process hcsProcess) (hr error) { + if hr = procHcsCloseProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) { + if hr = procHcsTerminateProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) { + if hr = procHcsGetProcessInfo.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) { + if hr = procHcsGetProcessProperties.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(settings) + if hr != nil { + return + } + return _hcsModifyProcess(process, _p0, result) +} + +func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (hr error) { + if hr = procHcsModifyProcess.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) { + if hr = procHcsCreateProcessWait.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsCreateProcessWait.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(propertyQuery) + if hr != nil { + return + } + return _hcsGetServiceProperties(_p0, properties, result) +} + +func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result **uint16) (hr error) { + if hr = procHcsGetServiceProperties.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsModifyServiceSettings(settings string, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(settings) + if hr != nil { + return + } + return _hcsModifyServiceSettings(_p0, result) +} + +func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) { + if hr = procHcsModifyServiceSettings.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) { + var _p0 *uint16 + _p0, hr = syscall.UTF16PtrFromString(id) + if hr != nil { + return + } + var _p1 *uint16 + _p1, hr = syscall.UTF16PtrFromString(configuration) + if hr != nil { + return + } + return _hcsCreateComputeSystemTP5(_p0, _p1, computeSystem, result) +} + +func _hcsCreateComputeSystemTP5(id *uint16, configuration *uint16, computeSystem *hcsSystem, result **uint16) (hr error) { + if hr = procHcsCreateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsStartComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsShutdownComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsTerminateComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsPauseComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { + if hr = procHcsResumeComputeSystem.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { + if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) { + if hr = procHcsUnregisterComputeSystemCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { + if hr = procHcsRegisterProcessCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + +func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) { + if hr = procHcsUnregisterProcessCallback.Find(); hr != nil { + return + } + r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) + if int32(r0) < 0 { + hr = syscall.Errno(win32FromHresult(r0)) + } + return +} + func _hnsCall(method string, path string, object string, response **uint16) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(method)