Browse Source

Merge pull request #22958 from Microsoft/hcs_rpc

Windows: Use the new HCS RPC API
John Howard 9 years ago
parent
commit
c7ee503082

+ 1 - 1
hack/vendor.sh

@@ -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

+ 74 - 137
libcontainerd/client_windows.go

@@ -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,90 +50,84 @@ 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
-		cu.HvRuntime = &hvRuntime{
+		configuration.HvPartition = true
+		configuration.HvRuntime = &hcsshim.HvRuntime{
 			ImagePath: spec.Windows.HvRuntime.ImagePath,
 			ImagePath: spec.Windows.HvRuntime.ImagePath,
 		}
 		}
 	}
 	}
 
 
+	if configuration.HvPartition {
+		configuration.SandboxPath = filepath.Dir(spec.Windows.LayerFolder)
+	} else {
+		configuration.VolumePath = spec.Root.Path
+		configuration.LayerFolderPath = spec.Windows.LayerFolder
+	}
+
 	for _, option := range options {
 	for _, option := range options {
 		if s, ok := option.(*ServicingOption); ok {
 		if s, ok := option.(*ServicingOption); ok {
-			cu.Servicing = s.IsServicing
+			configuration.Servicing = s.IsServicing
 			break
 			break
 		}
 		}
 	}
 	}
 
 
-	if cu.HvPartition {
-		cu.SandboxPath = filepath.Dir(spec.Windows.LayerFolder)
-	} else {
-		cu.VolumePath = spec.Root.Path
-		cu.LayerFolderPath = spec.Windows.LayerFolder
-	}
-
 	for _, layerPath := range spec.Windows.LayerPaths {
 	for _, layerPath := range spec.Windows.LayerPaths {
 		_, filename := filepath.Split(layerPath)
 		_, filename := filepath.Split(layerPath)
 		g, err := hcsshim.NameToGuid(filename)
 		g, err := hcsshim.NameToGuid(filename)
 		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{
@@ -218,7 +141,8 @@ 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
 	}
 	}
-
-	createProcessParms := hcsshim.CreateProcessParams{
-		EmulateConsole: procToAdd.Terminal,
-		ConsoleSize:    procToAdd.InitialConsoleSize,
+	// Note we always tell HCS to
+	// create stdout as it's required regardless of '-i' or '-t' options, so that
+	// docker can always grab the output through logs. We also tell HCS to always
+	// create stdin, even if it's not used - it will be closed shortly. Stderr
+	// is only created if it we're not -t.
+	createProcessParms := hcsshim.ProcessConfig{
+		EmulateConsole:   procToAdd.Terminal,
+		ConsoleSize:      procToAdd.InitialConsoleSize,
+		CreateStdInPipe:  true,
+		CreateStdOutPipe: true,
+		CreateStdErrPipe: !procToAdd.Terminal,
 	}
 	}
 
 
 	// Take working directory from the process to add if it is defined,
 	// 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
-	// create stdout as it's required regardless of '-i' or '-t' options, so that
-	// docker can always grab the output through logs. We also tell HCS to always
-	// create stdin, even if it's not used - it will be closed shortly. Stderr
-	// is only created if it we're not -t.
+	// Start the command running in the container.
 	var stdout, stderr io.ReadCloser
 	var stdout, stderr io.ReadCloser
-	var pid uint32
-	iopipe := &IOPipe{Terminal: procToAdd.Terminal}
-	pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem(
-		containerID,
-		true,
-		true,
-		!procToAdd.Terminal,
-		createProcessParms)
+	var stdin io.WriteCloser
+	newProcess, err := container.hcsContainer.CreateProcess(&createProcessParms)
+	if err != nil {
+		logrus.Errorf("AddProcess %s CreateProcess() failed %s", containerID, err)
+		return err
+	}
+
+	stdin, stdout, stderr, err = newProcess.Stdio()
 	if err != nil {
 	if err != nil {
-		logrus.Errorf("AddProcess %s CreateProcessInComputeSystem() failed %s", containerID, err)
+		logrus.Errorf("%s getting std pipes failed %s", containerID, err)
 		return 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,17 +232,21 @@ 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
-	container.processes[processFriendlyName] =
-		&process{
-			processCommon: processCommon{
-				containerID:  containerID,
-				friendlyName: processFriendlyName,
-				client:       clnt,
-				systemPid:    pid,
-			},
-			commandLine: createProcessParms.CommandLine,
-		}
+	pid := newProcess.Pid()
+
+	proc := &process{
+		processCommon: processCommon{
+			containerID:  containerID,
+			friendlyName: processFriendlyName,
+			client:       clnt,
+			systemPid:    uint32(pid),
+		},
+		commandLine: createProcessParms.CommandLine,
+		hcsProcess:  newProcess,
+	}
+
+	// Add the process to the container's list of processes
+	container.processes[processFriendlyName] = proc
 
 
 	// Make sure the lock is not held while calling back into the daemon
 	// 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 {
-			logrus.Errorf("Failed to terminate %s - %q", containerID, err)
+		if err := cont.hcsContainer.Terminate(); err != nil {
+			if err != hcsshim.ErrVmcomputeOperationPending {
+				logrus.Errorf("Failed to terminate %s - %q", containerID, err)
+			}
 		}
 		}
 	} else {
 	} 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)
 		}
 		}
 	}
 	}
 
 

+ 104 - 65
libcontainerd/container_windows.go

