mirror of https://github.com/docker/docs.git
Change Docker to use the new HCS RPC API
Signed-off-by: Darren Stahl <darst@microsoft.com>
This commit is contained in:
parent
91bc4cca58
commit
959c1a52bf
|
|
@ -43,7 +43,7 @@ esac
|
||||||
|
|
||||||
# the following lines are in sorted order, FYI
|
# the following lines are in sorted order, FYI
|
||||||
clone git github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
|
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/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/Sirupsen/logrus v0.10.0 # logrus is a common dependency among multiple deps
|
||||||
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package libcontainerd
|
package libcontainerd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -29,76 +28,6 @@ const (
|
||||||
ErrorInvalidObject = syscall.Errno(0x800710D8) // The object identifier does not represent a valid object
|
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
|
// defaultOwner is a tag passed to HCS to allow it to differentiate between
|
||||||
// container creator management stacks. We hard code "docker" in the case
|
// container creator management stacks. We hard code "docker" in the case
|
||||||
// of docker.
|
// of docker.
|
||||||
|
|
@ -109,7 +38,7 @@ const defaultOwner = "docker"
|
||||||
func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) error {
|
func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) error {
|
||||||
logrus.Debugln("LCD client.Create() with spec", spec)
|
logrus.Debugln("LCD client.Create() with spec", spec)
|
||||||
|
|
||||||
cu := &containerInit{
|
configuration := &hcsshim.ContainerConfig{
|
||||||
SystemType: "Container",
|
SystemType: "Container",
|
||||||
Name: containerID,
|
Name: containerID,
|
||||||
Owner: defaultOwner,
|
Owner: defaultOwner,
|
||||||
|
|
@ -121,55 +50,55 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.Windows.Networking != nil {
|
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 != nil {
|
||||||
if spec.Windows.Resources.CPU != nil {
|
if spec.Windows.Resources.CPU != nil {
|
||||||
if spec.Windows.Resources.CPU.Shares != 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 {
|
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 != nil {
|
||||||
if spec.Windows.Resources.Memory.Limit != 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 != nil {
|
||||||
if spec.Windows.Resources.Storage.Bps != 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 {
|
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 {
|
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 {
|
if spec.Windows.HvRuntime != nil {
|
||||||
cu.HvPartition = true
|
configuration.HvPartition = true
|
||||||
cu.HvRuntime = &hvRuntime{
|
configuration.HvRuntime = &hcsshim.HvRuntime{
|
||||||
ImagePath: spec.Windows.HvRuntime.ImagePath,
|
ImagePath: spec.Windows.HvRuntime.ImagePath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, option := range options {
|
if configuration.HvPartition {
|
||||||
if s, ok := option.(*ServicingOption); ok {
|
configuration.SandboxPath = filepath.Dir(spec.Windows.LayerFolder)
|
||||||
cu.Servicing = s.IsServicing
|
} else {
|
||||||
break
|
configuration.VolumePath = spec.Root.Path
|
||||||
}
|
configuration.LayerFolderPath = spec.Windows.LayerFolder
|
||||||
}
|
}
|
||||||
|
|
||||||
if cu.HvPartition {
|
for _, option := range options {
|
||||||
cu.SandboxPath = filepath.Dir(spec.Windows.LayerFolder)
|
if s, ok := option.(*ServicingOption); ok {
|
||||||
} else {
|
configuration.Servicing = s.IsServicing
|
||||||
cu.VolumePath = spec.Root.Path
|
break
|
||||||
cu.LayerFolderPath = spec.Windows.LayerFolder
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, layerPath := range spec.Windows.LayerPaths {
|
for _, layerPath := range spec.Windows.LayerPaths {
|
||||||
|
|
@ -178,33 +107,27 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cu.Layers = append(cu.Layers, layer{
|
configuration.Layers = append(configuration.Layers, hcsshim.Layer{
|
||||||
ID: g.ToString(),
|
ID: g.ToString(),
|
||||||
Path: layerPath,
|
Path: layerPath,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the mounts (volumes, bind mounts etc) to the structure
|
// 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 {
|
for i, mount := range spec.Mounts {
|
||||||
mds[i] = mappedDir{
|
mds[i] = hcsshim.MappedDir{
|
||||||
HostPath: mount.Source,
|
HostPath: mount.Source,
|
||||||
ContainerPath: mount.Destination,
|
ContainerPath: mount.Destination,
|
||||||
ReadOnly: mount.Readonly}
|
ReadOnly: mount.Readonly}
|
||||||
}
|
}
|
||||||
cu.MappedDirectories = mds
|
configuration.MappedDirectories = mds
|
||||||
|
|
||||||
configurationb, err := json.Marshal(cu)
|
hcsContainer, err := hcsshim.CreateContainer(containerID, configuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// Construct a container object for calling start on it.
|
||||||
container := &container{
|
container := &container{
|
||||||
containerCommon: containerCommon{
|
containerCommon: containerCommon{
|
||||||
|
|
@ -219,6 +142,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
|
||||||
processes: make(map[string]*process),
|
processes: make(map[string]*process),
|
||||||
},
|
},
|
||||||
ociSpec: spec,
|
ociSpec: spec,
|
||||||
|
hcsContainer: hcsContainer,
|
||||||
}
|
}
|
||||||
|
|
||||||
container.options = options
|
container.options = options
|
||||||
|
|
@ -252,10 +176,17 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Note we always tell HCS to
|
||||||
createProcessParms := hcsshim.CreateProcessParams{
|
// 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,
|
EmulateConsole: procToAdd.Terminal,
|
||||||
ConsoleSize: procToAdd.InitialConsoleSize,
|
ConsoleSize: procToAdd.InitialConsoleSize,
|
||||||
|
CreateStdInPipe: true,
|
||||||
|
CreateStdOutPipe: true,
|
||||||
|
CreateStdErrPipe: !procToAdd.Terminal,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take working directory from the process to add if it is defined,
|
// 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)
|
logrus.Debugf("commandLine: %s", createProcessParms.CommandLine)
|
||||||
|
|
||||||
// Start the command running in the container. Note we always tell HCS to
|
// Start the command running in the container.
|
||||||
// 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 stdout, stderr io.ReadCloser
|
var stdout, stderr io.ReadCloser
|
||||||
var pid uint32
|
var stdin io.WriteCloser
|
||||||
iopipe := &IOPipe{Terminal: procToAdd.Terminal}
|
newProcess, err := container.hcsContainer.CreateProcess(&createProcessParms)
|
||||||
pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem(
|
|
||||||
containerID,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
!procToAdd.Terminal,
|
|
||||||
createProcessParms)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("AddProcess %s CreateProcessInComputeSystem() failed %s", containerID, err)
|
logrus.Errorf("AddProcess %s CreateProcess() failed %s", containerID, err)
|
||||||
return 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.
|
// TEMP: Work around Windows BS/DEL behavior.
|
||||||
iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, procToAdd.Terminal)
|
iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, procToAdd.Terminal)
|
||||||
|
|
||||||
|
|
@ -302,18 +232,22 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
|
||||||
iopipe.Stderr = openReaderFromPipe(stderr)
|
iopipe.Stderr = openReaderFromPipe(stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the process to the containers list of processes
|
pid := newProcess.Pid()
|
||||||
container.processes[processFriendlyName] =
|
|
||||||
&process{
|
proc := &process{
|
||||||
processCommon: processCommon{
|
processCommon: processCommon{
|
||||||
containerID: containerID,
|
containerID: containerID,
|
||||||
friendlyName: processFriendlyName,
|
friendlyName: processFriendlyName,
|
||||||
client: clnt,
|
client: clnt,
|
||||||
systemPid: pid,
|
systemPid: uint32(pid),
|
||||||
},
|
},
|
||||||
commandLine: createProcessParms.CommandLine,
|
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
|
// Make sure the lock is not held while calling back into the daemon
|
||||||
clnt.unlock(containerID)
|
clnt.unlock(containerID)
|
||||||
|
|
||||||
|
|
@ -326,7 +260,7 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
|
||||||
clnt.lock(containerID)
|
clnt.lock(containerID)
|
||||||
|
|
||||||
// Spin up a go routine waiting for exit to handle cleanup
|
// Spin up a go routine waiting for exit to handle cleanup
|
||||||
go container.waitExit(pid, processFriendlyName, false)
|
go container.waitExit(proc, false)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -350,16 +284,17 @@ func (clnt *client) Signal(containerID string, sig int) error {
|
||||||
cont.manualStopRequested = true
|
cont.manualStopRequested = true
|
||||||
|
|
||||||
logrus.Debugf("lcd: Signal() containerID=%s sig=%d pid=%d", containerID, sig, cont.systemPid)
|
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 {
|
if syscall.Signal(sig) == syscall.SIGKILL {
|
||||||
// Terminate the compute system
|
// Terminate the compute system
|
||||||
if err := hcsshim.TerminateComputeSystem(containerID, hcsshim.TimeoutInfinite, context); err != nil {
|
if err := cont.hcsContainer.Terminate(); err != nil {
|
||||||
|
if err != hcsshim.ErrVmcomputeOperationPending {
|
||||||
logrus.Errorf("Failed to terminate %s - %q", containerID, err)
|
logrus.Errorf("Failed to terminate %s - %q", containerID, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Terminate Process
|
// 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)
|
logrus.Warnf("Failed to terminate pid %d in %s: %q", cont.systemPid, containerID, err)
|
||||||
// Ignore errors
|
// Ignore errors
|
||||||
err = nil
|
err = nil
|
||||||
|
|
@ -380,15 +315,17 @@ func (clnt *client) Resize(containerID, processFriendlyName string, width, heigh
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h, w := uint16(height), uint16(width)
|
||||||
|
|
||||||
if processFriendlyName == InitFriendlyName {
|
if processFriendlyName == InitFriendlyName {
|
||||||
logrus.Debugln("Resizing systemPID in", containerID, cont.process.systemPid)
|
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 {
|
for _, p := range cont.processes {
|
||||||
if p.friendlyName == processFriendlyName {
|
if p.friendlyName == processFriendlyName {
|
||||||
logrus.Debugln("Resizing exec'd process", containerID, p.systemPid)
|
logrus.Debugln("Resizing exec'd process", containerID, p.systemPid)
|
||||||
return hcsshim.ResizeConsoleInComputeSystem(containerID, p.systemPid, height, width)
|
return p.hcsProcess.ResizeConsole(w, h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ type container struct {
|
||||||
ociSpec Spec
|
ociSpec Spec
|
||||||
|
|
||||||
manualStopRequested bool
|
manualStopRequested bool
|
||||||
|
hcsContainer hcsshim.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctr *container) newProcess(friendlyName string) *process {
|
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
|
// Start the container. If this is a servicing container, this call will block
|
||||||
// until the container is done with the servicing execution.
|
// until the container is done with the servicing execution.
|
||||||
logrus.Debugln("Starting container ", ctr.containerID)
|
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)
|
logrus.Errorf("Failed to start compute system: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -49,59 +50,61 @@ func (ctr *container) start() error {
|
||||||
if s, ok := option.(*ServicingOption); ok && s.IsServicing {
|
if s, ok := option.(*ServicingOption); ok && s.IsServicing {
|
||||||
// Since the servicing operation is complete when StartCommputeSystem returns without error,
|
// Since the servicing operation is complete when StartCommputeSystem returns without error,
|
||||||
// we can shutdown (which triggers merge) and exit early.
|
// we can shutdown (which triggers merge) and exit early.
|
||||||
const shutdownTimeout = 5 * 60 * 1000 // 4 minutes
|
return ctr.shutdown()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
EmulateConsole: ctr.ociSpec.Process.Terminal,
|
||||||
WorkingDirectory: ctr.ociSpec.Process.Cwd,
|
WorkingDirectory: ctr.ociSpec.Process.Cwd,
|
||||||
ConsoleSize: ctr.ociSpec.Process.InitialConsoleSize,
|
ConsoleSize: ctr.ociSpec.Process.InitialConsoleSize,
|
||||||
|
CreateStdInPipe: true,
|
||||||
|
CreateStdOutPipe: true,
|
||||||
|
CreateStdErrPipe: !ctr.ociSpec.Process.Terminal,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the environment for the process
|
// Configure the environment for the process
|
||||||
createProcessParms.Environment = setupEnvironmentVariables(ctr.ociSpec.Process.Env)
|
createProcessParms.Environment = setupEnvironmentVariables(ctr.ociSpec.Process.Env)
|
||||||
createProcessParms.CommandLine = strings.Join(ctr.ociSpec.Process.Args, " ")
|
createProcessParms.CommandLine = strings.Join(ctr.ociSpec.Process.Args, " ")
|
||||||
|
|
||||||
iopipe := &IOPipe{Terminal: ctr.ociSpec.Process.Terminal}
|
// Start the command running in the container.
|
||||||
|
hcsProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
|
||||||
// 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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("CreateProcessInComputeSystem() failed %s", err)
|
logrus.Errorf("CreateProcess() failed %s", err)
|
||||||
|
if err2 := ctr.terminate(); err2 != nil {
|
||||||
// Explicitly terminate the compute system here.
|
logrus.Debugf("Failed to cleanup after a failed CreateProcess. Ignoring this. %s", err2)
|
||||||
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)
|
|
||||||
} else {
|
} else {
|
||||||
logrus.Debugln("Cleaned up after failed CreateProcessInComputeSystem by calling TerminateComputeSystem")
|
logrus.Debugln("Cleaned up after failed CreateProcess by calling Terminate")
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctr.startedAt = time.Now()
|
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.
|
// TEMP: Work around Windows BS/DEL behavior.
|
||||||
iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, ctr.ociSpec.Process.Terminal)
|
iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, ctr.ociSpec.Process.Terminal)
|
||||||
|
|
||||||
|
|
@ -118,7 +121,7 @@ func (ctr *container) start() error {
|
||||||
ctr.systemPid = uint32(pid)
|
ctr.systemPid = uint32(pid)
|
||||||
|
|
||||||
// Spin up a go routine waiting for exit to handle cleanup
|
// 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)
|
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
|
// 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
|
// equivalent to (in the linux containerd world) where events come in for
|
||||||
// state change notifications from containerd.
|
// state change notifications from containerd.
|
||||||
func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstProcessToStart bool) error {
|
func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) error {
|
||||||
logrus.Debugln("waitExit on pid", pid)
|
logrus.Debugln("waitExit on pid", process.systemPid)
|
||||||
|
|
||||||
// Block indefinitely for the process to exit.
|
// Block indefinitely for the process to exit.
|
||||||
exitCode, err := hcsshim.WaitForProcessInComputeSystem(ctr.containerID, pid, hcsshim.TimeoutInfinite)
|
err := process.hcsProcess.Wait()
|
||||||
if err != nil {
|
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)
|
logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): %s", err)
|
||||||
}
|
}
|
||||||
// Fall through here, do not return. This ensures we attempt to continue the
|
// 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.
|
// 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{
|
CommonStateInfo: CommonStateInfo{
|
||||||
State: StateExit,
|
State: StateExit,
|
||||||
ExitCode: uint32(exitCode),
|
ExitCode: uint32(exitCode),
|
||||||
Pid: pid,
|
Pid: process.systemPid,
|
||||||
ProcessID: processFriendlyName,
|
ProcessID: process.friendlyName,
|
||||||
},
|
},
|
||||||
UpdatePending: false,
|
UpdatePending: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
// But it could have been an exec'd process which exited
|
// But it could have been an exec'd process which exited
|
||||||
if !isFirstProcessToStart {
|
if !isFirstProcessToStart {
|
||||||
|
if err := process.hcsProcess.Close(); err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
}
|
||||||
si.State = StateExitProcess
|
si.State = StateExitProcess
|
||||||
} else {
|
} else {
|
||||||
// Since this is the init process, always call into vmcompute.dll to
|
updatePending, err := ctr.hcsContainer.HasPendingUpdates()
|
||||||
// shutdown the container after we have completed.
|
|
||||||
|
|
||||||
propertyCheckFlag := 1 // Include update pending check.
|
|
||||||
csProperties, err := hcsshim.GetComputeSystemProperties(ctr.containerID, uint32(propertyCheckFlag))
|
|
||||||
if err != nil {
|
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 {
|
} else {
|
||||||
si.UpdatePending = csProperties.AreUpdatesPending
|
si.UpdatePending = updatePending
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("Shutting down container %s", ctr.containerID)
|
logrus.Debugf("Shutting down container %s", ctr.containerID)
|
||||||
// Explicit timeout here rather than hcsshim.TimeoutInfinte to avoid a
|
if err := ctr.shutdown(); err != nil {
|
||||||
// (remote) possibility that ShutdownComputeSystem hangs indefinitely.
|
logrus.Debugf("Failed to shutdown container %s", ctr.containerID)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
logrus.Debugf("Completed shutting down container %s", ctr.containerID)
|
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 {
|
if !ctr.manualStopRequested && ctr.restartManager != nil {
|
||||||
restart, wait, err := ctr.restartManager.ShouldRestart(uint32(exitCode), false, time.Since(ctr.startedAt))
|
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
|
// Remove process from list if we have exited
|
||||||
// We need to do so here in case the Message Handler decides to restart it.
|
// We need to do so here in case the Message Handler decides to restart it.
|
||||||
if si.State == StateExit {
|
if si.State == StateExit {
|
||||||
|
if err := ctr.hcsContainer.Close(); err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
}
|
||||||
ctr.client.deleteContainer(ctr.friendlyName)
|
ctr.client.deleteContainer(ctr.friendlyName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -240,3 +245,37 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr
|
||||||
logrus.Debugln("waitExit() completed OK")
|
logrus.Debugln("waitExit() completed OK")
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package libcontainerd
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,6 +15,7 @@ type process struct {
|
||||||
|
|
||||||
// commandLine is to support returning summary information for docker top
|
// commandLine is to support returning summary information for docker top
|
||||||
commandLine string
|
commandLine string
|
||||||
|
hcsProcess hcsshim.Process
|
||||||
}
|
}
|
||||||
|
|
||||||
func openReaderFromPipe(p io.ReadCloser) io.Reader {
|
func openReaderFromPipe(p io.ReadCloser) io.Reader {
|
||||||
|
|
@ -57,3 +59,27 @@ func (w *delToBsWriter) Write(b []byte) (int, error) {
|
||||||
}
|
}
|
||||||
return w.WriteCloser.Write(bc)
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,6 @@ 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)
|
createmode := uint32(syscall.CREATE_NEW)
|
||||||
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
err := os.Mkdir(path, 0)
|
err := os.Mkdir(path, 0)
|
||||||
|
|
@ -74,8 +73,6 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
|
||||||
|
|
||||||
mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
|
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)
|
f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode)
|
||||||
return
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -113,9 +110,7 @@ func (w *baseLayerWriter) AddLink(name string, target string) (err error) {
|
||||||
return err
|
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 {
|
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) {
|
func (w *baseLayerWriter) Write(b []byte) (int, error) {
|
||||||
var n int
|
n, err := w.bw.Write(b)
|
||||||
err := winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) {
|
|
||||||
n, err = w.bw.Write(b)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.err = err
|
w.err = err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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 "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -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.
|
// 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 {
|
if procExportLayerBegin.Find() != nil {
|
||||||
// The new layer reader is not available on this Windows build. Fall back to the
|
// The new layer reader is not available on this Windows build. Fall back to the
|
||||||
// legacy export code path.
|
// legacy export code path.
|
||||||
|
|
@ -120,7 +122,7 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = ExportLayer(info, layerId, path, parentLayerPaths)
|
err = ExportLayer(info, layerID, path, parentLayerPaths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -137,7 +139,7 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r := &FilterLayerReader{}
|
r := &FilterLayerReader{}
|
||||||
err = exportLayerBegin(&infop, layerId, layers, &r.context)
|
err = exportLayerBegin(&infop, layerID, layers, &r.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeError(err, "ExportLayerBegin", "")
|
return nil, makeError(err, "ExportLayerBegin", "")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go
|
//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 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 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?
|
//sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -60,6 +96,8 @@ const (
|
||||||
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
|
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
|
||||||
WSAEINVAL = syscall.Errno(10022)
|
WSAEINVAL = syscall.Errno(10022)
|
||||||
|
|
||||||
|
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
|
||||||
|
|
||||||
// Timeout on wait calls
|
// Timeout on wait calls
|
||||||
TimeoutInfinite = 0xFFFFFFFF
|
TimeoutInfinite = 0xFFFFFFFF
|
||||||
)
|
)
|
||||||
|
|
@ -70,6 +108,18 @@ type HcsError struct {
|
||||||
Err error
|
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 {
|
func makeError(err error, title, rest string) error {
|
||||||
// Pass through DLL errors directly since they do not originate from HCS.
|
// Pass through DLL errors directly since they do not originate from HCS.
|
||||||
if _, ok := err.(*syscall.DLLError); ok {
|
if _, ok := err.(*syscall.DLLError); ok {
|
||||||
|
|
@ -119,3 +169,15 @@ func convertAndFreeCoTaskMemString(buffer *uint16) string {
|
||||||
coTaskMemFree(unsafe.Pointer(buffer))
|
coTaskMemFree(unsafe.Pointer(buffer))
|
||||||
return str
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,8 @@ func (r *legacyLayerWriterWrapper) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLayerWriter returns a new layer writer for creating a layer on disk.
|
// 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) {
|
func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) {
|
||||||
if len(parentLayerPaths) == 0 {
|
if len(parentLayerPaths) == 0 {
|
||||||
// This is a base layer. It gets imported differently.
|
// This is a base layer. It gets imported differently.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -598,6 +598,19 @@ func (f *Fn) HasStringParam() bool {
|
||||||
return false
|
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.
|
// HelperName returns name of function f helper.
|
||||||
func (f *Fn) HelperName() string {
|
func (f *Fn) HelperName() string {
|
||||||
if !f.HasStringParam() {
|
if !f.HasStringParam() {
|
||||||
|
|
@ -748,6 +761,7 @@ const srcTemplate = `
|
||||||
|
|
||||||
package {{packagename}}
|
package {{packagename}}
|
||||||
|
|
||||||
|
import "github.com/Microsoft/go-winio"
|
||||||
import "unsafe"{{if syscalldot}}
|
import "unsafe"{{if syscalldot}}
|
||||||
import "syscall"{{end}}
|
import "syscall"{{end}}
|
||||||
|
|
||||||
|
|
@ -764,7 +778,7 @@ var (
|
||||||
{{define "dlls"}}{{range .DLLs}} mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
|
{{define "dlls"}}{{range .DLLs}} mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
|
||||||
{{end}}{{end}}
|
{{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}}
|
{{end}}{{end}}
|
||||||
|
|
||||||
{{define "helperbody"}}
|
{{define "helperbody"}}
|
||||||
|
|
|
||||||
|
|
@ -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 "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
vmcomputedll = syscall.NewLazyDLL("vmcompute.dll")
|
||||||
|
hcsCallbackAPI = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback")
|
||||||
|
hcsCallbacksSupported = hcsCallbackAPI.Find() == nil
|
||||||
|
)
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,8 @@
|
||||||
|
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import "github.com/Microsoft/go-winio"
|
||||||
"unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
|
||||||
)
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
var _ unsafe.Pointer
|
||||||
|
|
@ -49,6 +46,33 @@ var (
|
||||||
procTerminateProcessInComputeSystem = modvmcompute.NewProc("TerminateProcessInComputeSystem")
|
procTerminateProcessInComputeSystem = modvmcompute.NewProc("TerminateProcessInComputeSystem")
|
||||||
procWaitForProcessInComputeSystem = modvmcompute.NewProc("WaitForProcessInComputeSystem")
|
procWaitForProcessInComputeSystem = modvmcompute.NewProc("WaitForProcessInComputeSystem")
|
||||||
procGetComputeSystemProperties = modvmcompute.NewProc("GetComputeSystemProperties")
|
procGetComputeSystemProperties = modvmcompute.NewProc("GetComputeSystemProperties")
|
||||||
|
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")
|
procHNSCall = modvmcompute.NewProc("HNSCall")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -734,6 +758,503 @@ func _getComputeSystemProperties(id *uint16, flags uint32, properties **uint16)
|
||||||
return
|
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) {
|
func _hnsCall(method string, path string, object string, response **uint16) (hr error) {
|
||||||
var _p0 *uint16
|
var _p0 *uint16
|
||||||
_p0, hr = syscall.UTF16PtrFromString(method)
|
_p0, hr = syscall.UTF16PtrFromString(method)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue