Merge pull request #1541 from msabansal/defaultgw

Default GW support for overlay networks
This commit is contained in:
Madhu Venugopal 2016-11-08 14:34:26 -08:00 committed by GitHub
commit 1b8698e148
25 changed files with 921 additions and 755 deletions

View File

@ -26,8 +26,8 @@
}, },
{ {
"ImportPath": "github.com/Microsoft/hcsshim", "ImportPath": "github.com/Microsoft/hcsshim",
"Comment": "v0.5.1", "Comment": "v0.5.6",
"Rev": "523023ef1ef8ec08b23bbff88ab68552c5f1a6d7" "Rev": "e439b7d2b63f036d3a50c93a9e0b154a0d50e788"
}, },
{ {
"ImportPath": "github.com/Sirupsen/logrus", "ImportPath": "github.com/Sirupsen/logrus",

View File

@ -23,6 +23,26 @@ type dirInfo struct {
fileInfo winio.FileBasicInfo fileInfo winio.FileBasicInfo
} }
// reapplyDirectoryTimes reapplies directory modification, creation, etc. times
// after processing of the directory tree has completed. The times are expected
// to be ordered such that parent directories come before child directories.
func reapplyDirectoryTimes(dis []dirInfo) error {
for i := range dis {
di := &dis[len(dis)-i-1] // reverse order: process child directories first
f, err := winio.OpenForBackup(di.path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING)
if err != nil {
return err
}
err = winio.SetFileBasicInfo(f, &di.fileInfo)
f.Close()
if err != nil {
return err
}
}
return nil
}
func (w *baseLayerWriter) closeCurrentFile() error { func (w *baseLayerWriter) closeCurrentFile() error {
if w.f != nil { if w.f != nil {
err := w.bw.Close() err := w.bw.Close()
@ -142,18 +162,9 @@ func (w *baseLayerWriter) Close() error {
if w.err == nil { if w.err == nil {
// Restore the file times of all the directories, since they may have // Restore the file times of all the directories, since they may have
// been modified by creating child directories. // been modified by creating child directories.
for i := range w.dirInfo { err = reapplyDirectoryTimes(w.dirInfo)
di := &w.dirInfo[len(w.dirInfo)-i-1] if err != nil {
f, err := winio.OpenForBackup(di.path, uint32(syscall.GENERIC_READ|syscall.GENERIC_WRITE), syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING) return err
if err != nil {
return makeError(err, "Failed to OpenForBackup", di.path)
}
err = winio.SetFileBasicInfo(f, &di.fileInfo)
f.Close()
if err != nil {
return makeError(err, "Failed to SetFileBasicInfo", di.path)
}
} }
err = ProcessBaseLayer(w.root) err = ProcessBaseLayer(w.root)

View File

@ -3,6 +3,7 @@ package hcsshim
import ( import (
"encoding/json" "encoding/json"
"runtime" "runtime"
"sync"
"syscall" "syscall"
"time" "time"
@ -20,12 +21,14 @@ const (
) )
type container struct { type container struct {
handleLock sync.RWMutex
handle hcsSystem handle hcsSystem
id string id string
callbackNumber uintptr callbackNumber uintptr
} }
type containerProperties struct { // ContainerProperties holds the properties for a container and the processes running in that container
type ContainerProperties struct {
ID string `json:"Id"` ID string `json:"Id"`
Name string Name string
SystemType string SystemType string
@ -33,6 +36,8 @@ type containerProperties struct {
SiloGUID string `json:"SiloGuid,omitempty"` SiloGUID string `json:"SiloGuid,omitempty"`
IsDummy bool `json:",omitempty"` IsDummy bool `json:",omitempty"`
RuntimeID string `json:"RuntimeId,omitempty"` RuntimeID string `json:"RuntimeId,omitempty"`
IsRuntimeTemplate bool `json:",omitempty"`
RuntimeImagePath string `json:",omitempty"`
Stopped bool `json:",omitempty"` Stopped bool `json:",omitempty"`
ExitType string `json:",omitempty"` ExitType string `json:",omitempty"`
AreUpdatesPending bool `json:",omitempty"` AreUpdatesPending bool `json:",omitempty"`
@ -116,20 +121,15 @@ func CreateContainer(id string, c *ContainerConfig) (Container, error) {
logrus.Debugf(title+" id=%s config=%s", id, configuration) logrus.Debugf(title+" id=%s config=%s", id, configuration)
var ( var (
resultp *uint16 resultp *uint16
createError error identity syscall.Handle
) )
if hcsCallbacksSupported { createError := hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp)
var identity syscall.Handle
createError = hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp)
if createError == nil || IsPending(createError) { if createError == nil || IsPending(createError) {
if err := container.registerCallback(); err != nil { if err := container.registerCallback(); err != nil {
return nil, makeContainerError(container, operation, "", err) return nil, makeContainerError(container, operation, "", err)
}
} }
} else {
createError = hcsCreateComputeSystemTP5(id, configuration, &container.handle, &resultp)
} }
err = processAsyncHcsResult(createError, resultp, container.callbackNumber, hcsNotificationSystemCreateCompleted, &defaultTimeout) err = processAsyncHcsResult(createError, resultp, container.callbackNumber, hcsNotificationSystemCreateCompleted, &defaultTimeout)
@ -164,19 +164,61 @@ func OpenContainer(id string) (Container, error) {
container.handle = handle container.handle = handle
if err := container.registerCallback(); err != nil {
return nil, makeContainerError(container, operation, "", err)
}
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle) logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
runtime.SetFinalizer(container, closeContainer) runtime.SetFinalizer(container, closeContainer)
return container, nil return container, nil
} }
// GetContainers gets a list of the containers on the system that match the query
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
operation := "GetContainers"
title := "HCSShim::" + operation
queryb, err := json.Marshal(q)
if err != nil {
return nil, err
}
query := string(queryb)
logrus.Debugf(title+" query=%s", query)
var (
resultp *uint16
computeSystemsp *uint16
)
err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp)
err = processHcsResult(err, resultp)
if computeSystemsp == nil {
return nil, ErrUnexpectedValue
}
computeSystemsRaw := convertAndFreeCoTaskMemBytes(computeSystemsp)
computeSystems := []ContainerProperties{}
if err := json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil {
return nil, err
}
logrus.Debugf(title + " succeeded")
return computeSystems, nil
}
// Start synchronously starts the container. // Start synchronously starts the container.
func (container *container) Start() error { func (container *container) Start() error {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "Start" operation := "Start"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return makeContainerError(container, operation, "", ErrAlreadyClosed)
}
var resultp *uint16 var resultp *uint16
err := hcsStartComputeSystemTP5(container.handle, nil, &resultp) err := hcsStartComputeSystem(container.handle, "", &resultp)
err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemStartCompleted, &defaultTimeout) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemStartCompleted, &defaultTimeout)
if err != nil { if err != nil {
return makeContainerError(container, operation, "", err) return makeContainerError(container, operation, "", err)
@ -189,12 +231,18 @@ func (container *container) Start() error {
// Shutdown requests a container shutdown, if IsPending() on the error returned is true, // Shutdown requests a container shutdown, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds. // it may not actually be shut down until Wait() succeeds.
func (container *container) Shutdown() error { func (container *container) Shutdown() error {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "Shutdown" operation := "Shutdown"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return makeContainerError(container, operation, "", ErrAlreadyClosed)
}
var resultp *uint16 var resultp *uint16
err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp) err := hcsShutdownComputeSystem(container.handle, "", &resultp)
err = processHcsResult(err, resultp) err = processHcsResult(err, resultp)
if err != nil { if err != nil {
return makeContainerError(container, operation, "", err) return makeContainerError(container, operation, "", err)
@ -207,12 +255,18 @@ func (container *container) Shutdown() error {
// Terminate requests a container terminate, if IsPending() on the error returned is true, // Terminate requests a container terminate, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds. // it may not actually be shut down until Wait() succeeds.
func (container *container) Terminate() error { func (container *container) Terminate() error {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "Terminate" operation := "Terminate"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return makeContainerError(container, operation, "", ErrAlreadyClosed)
}
var resultp *uint16 var resultp *uint16
err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp) err := hcsTerminateComputeSystem(container.handle, "", &resultp)
err = processHcsResult(err, resultp) err = processHcsResult(err, resultp)
if err != nil { if err != nil {
return makeContainerError(container, operation, "", err) return makeContainerError(container, operation, "", err)
@ -228,26 +282,15 @@ func (container *container) Wait() error {
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if hcsCallbacksSupported { err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil)
err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil) if err != nil {
if err != nil { return makeContainerError(container, operation, "", err)
return makeContainerError(container, operation, "", err)
}
} else {
_, err := container.waitTimeoutInternal(syscall.INFINITE)
if err != nil {
return makeContainerError(container, operation, "", err)
}
} }
logrus.Debugf(title+" succeeded id=%s", container.id) logrus.Debugf(title+" succeeded id=%s", container.id)
return nil 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. // WaitTimeout synchronously waits for the container to terminate or the duration to elapse.
// If the timeout expires, IsTimeout(err) == true // If the timeout expires, IsTimeout(err) == true
func (container *container) WaitTimeout(timeout time.Duration) error { func (container *container) WaitTimeout(timeout time.Duration) error {
@ -255,42 +298,16 @@ func (container *container) WaitTimeout(timeout time.Duration) error {
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if hcsCallbacksSupported { err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout)
err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout) if err != nil {
if err != nil { return makeContainerError(container, operation, "", err)
return makeContainerError(container, operation, "", err)
}
} else {
finished, err := waitTimeoutHelper(container, timeout)
if !finished {
err = ErrTimeout
}
if err != nil {
return makeContainerError(container, operation, "", err)
}
} }
logrus.Debugf(title+" succeeded id=%s", container.id) logrus.Debugf(title+" succeeded id=%s", container.id)
return nil return nil
} }
func (container *container) hcsWait(timeout uint32) (bool, error) { func (container *container) properties(query string) (*ContainerProperties, 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(query string) (*containerProperties, error) {
var ( var (
resultp *uint16 resultp *uint16
propertiesp *uint16 propertiesp *uint16
@ -305,7 +322,7 @@ func (container *container) properties(query string) (*containerProperties, erro
return nil, ErrUnexpectedValue return nil, ErrUnexpectedValue
} }
propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
properties := &containerProperties{} properties := &ContainerProperties{}
if err := json.Unmarshal(propertiesRaw, properties); err != nil { if err := json.Unmarshal(propertiesRaw, properties); err != nil {
return nil, err return nil, err
} }
@ -314,9 +331,16 @@ func (container *container) properties(query string) (*containerProperties, erro
// HasPendingUpdates returns true if the container has updates pending to install // HasPendingUpdates returns true if the container has updates pending to install
func (container *container) HasPendingUpdates() (bool, error) { func (container *container) HasPendingUpdates() (bool, error) {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "HasPendingUpdates" operation := "HasPendingUpdates"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return false, makeContainerError(container, operation, "", ErrAlreadyClosed)
}
properties, err := container.properties(pendingUpdatesQuery) properties, err := container.properties(pendingUpdatesQuery)
if err != nil { if err != nil {
return false, makeContainerError(container, operation, "", err) return false, makeContainerError(container, operation, "", err)
@ -328,9 +352,16 @@ func (container *container) HasPendingUpdates() (bool, error) {
// Statistics returns statistics for the container // Statistics returns statistics for the container
func (container *container) Statistics() (Statistics, error) { func (container *container) Statistics() (Statistics, error) {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "Statistics" operation := "Statistics"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return Statistics{}, makeContainerError(container, operation, "", ErrAlreadyClosed)
}
properties, err := container.properties(statisticsQuery) properties, err := container.properties(statisticsQuery)
if err != nil { if err != nil {
return Statistics{}, makeContainerError(container, operation, "", err) return Statistics{}, makeContainerError(container, operation, "", err)
@ -342,9 +373,16 @@ func (container *container) Statistics() (Statistics, error) {
// ProcessList returns an array of ProcessListItems for the container // ProcessList returns an array of ProcessListItems for the container
func (container *container) ProcessList() ([]ProcessListItem, error) { func (container *container) ProcessList() ([]ProcessListItem, error) {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "ProcessList" operation := "ProcessList"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
}
properties, err := container.properties(processListQuery) properties, err := container.properties(processListQuery)
if err != nil { if err != nil {
return nil, makeContainerError(container, operation, "", err) return nil, makeContainerError(container, operation, "", err)
@ -356,12 +394,18 @@ func (container *container) ProcessList() ([]ProcessListItem, error) {
// Pause pauses the execution of the container. This feature is not enabled in TP5. // Pause pauses the execution of the container. This feature is not enabled in TP5.
func (container *container) Pause() error { func (container *container) Pause() error {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "Pause" operation := "Pause"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return makeContainerError(container, operation, "", ErrAlreadyClosed)
}
var resultp *uint16 var resultp *uint16
err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp) err := hcsPauseComputeSystem(container.handle, "", &resultp)
err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemPauseCompleted, &defaultTimeout) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemPauseCompleted, &defaultTimeout)
if err != nil { if err != nil {
return makeContainerError(container, operation, "", err) return makeContainerError(container, operation, "", err)
@ -373,14 +417,18 @@ func (container *container) Pause() error {
// Resume resumes the execution of the container. This feature is not enabled in TP5. // Resume resumes the execution of the container. This feature is not enabled in TP5.
func (container *container) Resume() error { func (container *container) Resume() error {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "Resume" operation := "Resume"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
var (
resultp *uint16
)
err := hcsResumeComputeSystemTP5(container.handle, nil, &resultp) if container.handle == 0 {
return makeContainerError(container, operation, "", ErrAlreadyClosed)
}
var resultp *uint16
err := hcsResumeComputeSystem(container.handle, "", &resultp)
err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemResumeCompleted, &defaultTimeout) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemResumeCompleted, &defaultTimeout)
if err != nil { if err != nil {
return makeContainerError(container, operation, "", err) return makeContainerError(container, operation, "", err)
@ -392,6 +440,8 @@ func (container *container) Resume() error {
// CreateProcess launches a new process within the container. // CreateProcess launches a new process within the container.
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "CreateProcess" operation := "CreateProcess"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
var ( var (
@ -400,6 +450,10 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
resultp *uint16 resultp *uint16
) )
if container.handle == 0 {
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
}
// If we are not emulating a console, ignore any console size passed to us // If we are not emulating a console, ignore any console size passed to us
if !c.EmulateConsole { if !c.EmulateConsole {
c.ConsoleSize[0] = 0 c.ConsoleSize[0] = 0
@ -431,10 +485,8 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
}, },
} }
if hcsCallbacksSupported { if err := process.registerCallback(); err != nil {
if err := process.registerCallback(); err != nil { return nil, makeContainerError(container, operation, "", err)
return nil, makeContainerError(container, operation, "", err)
}
} }
logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
@ -444,6 +496,8 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
// OpenProcess gets an interface to an existing process within the container. // OpenProcess gets an interface to an existing process within the container.
func (container *container) OpenProcess(pid int) (Process, error) { func (container *container) OpenProcess(pid int) (Process, error) {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "OpenProcess" operation := "OpenProcess"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s, processid=%d", container.id, pid) logrus.Debugf(title+" id=%s, processid=%d", container.id, pid)
@ -452,6 +506,10 @@ func (container *container) OpenProcess(pid int) (Process, error) {
resultp *uint16 resultp *uint16
) )
if container.handle == 0 {
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
}
err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp) err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp)
err = processHcsResult(err, resultp) err = processHcsResult(err, resultp)
if err != nil { if err != nil {
@ -464,10 +522,8 @@ func (container *container) OpenProcess(pid int) (Process, error) {
container: container, container: container,
} }
if hcsCallbacksSupported { if err := process.registerCallback(); err != nil {
if err := process.registerCallback(); err != nil { return nil, makeContainerError(container, operation, "", err)
return nil, makeContainerError(container, operation, "", err)
}
} }
logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
@ -477,6 +533,8 @@ func (container *container) OpenProcess(pid int) (Process, error) {
// Close cleans up any state associated with the container but does not terminate or wait for it. // Close cleans up any state associated with the container but does not terminate or wait for it.
func (container *container) Close() error { func (container *container) Close() error {
container.handleLock.Lock()
defer container.handleLock.Unlock()
operation := "Close" operation := "Close"
title := "HCSShim::Container::" + operation title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id) logrus.Debugf(title+" id=%s", container.id)
@ -486,10 +544,8 @@ func (container *container) Close() error {
return nil return nil
} }
if hcsCallbacksSupported { if err := container.unregisterCallback(); err != nil {
if err := container.unregisterCallback(); err != nil { return makeContainerError(container, operation, "", err)
return makeContainerError(container, operation, "", err)
}
} }
if err := hcsCloseComputeSystem(container.handle); err != nil { if err := hcsCloseComputeSystem(container.handle); err != nil {
@ -497,6 +553,7 @@ func (container *container) Close() error {
} }
container.handle = 0 container.handle = 0
runtime.SetFinalizer(container, nil)
logrus.Debugf(title+" succeeded id=%s", container.id) logrus.Debugf(title+" succeeded id=%s", container.id)
return nil return nil

View File

@ -16,6 +16,9 @@ var (
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed // ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed") ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used // ErrInvalidNotificationType is an error encountered when an invalid notification type is used
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type") ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
@ -80,8 +83,13 @@ func (e *ContainerError) Error() string {
s += " encountered an error during " + e.Operation s += " encountered an error during " + e.Operation
} }
if e.Err != nil { switch e.Err.(type) {
s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) case nil:
break
case syscall.Errno:
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err))
default:
s += fmt.Sprintf(": %s", e.Err.Error())
} }
if e.ExtraInfo != "" { if e.ExtraInfo != "" {
@ -116,16 +124,16 @@ func (e *ProcessError) Error() string {
} }
if e.Operation != "" { if e.Operation != "" {
s += " " + e.Operation s += " encountered an error during " + e.Operation
} }
switch e.Err.(type) { switch e.Err.(type) {
case nil: case nil:
break break
case syscall.Errno: case syscall.Errno:
s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err))
default: default:
s += fmt.Sprintf(" failed: %s", e.Error()) s += fmt.Sprintf(": %s", e.Err.Error())
} }
return s return s
@ -151,6 +159,13 @@ func IsNotExist(err error) bool {
err == ErrProcNotFound err == ErrProcNotFound
} }
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
// already closed by a call to the Close() method.
func IsAlreadyClosed(err error) bool {
err = getInnerError(err)
return err == ErrAlreadyClosed
}
// IsPending returns a boolean indicating whether the error is that // IsPending returns a boolean indicating whether the error is that
// the requested operation is being completed in the background. // the requested operation is being completed in the background.
func IsPending(err error) bool { func IsPending(err error) bool {

View File

@ -1,4 +1,4 @@
// Shim for the Host Compute Service (HSC) to manage Windows Server // Shim for the Host Compute Service (HCS) to manage Windows Server
// containers and Hyper-V containers. // containers and Hyper-V containers.
package hcsshim package hcsshim
@ -44,16 +44,6 @@ import (
//sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead? //sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead?
//sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd? //sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd?
//sys createComputeSystem(id string, configuration string) (hr error) = vmcompute.CreateComputeSystem?
//sys createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) = vmcompute.CreateProcessWithStdHandlesInComputeSystem?
//sys resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) = vmcompute.ResizeConsoleInComputeSystem?
//sys shutdownComputeSystem(id string, timeout uint32) (hr error) = vmcompute.ShutdownComputeSystem?
//sys startComputeSystem(id string) (hr error) = vmcompute.StartComputeSystem?
//sys terminateComputeSystem(id string) (hr error) = vmcompute.TerminateComputeSystem?
//sys terminateProcessInComputeSystem(id string, pid uint32) (hr error) = vmcompute.TerminateProcessInComputeSystem?
//sys waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) = vmcompute.WaitForProcessInComputeSystem?
//sys getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) = vmcompute.GetComputeSystemProperties?
//sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems? //sys 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 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 hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem?
@ -65,7 +55,9 @@ import (
//sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? //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 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 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 hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback?
//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback?
//sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess? //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 hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess?
//sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess? //sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess?
@ -73,21 +65,12 @@ import (
//sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo? //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 hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties?
//sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess? //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 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 hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback?
//sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback? //sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback?
//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings?
//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 (

View File

@ -52,7 +52,7 @@ type MacPool struct {
// HNSNetwork represents a network in HNS // HNSNetwork represents a network in HNS
type HNSNetwork struct { type HNSNetwork struct {
Id string `json:",omitempty"` Id string `json:"ID,omitempty"`
Name string `json:",omitempty"` Name string `json:",omitempty"`
Type string `json:",omitempty"` Type string `json:",omitempty"`
NetworkAdapterName string `json:",omitempty"` NetworkAdapterName string `json:",omitempty"`
@ -68,7 +68,7 @@ type HNSNetwork struct {
// HNSEndpoint represents a network endpoint in HNS // HNSEndpoint represents a network endpoint in HNS
type HNSEndpoint struct { type HNSEndpoint struct {
Id string `json:",omitempty"` Id string `json:"ID,omitempty"`
Name string `json:",omitempty"` Name string `json:",omitempty"`
VirtualNetwork string `json:",omitempty"` VirtualNetwork string `json:",omitempty"`
VirtualNetworkName string `json:",omitempty"` VirtualNetworkName string `json:",omitempty"`
@ -79,6 +79,7 @@ type HNSEndpoint struct {
DNSServerList string `json:",omitempty"` DNSServerList string `json:",omitempty"`
GatewayAddress string `json:",omitempty"` GatewayAddress string `json:",omitempty"`
EnableInternalDNS bool `json:",omitempty"` EnableInternalDNS bool `json:",omitempty"`
DisableICC bool `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"` PrefixLength uint8 `json:",omitempty"`
IsRemoteEndpoint bool `json:",omitempty"` IsRemoteEndpoint bool `json:",omitempty"`
} }

View File

@ -130,21 +130,42 @@ type legacyLayerWriterWrapper struct {
} }
func (r *legacyLayerWriterWrapper) Close() error { func (r *legacyLayerWriterWrapper) Close() error {
defer os.RemoveAll(r.root)
err := r.legacyLayerWriter.Close() err := r.legacyLayerWriter.Close()
if err == nil { if err != nil {
var fullPath string return err
// Use the original path here because ImportLayer does not support long paths for the source in TP5. }
// But do use a long path for the destination to work around another bug with directories
// with MAX_PATH - 12 < length < MAX_PATH. // Use the original path here because ImportLayer does not support long paths for the source in TP5.
info := r.info // But do use a long path for the destination to work around another bug with directories
fullPath, err = makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) // with MAX_PATH - 12 < length < MAX_PATH.
if err == nil { info := r.info
info.HomeDir = "" fullPath, err := makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID))
err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths) if err != nil {
return err
}
info.HomeDir = ""
if err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths); err != nil {
return err
}
// Add any hard links that were collected.
for _, lnk := range r.PendingLinks {
if err = os.Remove(lnk.Path); err != nil && !os.IsNotExist(err) {
return err
}
if err = os.Link(lnk.Target, lnk.Path); err != nil {
return err
} }
} }
os.RemoveAll(r.root) // Prepare the utility VM for use if one is present in the layer.
return err if r.HasUtilityVM {
err = ProcessUtilityVMImage(filepath.Join(fullPath, "UtilityVM"))
if err != nil {
return err
}
}
return nil
} }
// NewLayerWriter returns a new layer writer for creating a layer on disk. // NewLayerWriter returns a new layer writer for creating a layer on disk.
@ -166,7 +187,7 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string)
return nil, err return nil, err
} }
return &legacyLayerWriterWrapper{ return &legacyLayerWriterWrapper{
legacyLayerWriter: newLegacyLayerWriter(path), legacyLayerWriter: newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID)),
info: info, info: info,
layerID: layerID, layerID: layerID,
path: path, path: path,

View File

@ -10,13 +10,14 @@ import (
type ProcessConfig struct { type ProcessConfig struct {
ApplicationName string ApplicationName string
CommandLine string CommandLine string
User string
WorkingDirectory string WorkingDirectory string
Environment map[string]string Environment map[string]string
EmulateConsole bool EmulateConsole bool
CreateStdInPipe bool CreateStdInPipe bool
CreateStdOutPipe bool CreateStdOutPipe bool
CreateStdErrPipe bool CreateStdErrPipe bool
ConsoleSize [2]int ConsoleSize [2]uint
} }
type Layer struct { type Layer struct {
@ -25,9 +26,11 @@ type Layer struct {
} }
type MappedDir struct { type MappedDir struct {
HostPath string HostPath string
ContainerPath string ContainerPath string
ReadOnly bool ReadOnly bool
BandwidthMaximum uint64
IOPSMaximum uint64
} }
type HvRuntime struct { type HvRuntime struct {
@ -42,10 +45,10 @@ type ContainerConfig struct {
Name string // Name of the container. We use the docker ID. Name string // Name of the container. We use the docker ID.
Owner string // The management platform that created this container Owner string // The management platform that created this container
IsDummy bool // Used for development purposes. IsDummy bool // Used for development purposes.
VolumePath string // Windows volume path for scratch space VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows
LayerFolderPath string // Where the layer folders are located LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
Layers []Layer // List of storage layers Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
Credentials string `json:",omitempty"` // Credentials information Credentials string `json:",omitempty"` // Credentials information
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container. ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default. ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default.
@ -56,14 +59,21 @@ type ContainerConfig struct {
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
HostName string // Hostname HostName string // Hostname
MappedDirectories []MappedDir // List of mapped directories (volumes/mounts) MappedDirectories []MappedDir // List of mapped directories (volumes/mounts)
SandboxPath string // Location of unmounted sandbox (used for Hyper-V containers) SandboxPath string `json:",omitempty"` // Location of unmounted sandbox. Used by Hyper-V containers only. Format %root%\windowsfilter
HvPartition bool // True if it a Hyper-V Container HvPartition bool // True if it a Hyper-V Container
EndpointList []string // List of networking endpoints to be attached to container EndpointList []string // List of networking endpoints to be attached to container
HvRuntime *HvRuntime // Hyper-V container settings HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
Servicing bool // True if this container is for servicing Servicing bool // True if this container is for servicing
AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution
} }
type ComputeSystemQuery struct {
IDs []string `json:"Ids,omitempty"`
Types []string `json:",omitempty"`
Names []string `json:",omitempty"`
Owners []string `json:",omitempty"`
}
// Container represents a created (but not necessarily running) container. // Container represents a created (but not necessarily running) container.
type Container interface { type Container interface {
// Start synchronously starts the container. // Start synchronously starts the container.

View File

@ -16,6 +16,13 @@ import (
var errorIterationCanceled = errors.New("") var errorIterationCanceled = errors.New("")
var mutatedUtilityVMFiles = map[string]bool{
`EFI\Microsoft\Boot\BCD`: true,
`EFI\Microsoft\Boot\BCD.LOG`: true,
`EFI\Microsoft\Boot\BCD.LOG1`: true,
`EFI\Microsoft\Boot\BCD.LOG2`: true,
}
func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) { func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) {
return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition) return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition)
} }
@ -49,17 +56,15 @@ type legacyLayerReader struct {
proceed chan bool proceed chan bool
currentFile *os.File currentFile *os.File
backupReader *winio.BackupFileReader backupReader *winio.BackupFileReader
isTP4Format bool
} }
// newLegacyLayerReader returns a new LayerReader that can read the Windows // newLegacyLayerReader returns a new LayerReader that can read the Windows
// TP4 transport format from disk. // container layer transport format from disk.
func newLegacyLayerReader(root string) *legacyLayerReader { func newLegacyLayerReader(root string) *legacyLayerReader {
r := &legacyLayerReader{ r := &legacyLayerReader{
root: root, root: root,
result: make(chan *fileEntry), result: make(chan *fileEntry),
proceed: make(chan bool), proceed: make(chan bool),
isTP4Format: IsTP4(),
} }
go r.walk() go r.walk()
return r return r
@ -251,17 +256,14 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil
fileInfo.LastAccessTime = fileInfo.LastWriteTime fileInfo.LastAccessTime = fileInfo.LastWriteTime
} else { } else {
beginning := int64(0) // The file attributes are written before the backup stream.
if !r.isTP4Format { var attr uint32
// In TP5, the file attributes were added before the backup stream err = binary.Read(f, binary.LittleEndian, &attr)
var attr uint32 if err != nil {
err = binary.Read(f, binary.LittleEndian, &attr) return
if err != nil {
return
}
fileInfo.FileAttributes = uintptr(attr)
beginning = 4
} }
fileInfo.FileAttributes = uintptr(attr)
beginning := int64(4)
// Find the accurate file size. // Find the accurate file size.
if !fe.fi.IsDir() { if !fe.fi.IsDir() {
@ -301,21 +303,32 @@ func (r *legacyLayerReader) Close() error {
return nil return nil
} }
type pendingLink struct {
Path, Target string
}
type legacyLayerWriter struct { type legacyLayerWriter struct {
root string root string
parentRoots []string
destRoot string
currentFile *os.File currentFile *os.File
backupWriter *winio.BackupFileWriter backupWriter *winio.BackupFileWriter
tombstones []string tombstones []string
isTP4Format bool
pathFixed bool pathFixed bool
HasUtilityVM bool
uvmDi []dirInfo
addedFiles map[string]bool
PendingLinks []pendingLink
} }
// newLegacyLayerWriter returns a LayerWriter that can write the TP4 transport format // newLegacyLayerWriter returns a LayerWriter that can write the contaler layer
// to disk. // transport format to disk.
func newLegacyLayerWriter(root string) *legacyLayerWriter { func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) *legacyLayerWriter {
return &legacyLayerWriter{ return &legacyLayerWriter{
root: root, root: root,
isTP4Format: IsTP4(), parentRoots: parentRoots,
destRoot: destRoot,
addedFiles: make(map[string]bool),
} }
} }
@ -325,12 +338,42 @@ func (w *legacyLayerWriter) init() error {
if err != nil { if err != nil {
return err return err
} }
for i, p := range w.parentRoots {
w.parentRoots[i], err = makeLongAbsPath(p)
if err != nil {
return err
}
}
destPath, err := makeLongAbsPath(w.destRoot)
if err != nil {
return err
}
w.root = path w.root = path
w.destRoot = destPath
w.pathFixed = true w.pathFixed = true
} }
return nil return nil
} }
func (w *legacyLayerWriter) initUtilityVM() error {
if !w.HasUtilityVM {
err := os.Mkdir(filepath.Join(w.destRoot, `UtilityVM`), 0)
if err != nil {
return err
}
// Server 2016 does not support multiple layers for the utility VM, so
// clone the utility VM from the parent layer into this layer. Use hard
// links to avoid unnecessary copying, since most of the files are
// immutable.
err = cloneTree(filepath.Join(w.parentRoots[0], `UtilityVM\Files`), filepath.Join(w.destRoot, `UtilityVM\Files`), mutatedUtilityVMFiles)
if err != nil {
return fmt.Errorf("cloning the parent utility VM image failed: %s", err)
}
w.HasUtilityVM = true
}
return nil
}
func (w *legacyLayerWriter) reset() { func (w *legacyLayerWriter) reset() {
if w.backupWriter != nil { if w.backupWriter != nil {
w.backupWriter.Close() w.backupWriter.Close()
@ -342,15 +385,180 @@ func (w *legacyLayerWriter) reset() {
} }
} }
// copyFileWithMetadata copies a file using the backup/restore APIs in order to preserve metadata
func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) {
createDisposition := uint32(syscall.CREATE_NEW)
if isDir {
err = os.Mkdir(destPath, 0)
if err != nil {
return nil, err
}
createDisposition = syscall.OPEN_EXISTING
}
src, err := openFileOrDir(srcPath, syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY, syscall.OPEN_EXISTING)
if err != nil {
return nil, err
}
defer src.Close()
srcr := winio.NewBackupFileReader(src, true)
defer srcr.Close()
fileInfo, err = winio.GetFileBasicInfo(src)
if err != nil {
return nil, err
}
dest, err := openFileOrDir(destPath, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition)
if err != nil {
return nil, err
}
defer dest.Close()
err = winio.SetFileBasicInfo(dest, fileInfo)
if err != nil {
return nil, err
}
destw := winio.NewBackupFileWriter(dest, true)
defer func() {
cerr := destw.Close()
if err == nil {
err = cerr
}
}()
_, err = io.Copy(destw, srcr)
if err != nil {
return nil, err
}
return fileInfo, nil
}
// cloneTree clones a directory tree using hard links. It skips hard links for
// the file names in the provided map and just copies those files.
func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error {
var di []dirInfo
err := filepath.Walk(srcPath, func(srcFilePath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
relPath, err := filepath.Rel(srcPath, srcFilePath)
if err != nil {
return err
}
destFilePath := filepath.Join(destPath, relPath)
// Directories, reparse points, and files that will be mutated during
// utility VM import must be copied. All other files can be hard linked.
isReparsePoint := info.Sys().(*syscall.Win32FileAttributeData).FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0
if info.IsDir() || isReparsePoint || mutatedFiles[relPath] {
fi, err := copyFileWithMetadata(srcFilePath, destFilePath, info.IsDir())
if err != nil {
return err
}
if info.IsDir() && !isReparsePoint {
di = append(di, dirInfo{path: destFilePath, fileInfo: *fi})
}
} else {
err = os.Link(srcFilePath, destFilePath)
if err != nil {
return err
}
}
// Don't recurse on reparse points.
if info.IsDir() && isReparsePoint {
return filepath.SkipDir
}
return nil
})
if err != nil {
return err
}
return reapplyDirectoryTimes(di)
}
func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error { func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
w.reset() w.reset()
err := w.init() err := w.init()
if err != nil { if err != nil {
return err return err
} }
path := filepath.Join(w.root, name)
createDisposition := uint32(syscall.CREATE_NEW) if name == `UtilityVM` {
return w.initUtilityVM()
}
if strings.HasPrefix(name, `UtilityVM\`) {
if !w.HasUtilityVM {
return errors.New("missing UtilityVM directory")
}
if !strings.HasPrefix(name, `UtilityVM\Files\`) && name != `UtilityVM\Files` {
return errors.New("invalid UtilityVM layer")
}
path := filepath.Join(w.destRoot, name)
createDisposition := uint32(syscall.OPEN_EXISTING)
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
st, err := os.Lstat(path)
if err != nil && !os.IsNotExist(err) {
return err
}
if st != nil {
// Delete the existing file/directory if it is not the same type as this directory.
existingAttr := st.Sys().(*syscall.Win32FileAttributeData).FileAttributes
if (uint32(fileInfo.FileAttributes)^existingAttr)&(syscall.FILE_ATTRIBUTE_DIRECTORY|syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
if err = os.RemoveAll(path); err != nil {
return err
}
st = nil
}
}
if st == nil {
if err = os.Mkdir(path, 0); err != nil {
return err
}
}
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
w.uvmDi = append(w.uvmDi, dirInfo{path: path, fileInfo: *fileInfo})
}
} else {
// Overwrite any existing hard link.
err = os.Remove(path)
if err != nil && !os.IsNotExist(err) {
return err
}
createDisposition = syscall.CREATE_NEW
}
f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition)
if err != nil {
return err
}
defer func() {
if f != nil {
f.Close()
os.Remove(path)
}
}()
err = winio.SetFileBasicInfo(f, fileInfo)
if err != nil {
return err
}
w.backupWriter = winio.NewBackupFileWriter(f, true)
w.currentFile = f
w.addedFiles[name] = true
f = nil
return nil
}
path := filepath.Join(w.root, name)
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
err := os.Mkdir(path, 0) err := os.Mkdir(path, 0)
if err != nil { if err != nil {
@ -359,7 +567,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
path += ".$wcidirs$" path += ".$wcidirs$"
} }
f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, createDisposition) f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.CREATE_NEW)
if err != nil { if err != nil {
return err return err
} }
@ -380,29 +588,97 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
if strings.HasPrefix(name, `Hives\`) { if strings.HasPrefix(name, `Hives\`) {
w.backupWriter = winio.NewBackupFileWriter(f, false) w.backupWriter = winio.NewBackupFileWriter(f, false)
} else { } else {
if !w.isTP4Format { // The file attributes are written before the stream.
// In TP5, the file attributes were added to the header err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes))
err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes)) if err != nil {
if err != nil { return err
return err
}
} }
} }
w.currentFile = f w.currentFile = f
w.addedFiles[name] = true
f = nil f = nil
return nil return nil
} }
func (w *legacyLayerWriter) AddLink(name string, target string) error { func (w *legacyLayerWriter) AddLink(name string, target string) error {
return errors.New("hard links not supported with legacy writer") w.reset()
err := w.init()
if err != nil {
return err
}
var requiredPrefix string
var roots []string
if prefix := `Files\`; strings.HasPrefix(name, prefix) {
requiredPrefix = prefix
// Look for cross-layer hard link targets in the parent layers, since
// nothing is in the destination path yet.
roots = w.parentRoots
} else if prefix := `UtilityVM\Files\`; strings.HasPrefix(name, prefix) {
requiredPrefix = prefix
// Since the utility VM is fully cloned into the destination path
// already, look for cross-layer hard link targets directly in the
// destination path.
roots = []string{w.destRoot}
}
if requiredPrefix == "" || !strings.HasPrefix(target, requiredPrefix) {
return errors.New("invalid hard link in layer")
}
// Find to try the target of the link in a previously added file. If that
// fails, search in parent layers.
var selectedRoot string
if _, ok := w.addedFiles[target]; ok {
selectedRoot = w.destRoot
} else {
for _, r := range roots {
if _, err = os.Lstat(filepath.Join(r, target)); err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
selectedRoot = r
break
}
}
if selectedRoot == "" {
return fmt.Errorf("failed to find link target for '%s' -> '%s'", name, target)
}
}
// The link can't be written until after the ImportLayer call.
w.PendingLinks = append(w.PendingLinks, pendingLink{
Path: filepath.Join(w.destRoot, name),
Target: filepath.Join(selectedRoot, target),
})
w.addedFiles[name] = true
return nil
} }
func (w *legacyLayerWriter) Remove(name string) error { func (w *legacyLayerWriter) Remove(name string) error {
if !strings.HasPrefix(name, `Files\`) { if strings.HasPrefix(name, `Files\`) {
w.tombstones = append(w.tombstones, name[len(`Files\`):])
} else if strings.HasPrefix(name, `UtilityVM\Files\`) {
err := w.initUtilityVM()
if err != nil {
return err
}
// Make sure the path exists; os.RemoveAll will not fail if the file is
// already gone, and this needs to be a fatal error for diagnostics
// purposes.
path := filepath.Join(w.destRoot, name)
if _, err := os.Lstat(path); err != nil {
return err
}
err = os.RemoveAll(path)
if err != nil {
return err
}
} else {
return fmt.Errorf("invalid tombstone %s", name) return fmt.Errorf("invalid tombstone %s", name)
} }
w.tombstones = append(w.tombstones, name[len(`Files\`):])
return nil return nil
} }
@ -437,5 +713,11 @@ func (w *legacyLayerWriter) Close() error {
return err return err
} }
} }
if w.HasUtilityVM {
err = reapplyDirectoryTimes(w.uvmDi)
if err != nil {
return err
}
}
return nil return nil
} }

View File

@ -1,6 +1,12 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import (
"sync"
"github.com/Sirupsen/logrus"
)
var prepareLayerLock sync.Mutex
// PrepareLayer finds a mounted read-write layer matching layerId and enables the // PrepareLayer finds a mounted read-write layer matching layerId and enables the
// the filesystem filter for use on that layer. This requires the paths to all // the filesystem filter for use on that layer. This requires the paths to all
@ -24,6 +30,10 @@ func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) er
return err return err
} }
// This lock is a temporary workaround for a Windows bug. Only allowing one
// call to prepareLayer at a time vastly reduces the chance of a timeout.
prepareLayerLock.Lock()
defer prepareLayerLock.Unlock()
err = prepareLayer(&infop, layerId, layers) err = prepareLayer(&infop, layerId, layers)
if err != nil { if err != nil {
err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour) err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour)

View File

@ -3,6 +3,8 @@ package hcsshim
import ( import (
"encoding/json" "encoding/json"
"io" "io"
"runtime"
"sync"
"syscall" "syscall"
"time" "time"
@ -11,6 +13,7 @@ import (
// ContainerError is an error encountered in HCS // ContainerError is an error encountered in HCS
type process struct { type process struct {
handleLock sync.RWMutex
handle hcsProcess handle hcsProcess
processID int processID int
container *container container *container
@ -64,10 +67,16 @@ func (process *process) Pid() int {
// Kill signals the process to terminate but does not wait for it to finish terminating. // Kill signals the process to terminate but does not wait for it to finish terminating.
func (process *process) Kill() error { func (process *process) Kill() error {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "Kill" operation := "Kill"
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
if process.handle == 0 {
return makeProcessError(process, operation, "", ErrAlreadyClosed)
}
var resultp *uint16 var resultp *uint16
err := hcsTerminateProcess(process.handle, &resultp) err := hcsTerminateProcess(process.handle, &resultp)
err = processHcsResult(err, resultp) err = processHcsResult(err, resultp)
@ -85,16 +94,9 @@ func (process *process) Wait() error {
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
if hcsCallbacksSupported { err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) if err != nil {
if err != nil { return makeProcessError(process, operation, "", err)
return makeProcessError(process, operation, "", err)
}
} else {
_, err := process.waitTimeoutInternal(syscall.INFINITE)
if err != nil {
return makeProcessError(process, operation, "", err)
}
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID) logrus.Debugf(title+" succeeded processid=%d", process.processID)
@ -108,51 +110,28 @@ func (process *process) WaitTimeout(timeout time.Duration) error {
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
if hcsCallbacksSupported { err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) if err != nil {
if err != nil { return makeProcessError(process, operation, "", err)
return makeProcessError(process, operation, "", err)
}
} else {
finished, err := waitTimeoutHelper(process, timeout)
if !finished {
err = ErrTimeout
}
if err != nil {
return makeProcessError(process, operation, "", err)
}
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID) logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil 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 // ExitCode returns the exit code of the process. The process must have
// already terminated. // already terminated.
func (process *process) ExitCode() (int, error) { func (process *process) ExitCode() (int, error) {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "ExitCode" operation := "ExitCode"
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
if process.handle == 0 {
return 0, makeProcessError(process, operation, "", ErrAlreadyClosed)
}
properties, err := process.properties() properties, err := process.properties()
if err != nil { if err != nil {
return 0, makeProcessError(process, operation, "", err) return 0, makeProcessError(process, operation, "", err)
@ -162,16 +141,26 @@ func (process *process) ExitCode() (int, error) {
return 0, makeProcessError(process, operation, "", ErrInvalidProcessState) return 0, makeProcessError(process, operation, "", ErrInvalidProcessState)
} }
if properties.LastWaitResult != 0 {
return 0, makeProcessError(process, operation, "", syscall.Errno(properties.LastWaitResult))
}
logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode) logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode)
return int(properties.ExitCode), nil return int(properties.ExitCode), nil
} }
// ResizeConsole resizes the console of the process. // ResizeConsole resizes the console of the process.
func (process *process) ResizeConsole(width, height uint16) error { func (process *process) ResizeConsole(width, height uint16) error {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "ResizeConsole" operation := "ResizeConsole"
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
if process.handle == 0 {
return makeProcessError(process, operation, "", ErrAlreadyClosed)
}
modifyRequest := processModifyRequest{ modifyRequest := processModifyRequest{
Operation: modifyConsoleSize, Operation: modifyConsoleSize,
ConsoleSize: &consoleSize{ ConsoleSize: &consoleSize{
@ -231,10 +220,16 @@ func (process *process) properties() (*processStatus, error) {
// these pipes does not close the underlying pipes; it should be possible to // these pipes does not close the underlying pipes; it should be possible to
// call this multiple times to get multiple interfaces. // call this multiple times to get multiple interfaces.
func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "Stdio" operation := "Stdio"
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
if process.handle == 0 {
return nil, nil, nil, makeProcessError(process, operation, "", ErrAlreadyClosed)
}
var stdIn, stdOut, stdErr syscall.Handle var stdIn, stdOut, stdErr syscall.Handle
if process.cachedPipes == nil { if process.cachedPipes == nil {
@ -269,10 +264,16 @@ func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e
// CloseStdin closes the write side of the stdin pipe so that the process is // 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. // notified on the read side that there is no more data in stdin.
func (process *process) CloseStdin() error { func (process *process) CloseStdin() error {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "CloseStdin" operation := "CloseStdin"
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
if process.handle == 0 {
return makeProcessError(process, operation, "", ErrAlreadyClosed)
}
modifyRequest := processModifyRequest{ modifyRequest := processModifyRequest{
Operation: modifyCloseHandle, Operation: modifyCloseHandle,
CloseHandle: &closeHandle{ CloseHandle: &closeHandle{
@ -301,6 +302,8 @@ func (process *process) CloseStdin() error {
// Close cleans up any state associated with the process but does not kill // Close cleans up any state associated with the process but does not kill
// or wait on it. // or wait on it.
func (process *process) Close() error { func (process *process) Close() error {
process.handleLock.Lock()
defer process.handleLock.Unlock()
operation := "Close" operation := "Close"
title := "HCSShim::Process::" + operation title := "HCSShim::Process::" + operation
logrus.Debugf(title+" processid=%d", process.processID) logrus.Debugf(title+" processid=%d", process.processID)
@ -310,10 +313,8 @@ func (process *process) Close() error {
return nil return nil
} }
if hcsCallbacksSupported { if err := process.unregisterCallback(); err != nil {
if err := process.unregisterCallback(); err != nil { return makeProcessError(process, operation, "", err)
return makeProcessError(process, operation, "", err)
}
} }
if err := hcsCloseProcess(process.handle); err != nil { if err := hcsCloseProcess(process.handle); err != nil {
@ -321,6 +322,7 @@ func (process *process) Close() error {
} }
process.handle = 0 process.handle = 0
runtime.SetFinalizer(process, nil)
logrus.Debugf(title+" succeeded processid=%d", process.processID) logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil

View File

@ -7,12 +7,6 @@ import (
"github.com/Microsoft/go-winio" "github.com/Microsoft/go-winio"
) )
var (
vmcomputedll = syscall.NewLazyDLL("vmcompute.dll")
hcsCallbackAPI = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback")
hcsCallbacksSupported = hcsCallbackAPI.Find() == nil
)
// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles // makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles
// if there is an error. // if there is an error.
func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) { func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {

View File

@ -1,53 +1,11 @@
package hcsshim package hcsshim
import ( import (
"github.com/Sirupsen/logrus"
"syscall"
"time" "time"
"github.com/Sirupsen/logrus"
) )
type waitable interface {
waitTimeoutInternal(timeout uint32) (bool, error)
hcsWait(timeout uint32) (bool, 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(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error { func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
err = processHcsResult(err, resultp) err = processHcsResult(err, resultp)
if IsPending(err) { if IsPending(err) {
@ -68,37 +26,13 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific
return ErrInvalidNotificationType return ErrInvalidNotificationType
} }
var c <-chan time.Time
if timeout != nil { if timeout != nil {
timer := time.NewTimer(*timeout) timer := time.NewTimer(*timeout)
c = timer.C
defer timer.Stop() defer timer.Stop()
select {
case err, ok := <-expectedChannel:
if !ok {
return ErrHandleClose
}
return err
case err, ok := <-channels[hcsNotificationSystemExited]:
if !ok {
return ErrHandleClose
}
// If the expected notification is hcsNotificationSystemExited which of the two selects
// chosen is random. Return the raw error if hcsNotificationSystemExited is expected
if channels[hcsNotificationSystemExited] == expectedChannel {
return err
}
return ErrUnexpectedContainerExit
case _, ok := <-channels[hcsNotificationServiceDisconnect]:
if !ok {
return ErrHandleClose
}
// hcsNotificationServiceDisconnect should never be an expected notification
// it does not need the same handling as hcsNotificationSystemExited
return ErrUnexpectedProcessAbort
case <-timer.C:
return ErrTimeout
}
} }
select { select {
case err, ok := <-expectedChannel: case err, ok := <-expectedChannel:
if !ok { if !ok {
@ -122,5 +56,7 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific
// hcsNotificationServiceDisconnect should never be an expected notification // hcsNotificationServiceDisconnect should never be an expected notification
// it does not need the same handling as hcsNotificationSystemExited // it does not need the same handling as hcsNotificationSystemExited
return ErrUnexpectedProcessAbort return ErrUnexpectedProcessAbort
case <-c:
return ErrTimeout
} }
} }

View File

@ -13,69 +13,57 @@ var (
modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
modvmcompute = syscall.NewLazyDLL("vmcompute.dll") modvmcompute = syscall.NewLazyDLL("vmcompute.dll")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId")
procActivateLayer = modvmcompute.NewProc("ActivateLayer") procActivateLayer = modvmcompute.NewProc("ActivateLayer")
procCopyLayer = modvmcompute.NewProc("CopyLayer") procCopyLayer = modvmcompute.NewProc("CopyLayer")
procCreateLayer = modvmcompute.NewProc("CreateLayer") procCreateLayer = modvmcompute.NewProc("CreateLayer")
procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer") procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer")
procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize") procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize")
procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer") procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer")
procDestroyLayer = modvmcompute.NewProc("DestroyLayer") procDestroyLayer = modvmcompute.NewProc("DestroyLayer")
procExportLayer = modvmcompute.NewProc("ExportLayer") procExportLayer = modvmcompute.NewProc("ExportLayer")
procGetLayerMountPath = modvmcompute.NewProc("GetLayerMountPath") procGetLayerMountPath = modvmcompute.NewProc("GetLayerMountPath")
procGetBaseImages = modvmcompute.NewProc("GetBaseImages") procGetBaseImages = modvmcompute.NewProc("GetBaseImages")
procImportLayer = modvmcompute.NewProc("ImportLayer") procImportLayer = modvmcompute.NewProc("ImportLayer")
procLayerExists = modvmcompute.NewProc("LayerExists") procLayerExists = modvmcompute.NewProc("LayerExists")
procNameToGuid = modvmcompute.NewProc("NameToGuid") procNameToGuid = modvmcompute.NewProc("NameToGuid")
procPrepareLayer = modvmcompute.NewProc("PrepareLayer") procPrepareLayer = modvmcompute.NewProc("PrepareLayer")
procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer") procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer")
procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage") procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage")
procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage") procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage")
procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin") procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin")
procImportLayerNext = modvmcompute.NewProc("ImportLayerNext") procImportLayerNext = modvmcompute.NewProc("ImportLayerNext")
procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite") procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite")
procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd") procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd")
procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin") procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin")
procExportLayerNext = modvmcompute.NewProc("ExportLayerNext") procExportLayerNext = modvmcompute.NewProc("ExportLayerNext")
procExportLayerRead = modvmcompute.NewProc("ExportLayerRead") procExportLayerRead = modvmcompute.NewProc("ExportLayerRead")
procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd") procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd")
procCreateComputeSystem = modvmcompute.NewProc("CreateComputeSystem") procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems")
procCreateProcessWithStdHandlesInComputeSystem = modvmcompute.NewProc("CreateProcessWithStdHandlesInComputeSystem") procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem")
procResizeConsoleInComputeSystem = modvmcompute.NewProc("ResizeConsoleInComputeSystem") procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem")
procShutdownComputeSystem = modvmcompute.NewProc("ShutdownComputeSystem") procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem")
procStartComputeSystem = modvmcompute.NewProc("StartComputeSystem") procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem")
procTerminateComputeSystem = modvmcompute.NewProc("TerminateComputeSystem") procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem")
procTerminateProcessInComputeSystem = modvmcompute.NewProc("TerminateProcessInComputeSystem") procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem")
procWaitForProcessInComputeSystem = modvmcompute.NewProc("WaitForProcessInComputeSystem") procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem")
procGetComputeSystemProperties = modvmcompute.NewProc("GetComputeSystemProperties") procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem")
procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems") procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties")
procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem") procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem")
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") procHcsRegisterComputeSystemCallback = modvmcompute.NewProc("HcsRegisterComputeSystemCallback")
procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback") procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback")
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")
procHcsGetServiceProperties = modvmcompute.NewProc("HcsGetServiceProperties")
procHcsRegisterProcessCallback = modvmcompute.NewProc("HcsRegisterProcessCallback") procHcsRegisterProcessCallback = modvmcompute.NewProc("HcsRegisterProcessCallback")
procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback") procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback")
procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings")
procHNSCall = modvmcompute.NewProc("HNSCall") procHNSCall = modvmcompute.NewProc("HNSCall")
) )
@ -599,196 +587,6 @@ func exportLayerEnd(context uintptr) (hr error) {
return return
} }
func createComputeSystem(id string, configuration string) (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 _createComputeSystem(_p0, _p1)
}
func _createComputeSystem(id *uint16, configuration *uint16) (hr error) {
if hr = procCreateComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procCreateComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(paramsJson)
if hr != nil {
return
}
return _createProcessWithStdHandlesInComputeSystem(_p0, _p1, pid, stdin, stdout, stderr)
}
func _createProcessWithStdHandlesInComputeSystem(id *uint16, paramsJson *uint16, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) {
if hr = procCreateProcessWithStdHandlesInComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procCreateProcessWithStdHandlesInComputeSystem.Addr(), 6, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(paramsJson)), uintptr(unsafe.Pointer(pid)), uintptr(unsafe.Pointer(stdin)), uintptr(unsafe.Pointer(stdout)), uintptr(unsafe.Pointer(stderr)))
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _resizeConsoleInComputeSystem(_p0, pid, height, width, flags)
}
func _resizeConsoleInComputeSystem(id *uint16, pid uint32, height uint16, width uint16, flags uint32) (hr error) {
if hr = procResizeConsoleInComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procResizeConsoleInComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(height), uintptr(width), uintptr(flags), 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func shutdownComputeSystem(id string, timeout uint32) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _shutdownComputeSystem(_p0, timeout)
}
func _shutdownComputeSystem(id *uint16, timeout uint32) (hr error) {
if hr = procShutdownComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procShutdownComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(timeout), 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func startComputeSystem(id string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _startComputeSystem(_p0)
}
func _startComputeSystem(id *uint16) (hr error) {
if hr = procStartComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procStartComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func terminateComputeSystem(id string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _terminateComputeSystem(_p0)
}
func _terminateComputeSystem(id *uint16) (hr error) {
if hr = procTerminateComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procTerminateComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func terminateProcessInComputeSystem(id string, pid uint32) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _terminateProcessInComputeSystem(_p0, pid)
}
func _terminateProcessInComputeSystem(id *uint16, pid uint32) (hr error) {
if hr = procTerminateProcessInComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procTerminateProcessInComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(pid), 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _waitForProcessInComputeSystem(_p0, pid, timeout, exitCode)
}
func _waitForProcessInComputeSystem(id *uint16, pid uint32, timeout uint32, exitCode *uint32) (hr error) {
if hr = procWaitForProcessInComputeSystem.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procWaitForProcessInComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(timeout), uintptr(unsafe.Pointer(exitCode)), 0, 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _getComputeSystemProperties(_p0, flags, properties)
}
func _getComputeSystemProperties(id *uint16, flags uint32, properties **uint16) (hr error) {
if hr = procGetComputeSystemProperties.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procGetComputeSystemProperties.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(flags), uintptr(unsafe.Pointer(properties)))
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
return
}
func hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) { func hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) {
var _p0 *uint16 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(query) _p0, hr = syscall.UTF16PtrFromString(query)
@ -1005,11 +803,22 @@ func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, res
return return
} }
func hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) { func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) {
if hr = procHcsCreateComputeSystemWait.Find(); hr != nil { if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsCreateComputeSystemWait.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(exitEvent)), uintptr(unsafe.Pointer(result))) 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 { if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0)) hr = syscall.Errno(win32FromHresult(r0))
} }
@ -1111,17 +920,6 @@ func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (h
return 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) { func hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) {
var _p0 *uint16 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(propertyQuery) _p0, hr = syscall.UTF16PtrFromString(propertyQuery)
@ -1142,128 +940,6 @@ func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result
return 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) { func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) {
if hr = procHcsRegisterProcessCallback.Find(); hr != nil { if hr = procHcsRegisterProcessCallback.Find(); hr != nil {
return return
@ -1286,6 +962,26 @@ func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) {
return 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 _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)

View File

@ -2,13 +2,14 @@ package libnetwork
import ( import (
"fmt" "fmt"
"strings"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types" "github.com/docker/libnetwork/types"
) )
const ( const (
libnGWNetwork = "docker_gwbridge" gwEPlen = 12
gwEPlen = 12
) )
var procGwNetwork = make(chan (bool), 1) var procGwNetwork = make(chan (bool), 1)
@ -52,6 +53,21 @@ func (sb *sandbox) setupDefaultGW() error {
eplen = len(sb.containerID) eplen = len(sb.containerID)
} }
sbLabels := sb.Labels()
if sbLabels[netlabel.PortMap] != nil {
createOptions = append(createOptions, CreateOptionPortMapping(sbLabels[netlabel.PortMap].([]types.PortBinding)))
}
if sbLabels[netlabel.ExposedPorts] != nil {
createOptions = append(createOptions, CreateOptionExposedPorts(sbLabels[netlabel.ExposedPorts].([]types.TransportPort)))
}
epOption := getPlatformOption()
if epOption != nil {
createOptions = append(createOptions, epOption)
}
newEp, err := n.CreateEndpoint("gateway_"+sb.containerID[0:eplen], createOptions...) newEp, err := n.CreateEndpoint("gateway_"+sb.containerID[0:eplen], createOptions...)
if err != nil { if err != nil {
return fmt.Errorf("container %s: endpoint create on GW Network failed: %v", sb.containerID, err) return fmt.Errorf("container %s: endpoint create on GW Network failed: %v", sb.containerID, err)
@ -119,7 +135,7 @@ func (sb *sandbox) needDefaultGW() bool {
func (sb *sandbox) getEndpointInGWNetwork() *endpoint { func (sb *sandbox) getEndpointInGWNetwork() *endpoint {
for _, ep := range sb.getConnectedEndpoints() { for _, ep := range sb.getConnectedEndpoints() {
if ep.getNetwork().name == libnGWNetwork { if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") {
return ep return ep
} }
} }
@ -127,7 +143,7 @@ func (sb *sandbox) getEndpointInGWNetwork() *endpoint {
} }
func (ep *endpoint) endpointInGWNetwork() bool { func (ep *endpoint) endpointInGWNetwork() bool {
if ep.getNetwork().name == libnGWNetwork { if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") {
return true return true
} }
return false return false

View File

@ -2,6 +2,12 @@ package libnetwork
import "github.com/docker/libnetwork/types" import "github.com/docker/libnetwork/types"
const libnGWNetwork = "docker_gwbridge"
func getPlatformOption() EndpointOption {
return nil
}
func (c *controller) createGWNetwork() (Network, error) { func (c *controller) createGWNetwork() (Network, error) {
return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in freebsd") return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in freebsd")
} }

View File

@ -7,6 +7,12 @@ import (
"github.com/docker/libnetwork/drivers/bridge" "github.com/docker/libnetwork/drivers/bridge"
) )
const libnGWNetwork = "docker_gwbridge"
func getPlatformOption() EndpointOption {
return nil
}
func (c *controller) createGWNetwork() (Network, error) { func (c *controller) createGWNetwork() (Network, error) {
netOption := map[string]string{ netOption := map[string]string{
bridge.BridgeName: libnGWNetwork, bridge.BridgeName: libnGWNetwork,

View File

@ -7,6 +7,12 @@ import (
"github.com/docker/libnetwork/drivers/solaris/bridge" "github.com/docker/libnetwork/drivers/solaris/bridge"
) )
const libnGWNetwork = "docker_gwbridge"
func getPlatformOption() EndpointOption {
return nil
}
func (c *controller) createGWNetwork() (Network, error) { func (c *controller) createGWNetwork() (Network, error) {
netOption := map[string]string{ netOption := map[string]string{
bridge.BridgeName: libnGWNetwork, bridge.BridgeName: libnGWNetwork,

View File

@ -1,6 +1,21 @@
package libnetwork package libnetwork
import "github.com/docker/libnetwork/types" import (
windriver "github.com/docker/libnetwork/drivers/windows"
"github.com/docker/libnetwork/options"
"github.com/docker/libnetwork/types"
)
const libnGWNetwork = "nat"
func getPlatformOption() EndpointOption {
epOption := options.Generic{
windriver.DisableICC: true,
windriver.DisableDNS: true,
}
return EndpointOptionGeneric(epOption)
}
func (c *controller) createGWNetwork() (Network, error) { func (c *controller) createGWNetwork() (Network, error) {
return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in windows") return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in windows")

View File

@ -30,4 +30,10 @@ const (
// SourceMac of the network // SourceMac of the network
SourceMac = "com.docker.network.windowsshim.sourcemac" SourceMac = "com.docker.network.windowsshim.sourcemac"
// DisableICC label
DisableICC = "com.docker.network.windowsshim.disableicc"
// DisableDNS label
DisableDNS = "com.docker.network.windowsshim.disable_dns"
) )

View File

@ -44,8 +44,6 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
logrus.Errorf("overlay: Failed adding table entry to joininfo: %v", err) logrus.Errorf("overlay: Failed adding table entry to joininfo: %v", err)
} }
jinfo.DisableGatewayService()
d.pushLocalEndpointEvent("join", nid, eid) d.pushLocalEndpointEvent("join", nid, eid)
return nil return nil

View File

@ -44,21 +44,28 @@ type networkConfiguration struct {
} }
// endpointConfiguration represents the user specified configuration for the sandbox endpoint // endpointConfiguration represents the user specified configuration for the sandbox endpoint
type endpointConfiguration struct { type endpointOption struct {
MacAddress net.HardwareAddr MacAddress net.HardwareAddr
QosPolicies []types.QosPolicy
DNSServers []string
DisableDNS bool
DisableICC bool
}
type endpointConnectivity struct {
PortBindings []types.PortBinding PortBindings []types.PortBinding
ExposedPorts []types.TransportPort ExposedPorts []types.TransportPort
QosPolicies []types.QosPolicy
DNSServers []string
} }
type hnsEndpoint struct { type hnsEndpoint struct {
id string id string
profileID string profileID string
macAddress net.HardwareAddr macAddress net.HardwareAddr
config *endpointConfiguration // User specified parameters epOption *endpointOption // User specified parameters
portMapping []types.PortBinding // Operation port bindings epConnectivity *endpointConnectivity // User specified parameters
addr *net.IPNet portMapping []types.PortBinding // Operation port bindings
addr *net.IPNet
gateway net.IP
} }
type hnsNetwork struct { type hnsNetwork struct {
@ -391,12 +398,12 @@ func parsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding,
return bindings, nil return bindings, nil
} }
func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) { func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) {
if epOptions == nil { if epOptions == nil {
return nil, nil return nil, nil
} }
ec := &endpointConfiguration{} ec := &endpointOption{}
if opt, ok := epOptions[netlabel.MacAddress]; ok { if opt, ok := epOptions[netlabel.MacAddress]; ok {
if mac, ok := opt.(net.HardwareAddr); ok { if mac, ok := opt.(net.HardwareAddr); ok {
@ -406,22 +413,6 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat
} }
} }
if opt, ok := epOptions[netlabel.PortMap]; ok {
if bs, ok := opt.([]types.PortBinding); ok {
ec.PortBindings = bs
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
if ports, ok := opt.([]types.TransportPort); ok {
ec.ExposedPorts = ports
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
if opt, ok := epOptions[QosPolicies]; ok { if opt, ok := epOptions[QosPolicies]; ok {
if policies, ok := opt.([]types.QosPolicy); ok { if policies, ok := opt.([]types.QosPolicy); ok {
ec.QosPolicies = policies ec.QosPolicies = policies
@ -438,6 +429,47 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat
} }
} }
if opt, ok := epOptions[DisableICC]; ok {
if disableICC, ok := opt.(bool); ok {
ec.DisableICC = disableICC
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
if opt, ok := epOptions[DisableDNS]; ok {
if disableDNS, ok := opt.(bool); ok {
ec.DisableDNS = disableDNS
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
return ec, nil
}
func parseEndpointConnectivity(epOptions map[string]interface{}) (*endpointConnectivity, error) {
if epOptions == nil {
return nil, nil
}
ec := &endpointConnectivity{}
if opt, ok := epOptions[netlabel.PortMap]; ok {
if bs, ok := opt.([]types.PortBinding); ok {
ec.PortBindings = bs
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
if ports, ok := opt.([]types.TransportPort); ok {
ec.ExposedPorts = ports
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
return ec, nil return ec, nil
} }
@ -457,7 +489,8 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
VirtualNetwork: n.config.HnsID, VirtualNetwork: n.config.HnsID,
} }
ec, err := parseEndpointOptions(epOptions) epOption, err := parseEndpointOptions(epOptions)
epConnectivity, err := parseEndpointConnectivity(epOptions)
macAddress := ifInfo.MacAddress() macAddress := ifInfo.MacAddress()
// Use the macaddress if it was provided // Use the macaddress if it was provided
@ -465,12 +498,12 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1) endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1)
} }
endpointStruct.Policies, err = convertPortBindings(ec.PortBindings) endpointStruct.Policies, err = convertPortBindings(epConnectivity.PortBindings)
if err != nil { if err != nil {
return err return err
} }
qosPolicies, err := convertQosPolicies(ec.QosPolicies) qosPolicies, err := convertQosPolicies(epOption.QosPolicies)
if err != nil { if err != nil {
return err return err
} }
@ -480,12 +513,14 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
endpointStruct.IPAddress = ifInfo.Address().IP endpointStruct.IPAddress = ifInfo.Address().IP
} }
endpointStruct.DNSServerList = strings.Join(ec.DNSServers, ",") endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",")
if n.driver.name == "nat" { if n.driver.name == "nat" && !epOption.DisableDNS {
endpointStruct.EnableInternalDNS = true endpointStruct.EnableInternalDNS = true
} }
endpointStruct.DisableICC = epOption.DisableICC
configurationb, err := json.Marshal(endpointStruct) configurationb, err := json.Marshal(endpointStruct)
if err != nil { if err != nil {
return err return err
@ -508,8 +543,13 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
macAddress: mac, macAddress: mac,
} }
if hnsresponse.GatewayAddress != "" {
endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress)
}
endpoint.profileID = hnsresponse.Id endpoint.profileID = hnsresponse.Id
endpoint.config = ec endpoint.epConnectivity = epConnectivity
endpoint.epOption = epOption
endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies) endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies)
if err != nil { if err != nil {
@ -572,10 +612,10 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro
} }
data["hnsid"] = ep.profileID data["hnsid"] = ep.profileID
if ep.config.ExposedPorts != nil { if ep.epConnectivity.ExposedPorts != nil {
// Return a copy of the config data // Return a copy of the config data
epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts)) epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts))
for _, tp := range ep.config.ExposedPorts { for _, tp := range ep.epConnectivity.ExposedPorts {
epc = append(epc, tp.GetCopy()) epc = append(epc, tp.GetCopy())
} }
data[netlabel.ExposedPorts] = epc data[netlabel.ExposedPorts] = epc
@ -604,7 +644,12 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
} }
// Ensure that the endpoint exists // Ensure that the endpoint exists
_, err = network.getEndpoint(eid) endpoint, err := network.getEndpoint(eid)
if err != nil {
return err
}
err = jinfo.SetGateway(endpoint.gateway)
if err != nil { if err != nil {
return err return err
} }

View File

@ -205,31 +205,6 @@ func (ep *endpoint) Info() EndpointInfo {
return nil return nil
} }
func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
ep, err := ep.retrieveFromStore()
if err != nil {
return nil, err
}
if sb, ok := ep.getSandbox(); ok {
if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() {
return gwep.DriverInfo()
}
}
n, err := ep.getNetworkFromStore()
if err != nil {
return nil, fmt.Errorf("could not find network in store for driver info: %v", err)
}
driver, err := n.driver(true)
if err != nil {
return nil, fmt.Errorf("failed to get driver info: %v", err)
}
return driver.EndpointOperInfo(n.ID(), ep.ID())
}
func (ep *endpoint) Iface() InterfaceInfo { func (ep *endpoint) Iface() InterfaceInfo {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()

View File

@ -0,0 +1,30 @@
// +build !windows
package libnetwork
import "fmt"
func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
ep, err := ep.retrieveFromStore()
if err != nil {
return nil, err
}
if sb, ok := ep.getSandbox(); ok {
if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() {
return gwep.DriverInfo()
}
}
n, err := ep.getNetworkFromStore()
if err != nil {
return nil, fmt.Errorf("could not find network in store for driver info: %v", err)
}
driver, err := n.driver(true)
if err != nil {
return nil, fmt.Errorf("failed to get driver info: %v", err)
}
return driver.EndpointOperInfo(n.ID(), ep.ID())
}

View File

@ -0,0 +1,45 @@
// +build windows
package libnetwork
import "fmt"
func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
ep, err := ep.retrieveFromStore()
if err != nil {
return nil, err
}
var gwDriverInfo map[string]interface{}
if sb, ok := ep.getSandbox(); ok {
if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() {
gwDriverInfo, err = gwep.DriverInfo()
if err != nil {
return nil, err
}
}
}
n, err := ep.getNetworkFromStore()
if err != nil {
return nil, fmt.Errorf("could not find network in store for driver info: %v", err)
}
driver, err := n.driver(true)
if err != nil {
return nil, fmt.Errorf("failed to get driver info: %v", err)
}
epInfo, err := driver.EndpointOperInfo(n.ID(), ep.ID())
if err != nil {
return nil, err
}
if epInfo != nil {
epInfo["GW_INFO"] = gwDriverInfo
return epInfo, nil
}
return gwDriverInfo, nil
}