@@ -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
-			const terminateTimeout = 1 * 60 * 1000 // 1 minute
-			if err := hcsshim.ShutdownComputeSystem(ctr.containerID, shutdownTimeout, ""); err != nil {
-				logrus.Errorf("Failed during cleanup of servicing container: %s", err)
-				// Terminate the container, ignoring errors.
-				if err2 := hcsshim.TerminateComputeSystem(ctr.containerID, terminateTimeout, ""); err2 != nil {
-					logrus.Errorf("Failed to terminate container %s after shutdown failure: %q", ctr.containerID, err2)
-				}
-				return err
-			}
-			return nil
+			return ctr.shutdown()
 		}
 		}
 	}
 	}
 
 
-	createProcessParms := hcsshim.CreateProcessParams{
+	// Note we always tell HCS to
+	// create stdout as it's required regardless of '-i' or '-t' options, so that
+	// docker can always grab the output through logs. We also tell HCS to always
+	// create stdin, even if it's not used - it will be closed shortly. Stderr
+	// is only created if it we're not -t.
+	createProcessParms := &hcsshim.ProcessConfig{
 		EmulateConsole:   ctr.ociSpec.Process.Terminal,
 		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. Note we always tell HCS to
-	// create stdout as it's required regardless of '-i' or '-t' options, so that
-	// docker can always grab the output through logs. We also tell HCS to always
-	// create stdin, even if it's not used - it will be closed shortly. Stderr
-	// is only created if it we're not -t.
-	var pid uint32
-	var stdout, stderr io.ReadCloser
-	pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem(
-		ctr.containerID,
-		true,
-		true,
-		!ctr.ociSpec.Process.Terminal,
-		createProcessParms)
+	// Start the command running in the container.
+	hcsProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
 	if err != nil {
 	if err != nil {
-		logrus.Errorf("CreateProcessInComputeSystem() failed %s", err)
-
-		// Explicitly terminate the compute system here.
-		if err2 := hcsshim.TerminateComputeSystem(ctr.containerID, hcsshim.TimeoutInfinite, "CreateProcessInComputeSystem failed"); err2 != nil {
-			// Ignore this error, there's not a lot we can do except log it
-			logrus.Warnf("Failed to TerminateComputeSystem after a failed CreateProcessInComputeSystem. Ignoring this.", err2)
+		logrus.Errorf("CreateProcess() failed %s", err)
+		if err2 := ctr.terminate(); err2 != nil {
+			logrus.Debugf("Failed to cleanup after a failed CreateProcess. Ignoring this. %s", err2)
 		} else {
 		} 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 {
-	logrus.Debugln("waitExit on pid", pid)
+func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) error {
+	logrus.Debugln("waitExit on pid", process.systemPid)
 
 
 	// Block indefinitely for the process to exit.
 	// 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,
-			ProcessID: processFriendlyName,
+			Pid:       process.systemPid,
+			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
-		// shutdown the container after we have completed.
-
-		propertyCheckFlag := 1 // Include update pending check.
-		csProperties, err := hcsshim.GetComputeSystemProperties(ctr.containerID, uint32(propertyCheckFlag))
+		updatePending, err := ctr.hcsContainer.HasPendingUpdates()
 		if err != nil {
 		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
-		// (remote) possibility that ShutdownComputeSystem hangs indefinitely.
-		const shutdownTimeout = 5 * 60 * 1000 // 5 minutes
-		if err := hcsshim.ShutdownComputeSystem(ctr.containerID, shutdownTimeout, "waitExit"); err != nil {
-			if herr, ok := err.(*hcsshim.HcsError); !ok ||
-				(herr.Err != hcsshim.ERROR_SHUTDOWN_IN_PROGRESS &&
-					herr.Err != ErrorBadPathname &&
-					herr.Err != syscall.ERROR_PATH_NOT_FOUND) {
-				logrus.Debugf("waitExit - error from ShutdownComputeSystem on %s %v. Calling TerminateComputeSystem", ctr.containerCommon, err)
-				if err := hcsshim.TerminateComputeSystem(ctr.containerID, shutdownTimeout, "waitExit"); err != nil {
-					logrus.Debugf("waitExit - ignoring error from TerminateComputeSystem %s %v", ctr.containerID, err)
-				} else {
-					logrus.Debugf("Successful TerminateComputeSystem after failed ShutdownComputeSystem on %s in waitExit", ctr.containerID)
-				}
-			}
+		if err := ctr.shutdown(); err != nil {
+			logrus.Debugf("Failed to shutdown container %s", ctr.containerID)
 		} else {
 		} 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
+}

+ 26 - 0
libcontainerd/process_windows.go

@@ -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)
+}

+ 11 - 20
vendor/src/github.com/Microsoft/hcsshim/baselayer.go

@@ -62,20 +62,17 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
 		}
 		}
 	}()
 	}()
 
 
-	err = winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) {
-		createmode := uint32(syscall.CREATE_NEW)
-		if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
-			err := os.Mkdir(path, 0)
-			if err != nil && !os.IsExist(err) {
-				return err
-			}
-			createmode = syscall.OPEN_EXISTING
+	createmode := uint32(syscall.CREATE_NEW)
+	if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
+		err := os.Mkdir(path, 0)
+		if err != nil && !os.IsExist(err) {
+			return err
 		}
 		}
+		createmode = syscall.OPEN_EXISTING
+	}
 
 
-		mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
-		f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode)
-		return
-	})
+	mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
+	f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode)
 	if err != nil {
 	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
-	err := winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) {
-		n, err = w.bw.Write(b)
-		return
-	})
+	n, err := w.bw.Write(b)
 	if err != nil {
 	if err != nil {
 		w.err = err
 		w.err = err
 	}
 	}

+ 78 - 0
vendor/src/github.com/Microsoft/hcsshim/callback.go

@@ -0,0 +1,78 @@
+package hcsshim
+
+import (
+	"errors"
+	"sync"
+	"syscall"
+)
+
+var (
+	nextCallback    uintptr
+	callbackMap     = map[uintptr]*notifcationWatcherContext{}
+	callbackMapLock = sync.RWMutex{}
+
+	notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
+
+	// Notifications for HCS_SYSTEM handles
+	hcsNotificationSystemExited          hcsNotification = 0x00000001
+	hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
+	hcsNotificationSystemStartCompleted  hcsNotification = 0x00000003
+	hcsNotificationSystemPauseCompleted  hcsNotification = 0x00000004
+	hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
+
+	// Notifications for HCS_PROCESS handles
+	hcsNotificationProcessExited hcsNotification = 0x00010000
+
+	// Common notifications
+	hcsNotificationInvalid           hcsNotification = 0x00000000
+	hcsNotificationServiceDisconnect hcsNotification = 0x01000000
+
+	// ErrUnexpectedContainerExit is the error returned when a container exits while waiting for
+	// a different expected notification
+	ErrUnexpectedContainerExit = errors.New("unexpected container exit")
+
+	// ErrUnexpectedProcessAbort is the error returned when communication with the compute service
+	// is lost while waiting for a notification
+	ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
+)
+
+type hcsNotification uint32
+type notificationChannel chan error
+
+type notifcationWatcherContext struct {
+	channel              notificationChannel
+	expectedNotification hcsNotification
+	handle               hcsCallback
+}
+
+func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
+	var (
+		result       error
+		completeWait = false
+	)
+
+	callbackMapLock.RLock()
+	context := callbackMap[callbackNumber]
+	callbackMapLock.RUnlock()
+
+	if notificationType == context.expectedNotification {
+		if int32(notificationStatus) < 0 {
+			result = syscall.Errno(win32FromHresult(notificationStatus))
+		} else {
+			result = nil
+		}
+		completeWait = true
+	} else if notificationType == hcsNotificationSystemExited {
+		result = ErrUnexpectedContainerExit
+		completeWait = true
+	} else if notificationType == hcsNotificationServiceDisconnect {
+		result = ErrUnexpectedProcessAbort
+		completeWait = true
+	}
+
+	if completeWait {
+		context.channel <- result
+	}
+
+	return 0
+}

+ 513 - 0
vendor/src/github.com/Microsoft/hcsshim/container.go

@@ -0,0 +1,513 @@
+package hcsshim
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"runtime"
+	"syscall"
+	"time"
+
+	"github.com/Sirupsen/logrus"
+)
+
+var (
+	defaultTimeout = time.Minute * 4
+
+	// ErrTimeout is an error encountered when waiting on a notification times out
+	ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
+)
+
+type ContainerError struct {
+	Container *container
+	Operation string
+	ExtraInfo string
+	Err       error
+}
+
+type container struct {
+	handle hcsSystem
+	id     string
+}
+
+type containerProperties struct {
+	ID                string `json:"Id"`
+	Name              string
+	SystemType        string
+	Owner             string
+	SiloGUID          string `json:"SiloGuid,omitempty"`
+	IsDummy           bool   `json:",omitempty"`
+	RuntimeID         string `json:"RuntimeId,omitempty"`
+	Stopped           bool   `json:",omitempty"`
+	ExitType          string `json:",omitempty"`
+	AreUpdatesPending bool   `json:",omitempty"`
+}
+
+// CreateContainer creates a new container with the given configuration but does not start it.
+func CreateContainer(id string, c *ContainerConfig) (Container, error) {
+	operation := "CreateContainer"
+	title := "HCSShim::" + operation
+	logrus.Debugf(title+" id=%s", id)
+
+	container := &container{
+		id: id,
+	}
+
+	configurationb, err := json.Marshal(c)
+	if err != nil {
+		return nil, err
+	}
+
+	configuration := string(configurationb)
+
+	var (
+		handle      hcsSystem
+		resultp     *uint16
+		createError error
+	)
+	if hcsCallbacksSupported {
+		var identity syscall.Handle
+		createError = hcsCreateComputeSystem(id, configuration, identity, &handle, &resultp)
+	} else {
+		createError = hcsCreateComputeSystemTP5(id, configuration, &handle, &resultp)
+	}
+	container.handle = handle
+
+	err = processAsyncHcsResult(container, createError, resultp, hcsNotificationSystemCreateCompleted, &defaultTimeout)
+	if err != nil {
+		err := &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err}
+		logrus.Error(err)
+		return nil, err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle)
+	runtime.SetFinalizer(container, closeContainer)
+	return container, nil
+}
+
+// OpenContainer opens an existing container by ID.
+func OpenContainer(id string) (Container, error) {
+	operation := "OpenContainer"
+	title := "HCSShim::" + operation
+	logrus.Debugf(title+" id=%s", id)
+
+	container := &container{
+		id: id,
+	}
+
+	var (
+		handle  hcsSystem
+		resultp *uint16
+	)
+	err := hcsOpenComputeSystem(id, &handle, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return nil, err
+	}
+
+	container.handle = handle
+
+	logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
+	runtime.SetFinalizer(container, closeContainer)
+	return container, nil
+}
+
+// Start synchronously starts the container.
+func (container *container) Start() error {
+	operation := "Start"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+
+	var resultp *uint16
+	err := hcsStartComputeSystemTP5(container.handle, nil, &resultp)
+	err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemStartCompleted, &defaultTimeout)
+	if err != nil {
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+// Shutdown requests a container shutdown, but it may not actually be shut down until Wait() succeeds.
+// It returns ErrVmcomputeOperationPending if the shutdown is in progress, nil if the shutdown is complete.
+func (container *container) Shutdown() error {
+	operation := "Shutdown"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+
+	var resultp *uint16
+	err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		if err == ErrVmcomputeOperationPending {
+			return ErrVmcomputeOperationPending
+		}
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
+// It returns ErrVmcomputeOperationPending if the shutdown is in progress, nil if the shutdown is complete.
+func (container *container) Terminate() error {
+	operation := "Terminate"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+
+	var resultp *uint16
+	err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		if err == ErrVmcomputeOperationPending {
+			return ErrVmcomputeOperationPending
+		}
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+// Wait synchronously waits for the container to shutdown or terminate.
+func (container *container) Wait() error {
+	operation := "Wait"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+
+	if hcsCallbacksSupported {
+		err := registerAndWaitForCallback(container, hcsNotificationSystemExited)
+		if err != nil {
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	} else {
+		_, err := container.waitTimeoutInternal(syscall.INFINITE)
+		if err != nil {
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+func (container *container) waitTimeoutInternal(timeout uint32) (bool, error) {
+	return waitTimeoutInternalHelper(container, timeout)
+}
+
+// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It returns
+// ErrTimeout if the timeout duration expires before the container is shut down.
+func (container *container) WaitTimeout(timeout time.Duration) error {
+	operation := "WaitTimeout"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+
+	if hcsCallbacksSupported {
+		err := registerAndWaitForCallbackTimeout(container, hcsNotificationSystemExited, timeout)
+		if err == ErrTimeout {
+			return ErrTimeout
+		} else if err != nil {
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	} else {
+		finished, err := waitTimeoutHelper(container, timeout)
+		if !finished {
+			return ErrTimeout
+		} else if err != nil {
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+func (container *container) hcsWait(timeout uint32) (bool, error) {
+	var (
+		resultp   *uint16
+		exitEvent syscall.Handle
+	)
+
+	err := hcsCreateComputeSystemWait(container.handle, &exitEvent, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		return false, err
+	}
+	defer syscall.CloseHandle(exitEvent)
+
+	return waitForSingleObject(exitEvent, timeout)
+}
+
+func (container *container) properties() (*containerProperties, error) {
+	var (
+		resultp     *uint16
+		propertiesp *uint16
+	)
+	err := hcsGetComputeSystemProperties(container.handle, "", &propertiesp, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		return nil, err
+	}
+
+	if propertiesp == nil {
+		return nil, errors.New("Unexpected result from hcsGetComputeSystemProperties, properties should never be nil")
+	}
+	propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
+
+	properties := &containerProperties{}
+	if err := json.Unmarshal(propertiesRaw, properties); err != nil {
+		return nil, err
+	}
+
+	return properties, nil
+}
+
+// HasPendingUpdates returns true if the container has updates pending to install
+func (container *container) HasPendingUpdates() (bool, error) {
+	operation := "HasPendingUpdates"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+	properties, err := container.properties()
+	if err != nil {
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return false, err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return properties.AreUpdatesPending, nil
+}
+
+// Pause pauses the execution of the container. This feature is not enabled in TP5.
+func (container *container) Pause() error {
+	operation := "Pause"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+
+	var resultp *uint16
+	err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp)
+	err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemPauseCompleted, &defaultTimeout)
+	if err != nil {
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+// Resume resumes the execution of the container. This feature is not enabled in TP5.
+func (container *container) Resume() error {
+	operation := "Resume"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+	var (
+		resultp *uint16
+	)
+
+	err := hcsResumeComputeSystemTP5(container.handle, nil, &resultp)
+	err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemResumeCompleted, &defaultTimeout)
+	if err != nil {
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+// CreateProcess launches a new process within the container.
+func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
+	operation := "CreateProcess"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+	var (
+		processInfo   hcsProcessInformation
+		processHandle hcsProcess
+		resultp       *uint16
+	)
+
+	// If we are not emulating a console, ignore any console size passed to us
+	if !c.EmulateConsole {
+		c.ConsoleSize[0] = 0
+		c.ConsoleSize[1] = 0
+	}
+
+	configurationb, err := json.Marshal(c)
+	if err != nil {
+		return nil, err
+	}
+
+	configuration := string(configurationb)
+
+	err = hcsCreateProcess(container.handle, configuration, &processInfo, &processHandle, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		err = &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err}
+		logrus.Error(err)
+		return nil, err
+	}
+
+	process := &process{
+		handle:    processHandle,
+		processID: int(processInfo.ProcessId),
+		container: container,
+		cachedPipes: &cachedPipes{
+			stdIn:  processInfo.StdInput,
+			stdOut: processInfo.StdOutput,
+			stdErr: processInfo.StdError,
+		},
+	}
+
+	logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
+	runtime.SetFinalizer(process, closeProcess)
+	return process, nil
+}
+
+// OpenProcess gets an interface to an existing process within the container.
+func (container *container) OpenProcess(pid int) (Process, error) {
+	operation := "OpenProcess"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s, processid=%d", container.id, pid)
+	var (
+		processHandle hcsProcess
+		resultp       *uint16
+	)
+
+	err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return nil, err
+	}
+
+	process := &process{
+		handle:    processHandle,
+		processID: pid,
+		container: container,
+	}
+
+	logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
+	runtime.SetFinalizer(process, closeProcess)
+	return process, nil
+}
+
+// Close cleans up any state associated with the container but does not terminate or wait for it.
+func (container *container) Close() error {
+	operation := "Close"
+	title := "HCSShim::Container::" + operation
+	logrus.Debugf(title+" id=%s", container.id)
+
+	// Don't double free this
+	if container.handle == 0 {
+		return nil
+	}
+
+	if err := hcsCloseComputeSystem(container.handle); err != nil {
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	container.handle = 0
+
+	logrus.Debugf(title+" succeeded id=%s", container.id)
+	return nil
+}
+
+// closeContainer wraps container.Close for use by a finalizer
+func closeContainer(container *container) {
+	container.Close()
+}
+
+func (container *container) registerCallback(expectedNotification hcsNotification) (uintptr, error) {
+	callbackMapLock.Lock()
+	defer callbackMapLock.Unlock()
+
+	callbackNumber := nextCallback
+	nextCallback++
+
+	context := &notifcationWatcherContext{
+		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
+}

+ 5 - 3
vendor/src/github.com/Microsoft/hcsshim/exportlayer.go

@@ -112,7 +112,9 @@ func (r *FilterLayerReader) Close() (err error) {
 }
 }
 
 
 // NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
 // 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", "")
 	}
 	}

+ 62 - 0
vendor/src/github.com/Microsoft/hcsshim/hcsshim.go

@@ -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
+}

+ 2 - 0
vendor/src/github.com/Microsoft/hcsshim/importlayer.go

@@ -148,6 +148,8 @@ func (r *legacyLayerWriterWrapper) Close() error {
 }
 }
 
 
 // NewLayerWriter returns a new layer writer for creating a layer on disk.
 // 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.

+ 147 - 0
vendor/src/github.com/Microsoft/hcsshim/interface.go

@@ -0,0 +1,147 @@
+package hcsshim
+
+import (
+	"io"
+	"time"
+)
+
+// ProcessConfig is used as both the input of Container.CreateProcess
+// and to convert the parameters to JSON for passing onto the HCS
+type ProcessConfig struct {
+	ApplicationName  string
+	CommandLine      string
+	WorkingDirectory string
+	Environment      map[string]string
+	EmulateConsole   bool
+	CreateStdInPipe  bool
+	CreateStdOutPipe bool
+	CreateStdErrPipe bool
+	ConsoleSize      [2]int
+}
+
+type Layer struct {
+	ID   string
+	Path string
+}
+
+type MappedDir struct {
+	HostPath      string
+	ContainerPath string
+	ReadOnly      bool
+}
+
+type HvRuntime struct {
+	ImagePath string `json:",omitempty"`
+}
+
+// ContainerConfig is used as both the input of CreateContainer
+// and to convert the parameters to JSON for passing onto the HCS
+// TODO Windows: @darrenstahlmsft Add ProcessorCount
+type ContainerConfig struct {
+	SystemType              string      // HCS requires this to be hard-coded to "Container"
+	Name                    string      // Name of the container. We use the docker ID.
+	Owner                   string      // The management platform that created this container
+	IsDummy                 bool        // Used for development purposes.
+	VolumePath              string      // Windows volume path for scratch space
+	IgnoreFlushesDuringBoot bool        // Optimization hint for container startup in Windows
+	LayerFolderPath         string      // Where the layer folders are located
+	Layers                  []Layer     // List of storage layers
+	ProcessorWeight         uint64      `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default.
+	ProcessorMaximum        int64       `json:",omitempty"` // CPU maximum usage percent 1..100
+	StorageIOPSMaximum      uint64      `json:",omitempty"` // Maximum Storage IOPS
+	StorageBandwidthMaximum uint64      `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
+	StorageSandboxSize      uint64      `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
+	MemoryMaximumInMB       int64       `json:",omitempty"` // Maximum memory available to the container in Megabytes
+	HostName                string      // Hostname
+	MappedDirectories       []MappedDir // List of mapped directories (volumes/mounts)
+	SandboxPath             string      // Location of unmounted sandbox (used for Hyper-V containers)
+	HvPartition             bool        // True if it a Hyper-V Container
+	EndpointList            []string    // List of networking endpoints to be attached to container
+	HvRuntime               *HvRuntime  // Hyper-V container settings
+	Servicing               bool        // True if this container is for servicing
+}
+
+const (
+	notificationTypeNone           string = "None"
+	notificationTypeGracefulExit   string = "GracefulExit"
+	notificationTypeForcedExit     string = "ForcedExit"
+	notificationTypeUnexpectedExit string = "UnexpectedExit"
+	notificationTypeReboot         string = "Reboot"
+	notificationTypeConstructed    string = "Constructed"
+	notificationTypeStarted        string = "Started"
+	notificationTypePaused         string = "Paused"
+	notificationTypeUnknown        string = "Unknown"
+)
+
+// Container represents a created (but not necessarily running) container.
+type Container interface {
+	// Start synchronously starts the container.
+	Start() error
+
+	// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
+	Shutdown() error
+
+	// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
+	Terminate() error
+
+	// Waits synchronously waits for the container to shutdown or terminate.
+	Wait() error
+
+	// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
+	// returns false if timeout occurs.
+	WaitTimeout(time.Duration) error
+
+	// Pause pauses the execution of a container.
+	Pause() error
+
+	// Resume resumes the execution of a container.
+	Resume() error
+
+	// HasPendingUpdates returns true if the container has updates pending to install.
+	HasPendingUpdates() (bool, error)
+
+	// CreateProcess launches a new process within the container.
+	CreateProcess(c *ProcessConfig) (Process, error)
+
+	// OpenProcess gets an interface to an existing process within the container.
+	OpenProcess(pid int) (Process, error)
+
+	// Close cleans up any state associated with the container but does not terminate or wait for it.
+	Close() error
+}
+
+// Process represents a running or exited process.
+type Process interface {
+	// Pid returns the process ID of the process within the container.
+	Pid() int
+
+	// Kill signals the process to terminate but does not wait for it to finish terminating.
+	Kill() error
+
+	// Wait waits for the process to exit.
+	Wait() error
+
+	// WaitTimeout waits for the process to exit or the duration to elapse. It returns
+	// false if timeout occurs.
+	WaitTimeout(time.Duration) error
+
+	// ExitCode returns the exit code of the process. The process must have
+	// already terminated.
+	ExitCode() (int, error)
+
+	// ResizeConsole resizes the console of the process.
+	ResizeConsole(width, height uint16) error
+
+	// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
+	// these pipes does not close the underlying pipes; it should be possible to
+	// call this multiple times to get multiple interfaces.
+	Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error)
+
+	// CloseStdin closes the write side of the stdin pipe so that the process is
+	// notified on the read side that there is no more data in stdin.
+	CloseStdin() error
+
+	// Close cleans up any state associated with the process but does not kill
+	// or wait on it.
+	Close() error
+}

+ 15 - 1
vendor/src/github.com/Microsoft/hcsshim/mksyscall_windows.go

@@ -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"}}

+ 432 - 0
vendor/src/github.com/Microsoft/hcsshim/process.go

@@ -0,0 +1,432 @@
+package hcsshim
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"syscall"
+	"time"
+
+	"github.com/Sirupsen/logrus"
+)
+
+var (
+	ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
+)
+
+type ProcessError struct {
+	Process   *process
+	Operation string
+	Err       error
+}
+
+type process struct {
+	handle             hcsProcess
+	processID          int
+	container          *container
+	cachedPipes        *cachedPipes
+	killCallbackNumber uintptr
+}
+
+type cachedPipes struct {
+	stdIn  syscall.Handle
+	stdOut syscall.Handle
+	stdErr syscall.Handle
+}
+
+type processModifyRequest struct {
+	Operation   string
+	ConsoleSize *consoleSize `json:",omitempty"`
+	CloseHandle *closeHandle `json:",omitempty"`
+}
+
+type consoleSize struct {
+	Height uint16
+	Width  uint16
+}
+
+type closeHandle struct {
+	Handle string
+}
+
+type processStatus struct {
+	ProcessId      uint32
+	Exited         bool
+	ExitCode       uint32
+	LastWaitResult int32
+}
+
+const (
+	stdIn  string = "StdIn"
+	stdOut string = "StdOut"
+	stdErr string = "StdErr"
+)
+
+const (
+	modifyConsoleSize string = "ConsoleSize"
+	modifyCloseHandle string = "CloseHandle"
+)
+
+// Pid returns the process ID of the process within the container.
+func (process *process) Pid() int {
+	return process.processID
+}
+
+// Kill signals the process to terminate but does not wait for it to finish terminating.
+func (process *process) Kill() error {
+	operation := "Kill"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	var resultp *uint16
+	err := hcsTerminateProcess(process.handle, &resultp)
+	err = processHcsResult(err, resultp)
+	if err == ErrVmcomputeOperationPending {
+		return ErrVmcomputeOperationPending
+	} else if err != nil {
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
+	return nil
+}
+
+// Wait waits for the process to exit.
+func (process *process) Wait() error {
+	operation := "Wait"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	if hcsCallbacksSupported {
+		err := registerAndWaitForCallback(process, hcsNotificationProcessExited)
+		if err != nil {
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	} else {
+		_, err := process.waitTimeoutInternal(syscall.INFINITE)
+		if err != nil {
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
+	return nil
+}
+
+// WaitTimeout waits for the process to exit or the duration to elapse. It returns
+// false if timeout occurs.
+func (process *process) WaitTimeout(timeout time.Duration) error {
+	operation := "WaitTimeout"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	if hcsCallbacksSupported {
+		err := registerAndWaitForCallbackTimeout(process, hcsNotificationProcessExited, timeout)
+		if err == ErrTimeout {
+			return ErrTimeout
+		} else if err != nil {
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	} else {
+		finished, err := waitTimeoutHelper(process, timeout)
+		if !finished {
+			return ErrTimeout
+		} else if err != nil {
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
+			logrus.Error(err)
+			return err
+		}
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
+	return nil
+}
+
+func (process *process) hcsWait(timeout uint32) (bool, error) {
+	var (
+		resultp   *uint16
+		exitEvent syscall.Handle
+	)
+	err := hcsCreateProcessWait(process.handle, &exitEvent, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		return false, err
+	}
+	defer syscall.CloseHandle(exitEvent)
+
+	return waitForSingleObject(exitEvent, timeout)
+}
+
+func (process *process) waitTimeoutInternal(timeout uint32) (bool, error) {
+	return waitTimeoutInternalHelper(process, timeout)
+}
+
+// ExitCode returns the exit code of the process. The process must have
+// already terminated.
+func (process *process) ExitCode() (int, error) {
+	operation := "ExitCode"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	properties, err := process.properties()
+	if err != nil {
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
+		logrus.Error(err)
+		return 0, err
+	}
+
+	if properties.Exited == false {
+		return 0, ErrInvalidProcessState
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode)
+	return int(properties.ExitCode), nil
+}
+
+// ResizeConsole resizes the console of the process.
+func (process *process) ResizeConsole(width, height uint16) error {
+	operation := "ResizeConsole"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	modifyRequest := processModifyRequest{
+		Operation: modifyConsoleSize,
+		ConsoleSize: &consoleSize{
+			Height: height,
+			Width:  width,
+		},
+	}
+
+	modifyRequestb, err := json.Marshal(modifyRequest)
+	if err != nil {
+		return err
+	}
+
+	modifyRequestStr := string(modifyRequestb)
+
+	var resultp *uint16
+	err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
+	return nil
+}
+
+func (process *process) properties() (*processStatus, error) {
+	operation := "properties"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	var (
+		resultp     *uint16
+		propertiesp *uint16
+	)
+	err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
+		logrus.Error(err)
+		return nil, err
+	}
+
+	if propertiesp == nil {
+		return nil, errors.New("Unexpected result from hcsGetProcessProperties, properties should never be nil")
+	}
+	propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
+
+	properties := &processStatus{}
+	if err := json.Unmarshal(propertiesRaw, properties); err != nil {
+		return nil, err
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw)
+	return properties, nil
+}
+
+// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
+// these pipes does not close the underlying pipes; it should be possible to
+// call this multiple times to get multiple interfaces.
+func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
+	operation := "Stdio"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	var stdIn, stdOut, stdErr syscall.Handle
+
+	if process.cachedPipes == nil {
+		var (
+			processInfo hcsProcessInformation
+			resultp     *uint16
+		)
+		err := hcsGetProcessInfo(process.handle, &processInfo, &resultp)
+		err = processHcsResult(err, resultp)
+		if err != nil {
+			err = &ProcessError{Operation: operation, Process: process, Err: err}
+			logrus.Error(err)
+			return nil, nil, nil, err
+		}
+
+		stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError
+	} else {
+		// Use cached pipes
+		stdIn, stdOut, stdErr = process.cachedPipes.stdIn, process.cachedPipes.stdOut, process.cachedPipes.stdErr
+
+		// Invalidate the cache
+		process.cachedPipes = nil
+	}
+
+	pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr})
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
+	return pipes[0], pipes[1], pipes[2], nil
+}
+
+// CloseStdin closes the write side of the stdin pipe so that the process is
+// notified on the read side that there is no more data in stdin.
+func (process *process) CloseStdin() error {
+	operation := "CloseStdin"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	modifyRequest := processModifyRequest{
+		Operation: modifyCloseHandle,
+		CloseHandle: &closeHandle{
+			Handle: stdIn,
+		},
+	}
+
+	modifyRequestb, err := json.Marshal(modifyRequest)
+	if err != nil {
+		return err
+	}
+
+	modifyRequestStr := string(modifyRequestb)
+
+	var resultp *uint16
+	err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
+	err = processHcsResult(err, resultp)
+	if err != nil {
+		err = &ProcessError{Operation: operation, Process: process, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
+	return nil
+}
+
+// Close cleans up any state associated with the process but does not kill
+// or wait on it.
+func (process *process) Close() error {
+	operation := "Close"
+	title := "HCSShim::Process::" + operation
+	logrus.Debugf(title+" processid=%d", process.processID)
+
+	// Don't double free this
+	if process.handle == 0 {
+		return nil
+	}
+
+	if err := hcsCloseProcess(process.handle); err != nil {
+		err = &ProcessError{Operation: operation, Process: process, Err: err}
+		logrus.Error(err)
+		return err
+	}
+
+	process.handle = 0
+
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
+	return nil
+}
+
+// closeProcess wraps process.Close for use by a finalizer
+func closeProcess(process *process) {
+	process.Close()
+}
+
+func (process *process) registerCallback(expectedNotification hcsNotification) (uintptr, error) {
+	callbackMapLock.Lock()
+	defer callbackMapLock.Unlock()
+
+	callbackNumber := nextCallback
+	nextCallback++
+
+	context := &notifcationWatcherContext{
+		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
+}

+ 11 - 0
vendor/src/github.com/Microsoft/hcsshim/utils.go

@@ -0,0 +1,11 @@
+package hcsshim
+
+import (
+	"syscall"
+)
+
+var (
+	vmcomputedll          = syscall.NewLazyDLL("vmcompute.dll")
+	hcsCallbackAPI        = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback")
+	hcsCallbacksSupported = hcsCallbackAPI.Find() == nil
+)

+ 113 - 0
vendor/src/github.com/Microsoft/hcsshim/waithelper.go

@@ -0,0 +1,113 @@
+package hcsshim
+
+import (
+	"syscall"
+	"time"
+)
+
+type waitable interface {
+	waitTimeoutInternal(timeout uint32) (bool, error)
+	hcsWait(timeout uint32) (bool, error)
+}
+
+type callbackable interface {
+	registerCallback(expectedNotification hcsNotification) (uintptr, error)
+	unregisterCallback(callbackNumber uintptr) error
+}
+
+func waitTimeoutHelper(object waitable, timeout time.Duration) (bool, error) {
+	var (
+		millis uint32
+	)
+
+	for totalMillis := uint64(timeout / time.Millisecond); totalMillis > 0; totalMillis = totalMillis - uint64(millis) {
+		if totalMillis >= syscall.INFINITE {
+			millis = syscall.INFINITE - 1
+		} else {
+			millis = uint32(totalMillis)
+		}
+
+		result, err := object.waitTimeoutInternal(millis)
+
+		if err != nil {
+			return result, err
+		}
+	}
+	return true, nil
+}
+
+func waitTimeoutInternalHelper(object waitable, timeout uint32) (bool, error) {
+	return object.hcsWait(timeout)
+}
+
+func waitForSingleObject(handle syscall.Handle, timeout uint32) (bool, error) {
+	s, e := syscall.WaitForSingleObject(handle, timeout)
+	switch s {
+	case syscall.WAIT_OBJECT_0:
+		return true, nil
+	case syscall.WAIT_TIMEOUT:
+		return false, nil
+	default:
+		return false, e
+	}
+}
+
+func processAsyncHcsResult(object callbackable, err error, resultp *uint16, expectedNotification hcsNotification, timeout *time.Duration) error {
+	err = processHcsResult(err, resultp)
+	if err == ErrVmcomputeOperationPending {
+		if timeout != nil {
+			err = registerAndWaitForCallbackTimeout(object, expectedNotification, *timeout)
+		} else {
+			err = registerAndWaitForCallback(object, expectedNotification)
+		}
+	}
+
+	return err
+}
+
+func registerAndWaitForCallbackTimeout(object callbackable, expectedNotification hcsNotification, timeout time.Duration) error {
+	callbackNumber, err := object.registerCallback(expectedNotification)
+	if err != nil {
+		return err
+	}
+	defer object.unregisterCallback(callbackNumber)
+
+	return waitForNotificationTimeout(callbackNumber, timeout)
+}
+
+func registerAndWaitForCallback(object callbackable, expectedNotification hcsNotification) error {
+	callbackNumber, err := object.registerCallback(expectedNotification)
+	if err != nil {
+		return err
+	}
+	defer object.unregisterCallback(callbackNumber)
+
+	return waitForNotification(callbackNumber)
+}
+
+func waitForNotificationTimeout(callbackNumber uintptr, timeout time.Duration) error {
+	callbackMapLock.RLock()
+	channel := callbackMap[callbackNumber].channel
+	callbackMapLock.RUnlock()
+
+	timer := time.NewTimer(timeout)
+	defer timer.Stop()
+
+	select {
+	case err := <-channel:
+		return err
+	case <-timer.C:
+		return ErrTimeout
+	}
+}
+
+func waitForNotification(callbackNumber uintptr) error {
+	callbackMapLock.RLock()
+	channel := callbackMap[callbackNumber].channel
+	callbackMapLock.RUnlock()
+
+	select {
+	case err := <-channel:
+		return err
+	}
+}

+ 527 - 6
vendor/src/github.com/Microsoft/hcsshim/zhcsshim.go

@@ -2,11 +2,8 @@
 
 
 package hcsshim
 package hcsshim
 
 
-import (
-	"unsafe"
-
-	"github.com/Microsoft/go-winio"
-)
+import "github.com/Microsoft/go-winio"
+import "unsafe"
 import "syscall"
 import "syscall"
 
 
 var _ unsafe.Pointer
 var _ unsafe.Pointer
@@ -49,7 +46,34 @@ 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")
-	procHNSCall                                    = modvmcompute.NewProc("HNSCall")
+	procHcsEnumerateComputeSystems                 = modvmcompute.NewProc("HcsEnumerateComputeSystems")
+	procHcsCreateComputeSystem                     = modvmcompute.NewProc("HcsCreateComputeSystem")
+	procHcsOpenComputeSystem                       = modvmcompute.NewProc("HcsOpenComputeSystem")
+	procHcsCloseComputeSystem                      = modvmcompute.NewProc("HcsCloseComputeSystem")
+	procHcsStartComputeSystem                      = modvmcompute.NewProc("HcsStartComputeSystem")
+	procHcsShutdownComputeSystem                   = modvmcompute.NewProc("HcsShutdownComputeSystem")
+	procHcsTerminateComputeSystem                  = modvmcompute.NewProc("HcsTerminateComputeSystem")
+	procHcsPauseComputeSystem                      = modvmcompute.NewProc("HcsPauseComputeSystem")
+	procHcsResumeComputeSystem                     = modvmcompute.NewProc("HcsResumeComputeSystem")
+	procHcsGetComputeSystemProperties              = modvmcompute.NewProc("HcsGetComputeSystemProperties")
+	procHcsModifyComputeSystem                     = modvmcompute.NewProc("HcsModifyComputeSystem")
+	procHcsCreateComputeSystemWait                 = modvmcompute.NewProc("HcsCreateComputeSystemWait")
+	procHcsCreateProcess                           = modvmcompute.NewProc("HcsCreateProcess")
+	procHcsOpenProcess                             = modvmcompute.NewProc("HcsOpenProcess")
+	procHcsCloseProcess                            = modvmcompute.NewProc("HcsCloseProcess")
+	procHcsTerminateProcess                        = modvmcompute.NewProc("HcsTerminateProcess")
+	procHcsGetProcessInfo                          = modvmcompute.NewProc("HcsGetProcessInfo")
+	procHcsGetProcessProperties                    = modvmcompute.NewProc("HcsGetProcessProperties")
+	procHcsModifyProcess                           = modvmcompute.NewProc("HcsModifyProcess")
+	procHcsCreateProcessWait                       = modvmcompute.NewProc("HcsCreateProcessWait")
+	procHcsGetServiceProperties                    = modvmcompute.NewProc("HcsGetServiceProperties")
+	procHcsModifyServiceSettings                   = modvmcompute.NewProc("HcsModifyServiceSettings")
+
+	procHcsRegisterComputeSystemCallback   = modvmcompute.NewProc("HcsRegisterComputeSystemCallback")
+	procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback")
+	procHcsRegisterProcessCallback         = modvmcompute.NewProc("HcsRegisterProcessCallback")
+	procHcsUnregisterProcessCallback       = modvmcompute.NewProc("HcsUnregisterProcessCallback")
+	procHNSCall                            = modvmcompute.NewProc("HNSCall")
 )
 )
 
 
 func coTaskMemFree(buffer unsafe.Pointer) {
 func coTaskMemFree(buffer unsafe.Pointer) {
@@ -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)