From 0c0c7828b0a46e3e092d2b378d4f72c75e44a208 Mon Sep 17 00:00:00 2001 From: msabansal Date: Fri, 4 Nov 2016 13:26:50 -0700 Subject: [PATCH] Default GW support for overlay networks Signed-off-by: msabansal --- Godeps/Godeps.json | 4 +- .../github.com/Microsoft/hcsshim/baselayer.go | 35 +- .../github.com/Microsoft/hcsshim/container.go | 211 +++++--- .../github.com/Microsoft/hcsshim/errors.go | 25 +- .../github.com/Microsoft/hcsshim/hcsshim.go | 29 +- .../github.com/Microsoft/hcsshim/hnsfuncs.go | 5 +- .../Microsoft/hcsshim/importlayer.go | 47 +- .../github.com/Microsoft/hcsshim/interface.go | 28 +- .../github.com/Microsoft/hcsshim/legacy.go | 348 +++++++++++-- .../Microsoft/hcsshim/preparelayer.go | 12 +- .../github.com/Microsoft/hcsshim/process.go | 94 ++-- .../src/github.com/Microsoft/hcsshim/utils.go | 6 - .../Microsoft/hcsshim/waithelper.go | 78 +-- .../github.com/Microsoft/hcsshim/zhcsshim.go | 466 +++--------------- default_gateway.go | 24 +- default_gateway_freebsd.go | 6 + default_gateway_linux.go | 6 + default_gateway_solaris.go | 6 + default_gateway_windows.go | 17 +- drivers/windows/labels.go | 6 + drivers/windows/overlay/joinleave_windows.go | 2 - drivers/windows/windows.go | 121 +++-- endpoint_info.go | 25 - endpoint_info_unix.go | 30 ++ endpoint_info_windows.go | 45 ++ 25 files changed, 921 insertions(+), 755 deletions(-) create mode 100644 endpoint_info_unix.go create mode 100644 endpoint_info_windows.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index bcd738d0..8fa0717b 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -26,8 +26,8 @@ }, { "ImportPath": "github.com/Microsoft/hcsshim", - "Comment": "v0.5.1", - "Rev": "523023ef1ef8ec08b23bbff88ab68552c5f1a6d7" + "Comment": "v0.5.6", + "Rev": "e439b7d2b63f036d3a50c93a9e0b154a0d50e788" }, { "ImportPath": "github.com/Sirupsen/logrus", diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go index 4b04a681..9babd4e1 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/baselayer.go @@ -23,6 +23,26 @@ type dirInfo struct { 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 { if w.f != nil { err := w.bw.Close() @@ -142,18 +162,9 @@ func (w *baseLayerWriter) Close() error { if w.err == nil { // Restore the file times of all the directories, since they may have // been modified by creating child directories. - for i := range w.dirInfo { - di := &w.dirInfo[len(w.dirInfo)-i-1] - f, err := winio.OpenForBackup(di.path, uint32(syscall.GENERIC_READ|syscall.GENERIC_WRITE), syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING) - if err != nil { - return makeError(err, "Failed to OpenForBackup", di.path) - } - - err = winio.SetFileBasicInfo(f, &di.fileInfo) - f.Close() - if err != nil { - return makeError(err, "Failed to SetFileBasicInfo", di.path) - } + err = reapplyDirectoryTimes(w.dirInfo) + if err != nil { + return err } err = ProcessBaseLayer(w.root) diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go index 9e76e332..48a75497 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/container.go @@ -3,6 +3,7 @@ package hcsshim import ( "encoding/json" "runtime" + "sync" "syscall" "time" @@ -20,12 +21,14 @@ const ( ) type container struct { + handleLock sync.RWMutex handle hcsSystem id string 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"` Name string SystemType string @@ -33,6 +36,8 @@ type containerProperties struct { SiloGUID string `json:"SiloGuid,omitempty"` IsDummy bool `json:",omitempty"` RuntimeID string `json:"RuntimeId,omitempty"` + IsRuntimeTemplate bool `json:",omitempty"` + RuntimeImagePath string `json:",omitempty"` Stopped bool `json:",omitempty"` ExitType string `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) var ( - resultp *uint16 - createError error + resultp *uint16 + identity syscall.Handle ) - if hcsCallbacksSupported { - var identity syscall.Handle - createError = hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp) + createError := hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp) - if createError == nil || IsPending(createError) { - if err := container.registerCallback(); err != nil { - return nil, makeContainerError(container, operation, "", err) - } + if createError == nil || IsPending(createError) { + if err := container.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) } - } else { - createError = hcsCreateComputeSystemTP5(id, configuration, &container.handle, &resultp) } err = processAsyncHcsResult(createError, resultp, container.callbackNumber, hcsNotificationSystemCreateCompleted, &defaultTimeout) @@ -164,19 +164,61 @@ func OpenContainer(id string) (Container, error) { 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) runtime.SetFinalizer(container, closeContainer) 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. func (container *container) Start() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Start" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsStartComputeSystemTP5(container.handle, nil, &resultp) + err := hcsStartComputeSystem(container.handle, "", &resultp) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemStartCompleted, &defaultTimeout) if err != nil { 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, // it may not actually be shut down until Wait() succeeds. func (container *container) Shutdown() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Shutdown" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp) + err := hcsShutdownComputeSystem(container.handle, "", &resultp) err = processHcsResult(err, resultp) if err != nil { 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, // it may not actually be shut down until Wait() succeeds. func (container *container) Terminate() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Terminate" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp) + err := hcsTerminateComputeSystem(container.handle, "", &resultp) err = processHcsResult(err, resultp) if err != nil { return makeContainerError(container, operation, "", err) @@ -228,26 +282,15 @@ func (container *container) Wait() error { title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) - if hcsCallbacksSupported { - err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil) - if err != nil { - return makeContainerError(container, operation, "", err) - } - } else { - _, err := container.waitTimeoutInternal(syscall.INFINITE) - if err != nil { - return makeContainerError(container, operation, "", err) - } + err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil) + if err != nil { + return makeContainerError(container, operation, "", err) } logrus.Debugf(title+" succeeded id=%s", container.id) return nil } -func (container *container) waitTimeoutInternal(timeout uint32) (bool, error) { - return waitTimeoutInternalHelper(container, timeout) -} - // WaitTimeout synchronously waits for the container to terminate or the duration to elapse. // If the timeout expires, IsTimeout(err) == true func (container *container) WaitTimeout(timeout time.Duration) error { @@ -255,42 +298,16 @@ func (container *container) WaitTimeout(timeout time.Duration) error { title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) - if hcsCallbacksSupported { - err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout) - if err != nil { - return makeContainerError(container, operation, "", err) - } - } else { - finished, err := waitTimeoutHelper(container, timeout) - if !finished { - err = ErrTimeout - } - if err != nil { - return makeContainerError(container, operation, "", err) - } + err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout) + if err != nil { + return makeContainerError(container, operation, "", err) } logrus.Debugf(title+" succeeded id=%s", container.id) return nil } -func (container *container) hcsWait(timeout uint32) (bool, error) { - var ( - resultp *uint16 - exitEvent syscall.Handle - ) - - err := hcsCreateComputeSystemWait(container.handle, &exitEvent, &resultp) - err = processHcsResult(err, resultp) - if err != nil { - return false, err - } - defer syscall.CloseHandle(exitEvent) - - return waitForSingleObject(exitEvent, timeout) -} - -func (container *container) properties(query string) (*containerProperties, error) { +func (container *container) properties(query string) (*ContainerProperties, error) { var ( resultp *uint16 propertiesp *uint16 @@ -305,7 +322,7 @@ func (container *container) properties(query string) (*containerProperties, erro return nil, ErrUnexpectedValue } propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) - properties := &containerProperties{} + properties := &ContainerProperties{} if err := json.Unmarshal(propertiesRaw, properties); err != nil { 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 func (container *container) HasPendingUpdates() (bool, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "HasPendingUpdates" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + + if container.handle == 0 { + return false, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + properties, err := container.properties(pendingUpdatesQuery) if err != nil { return false, makeContainerError(container, operation, "", err) @@ -328,9 +352,16 @@ func (container *container) HasPendingUpdates() (bool, error) { // Statistics returns statistics for the container func (container *container) Statistics() (Statistics, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Statistics" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + + if container.handle == 0 { + return Statistics{}, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + properties, err := container.properties(statisticsQuery) if err != nil { 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 func (container *container) ProcessList() ([]ProcessListItem, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "ProcessList" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + + if container.handle == 0 { + return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + properties, err := container.properties(processListQuery) if err != nil { 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. func (container *container) Pause() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Pause" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) + if container.handle == 0 { + return makeContainerError(container, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 - err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp) + err := hcsPauseComputeSystem(container.handle, "", &resultp) err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemPauseCompleted, &defaultTimeout) if err != nil { 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. func (container *container) Resume() error { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "Resume" title := "HCSShim::Container::" + operation 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) if err != nil { return makeContainerError(container, operation, "", err) @@ -392,6 +440,8 @@ func (container *container) Resume() error { // CreateProcess launches a new process within the container. func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "CreateProcess" title := "HCSShim::Container::" + operation var ( @@ -400,6 +450,10 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { 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 !c.EmulateConsole { c.ConsoleSize[0] = 0 @@ -431,10 +485,8 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { }, } - if hcsCallbacksSupported { - if err := process.registerCallback(); err != nil { - return nil, makeContainerError(container, operation, "", err) - } + if err := process.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) } 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. func (container *container) OpenProcess(pid int) (Process, error) { + container.handleLock.RLock() + defer container.handleLock.RUnlock() operation := "OpenProcess" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s, processid=%d", container.id, pid) @@ -452,6 +506,10 @@ func (container *container) OpenProcess(pid int) (Process, error) { resultp *uint16 ) + if container.handle == 0 { + return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) + } + err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp) err = processHcsResult(err, resultp) if err != nil { @@ -464,10 +522,8 @@ func (container *container) OpenProcess(pid int) (Process, error) { container: container, } - if hcsCallbacksSupported { - if err := process.registerCallback(); err != nil { - return nil, makeContainerError(container, operation, "", err) - } + if err := process.registerCallback(); err != nil { + return nil, makeContainerError(container, operation, "", err) } 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. func (container *container) Close() error { + container.handleLock.Lock() + defer container.handleLock.Unlock() operation := "Close" title := "HCSShim::Container::" + operation logrus.Debugf(title+" id=%s", container.id) @@ -486,10 +544,8 @@ func (container *container) Close() error { return nil } - if hcsCallbacksSupported { - if err := container.unregisterCallback(); err != nil { - return makeContainerError(container, operation, "", err) - } + if err := container.unregisterCallback(); err != nil { + return makeContainerError(container, operation, "", err) } if err := hcsCloseComputeSystem(container.handle); err != nil { @@ -497,6 +553,7 @@ func (container *container) Close() error { } container.handle = 0 + runtime.SetFinalizer(container, nil) logrus.Debugf(title+" succeeded id=%s", container.id) return nil diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go index 0d4dad59..19bb97a0 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/errors.go @@ -16,6 +16,9 @@ var ( // 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") + // 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 = errors.New("hcsshim: invalid notification type") @@ -80,8 +83,13 @@ func (e *ContainerError) Error() string { s += " encountered an error during " + e.Operation } - if e.Err != nil { - s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err)) + switch e.Err.(type) { + 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 != "" { @@ -116,16 +124,16 @@ func (e *ProcessError) Error() string { } if e.Operation != "" { - s += " " + e.Operation + s += " encountered an error during " + e.Operation } switch e.Err.(type) { case nil: break 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: - s += fmt.Sprintf(" failed: %s", e.Error()) + s += fmt.Sprintf(": %s", e.Err.Error()) } return s @@ -151,6 +159,13 @@ func IsNotExist(err error) bool { 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 // the requested operation is being completed in the background. func IsPending(err error) bool { diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go index eaecf132..3cb3a299 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go @@ -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. package hcsshim @@ -44,16 +44,6 @@ import ( //sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead? //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 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? @@ -65,7 +55,9 @@ import ( //sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? //sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties? //sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem? -//sys hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystemWait? +//sys 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 hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess? //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 hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties? //sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess? -//sys hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateProcessWait? //sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties? -//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings? - -//sys hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem? -//sys hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem? -//sys hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem? -//sys hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem? -//sys hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem? -//sys hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem? -//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback? -//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback? //sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback? //sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback? +//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings? + //sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall? const ( diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go index 57ad5198..e3d8c0b1 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go @@ -52,7 +52,7 @@ type MacPool struct { // HNSNetwork represents a network in HNS type HNSNetwork struct { - Id string `json:",omitempty"` + Id string `json:"ID,omitempty"` Name string `json:",omitempty"` Type string `json:",omitempty"` NetworkAdapterName string `json:",omitempty"` @@ -68,7 +68,7 @@ type HNSNetwork struct { // HNSEndpoint represents a network endpoint in HNS type HNSEndpoint struct { - Id string `json:",omitempty"` + Id string `json:"ID,omitempty"` Name string `json:",omitempty"` VirtualNetwork string `json:",omitempty"` VirtualNetworkName string `json:",omitempty"` @@ -79,6 +79,7 @@ type HNSEndpoint struct { DNSServerList string `json:",omitempty"` GatewayAddress string `json:",omitempty"` EnableInternalDNS bool `json:",omitempty"` + DisableICC bool `json:",omitempty"` PrefixLength uint8 `json:",omitempty"` IsRemoteEndpoint bool `json:",omitempty"` } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go index 42d72704..5f826301 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go @@ -130,21 +130,42 @@ type legacyLayerWriterWrapper struct { } func (r *legacyLayerWriterWrapper) Close() error { + defer os.RemoveAll(r.root) err := r.legacyLayerWriter.Close() - if err == nil { - var fullPath string - // 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. - info := r.info - fullPath, err = makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) - if err == nil { - info.HomeDir = "" - err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths) + if err != nil { + 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. + info := r.info + fullPath, err := makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) + 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) - return err + // Prepare the utility VM for use if one is present in the layer. + 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. @@ -166,7 +187,7 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) return nil, err } return &legacyLayerWriterWrapper{ - legacyLayerWriter: newLegacyLayerWriter(path), + legacyLayerWriter: newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID)), info: info, layerID: layerID, path: path, diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go index 528cde2f..000a18c1 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/interface.go @@ -10,13 +10,14 @@ import ( type ProcessConfig struct { ApplicationName string CommandLine string + User string WorkingDirectory string Environment map[string]string EmulateConsole bool CreateStdInPipe bool CreateStdOutPipe bool CreateStdErrPipe bool - ConsoleSize [2]int + ConsoleSize [2]uint } type Layer struct { @@ -25,9 +26,11 @@ type Layer struct { } type MappedDir struct { - HostPath string - ContainerPath string - ReadOnly bool + HostPath string + ContainerPath string + ReadOnly bool + BandwidthMaximum uint64 + IOPSMaximum uint64 } type HvRuntime struct { @@ -42,10 +45,10 @@ type ContainerConfig struct { Name string // Name of the container. We use the docker ID. Owner string // The management platform that created this container IsDummy bool // Used for development purposes. - VolumePath string // Windows volume path for scratch space + 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 - LayerFolderPath string // Where the layer folders are located - Layers []Layer // List of storage layers + 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. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID Credentials string `json:",omitempty"` // Credentials information 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. @@ -56,14 +59,21 @@ type ContainerConfig struct { MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes HostName string // Hostname MappedDirectories []MappedDir // List of mapped directories (volumes/mounts) - SandboxPath string // Location of unmounted sandbox (used for Hyper-V containers) + 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 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 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. type Container interface { // Start synchronously starts the container. diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go index e19ac8a9..11d90a7b 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/legacy.go @@ -16,6 +16,13 @@ import ( 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) { return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition) } @@ -49,17 +56,15 @@ type legacyLayerReader struct { proceed chan bool currentFile *os.File backupReader *winio.BackupFileReader - isTP4Format bool } // 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 { r := &legacyLayerReader{ - root: root, - result: make(chan *fileEntry), - proceed: make(chan bool), - isTP4Format: IsTP4(), + root: root, + result: make(chan *fileEntry), + proceed: make(chan bool), } go r.walk() return r @@ -251,17 +256,14 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil fileInfo.LastAccessTime = fileInfo.LastWriteTime } else { - beginning := int64(0) - if !r.isTP4Format { - // In TP5, the file attributes were added before the backup stream - var attr uint32 - err = binary.Read(f, binary.LittleEndian, &attr) - if err != nil { - return - } - fileInfo.FileAttributes = uintptr(attr) - beginning = 4 + // The file attributes are written before the backup stream. + var attr uint32 + err = binary.Read(f, binary.LittleEndian, &attr) + if err != nil { + return } + fileInfo.FileAttributes = uintptr(attr) + beginning := int64(4) // Find the accurate file size. if !fe.fi.IsDir() { @@ -301,21 +303,32 @@ func (r *legacyLayerReader) Close() error { return nil } +type pendingLink struct { + Path, Target string +} + type legacyLayerWriter struct { root string + parentRoots []string + destRoot string currentFile *os.File backupWriter *winio.BackupFileWriter tombstones []string - isTP4Format bool pathFixed bool + HasUtilityVM bool + uvmDi []dirInfo + addedFiles map[string]bool + PendingLinks []pendingLink } -// newLegacyLayerWriter returns a LayerWriter that can write the TP4 transport format -// to disk. -func newLegacyLayerWriter(root string) *legacyLayerWriter { +// newLegacyLayerWriter returns a LayerWriter that can write the contaler layer +// transport format to disk. +func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) *legacyLayerWriter { return &legacyLayerWriter{ 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 { 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.destRoot = destPath w.pathFixed = true } 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() { if w.backupWriter != nil { 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 { w.reset() err := w.init() if err != nil { 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 { err := os.Mkdir(path, 0) if err != nil { @@ -359,7 +567,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro 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 { return err } @@ -380,29 +588,97 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro if strings.HasPrefix(name, `Hives\`) { w.backupWriter = winio.NewBackupFileWriter(f, false) } else { - if !w.isTP4Format { - // In TP5, the file attributes were added to the header - err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes)) - if err != nil { - return err - } + // The file attributes are written before the stream. + err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes)) + if err != nil { + return err } } w.currentFile = f + w.addedFiles[name] = true f = nil return nil } 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 { - 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) } - w.tombstones = append(w.tombstones, name[len(`Files\`):]) + return nil } @@ -437,5 +713,11 @@ func (w *legacyLayerWriter) Close() error { return err } } + if w.HasUtilityVM { + err = reapplyDirectoryTimes(w.uvmDi) + if err != nil { + return err + } + } return nil } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go index 69b5fe04..27916834 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go @@ -1,6 +1,12 @@ 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 // 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 } + // 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) if err != nil { err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour) diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go index d6e63c92..af3fab35 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/process.go @@ -3,6 +3,8 @@ package hcsshim import ( "encoding/json" "io" + "runtime" + "sync" "syscall" "time" @@ -11,6 +13,7 @@ import ( // ContainerError is an error encountered in HCS type process struct { + handleLock sync.RWMutex handle hcsProcess processID int 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. func (process *process) Kill() error { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "Kill" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return makeProcessError(process, operation, "", ErrAlreadyClosed) + } + var resultp *uint16 err := hcsTerminateProcess(process.handle, &resultp) err = processHcsResult(err, resultp) @@ -85,16 +94,9 @@ func (process *process) Wait() error { title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) - if hcsCallbacksSupported { - err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) - if err != nil { - return makeProcessError(process, operation, "", err) - } - } else { - _, err := process.waitTimeoutInternal(syscall.INFINITE) - if err != nil { - return makeProcessError(process, operation, "", err) - } + err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) + if err != nil { + return makeProcessError(process, operation, "", err) } logrus.Debugf(title+" succeeded processid=%d", process.processID) @@ -108,51 +110,28 @@ func (process *process) WaitTimeout(timeout time.Duration) error { title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) - if hcsCallbacksSupported { - err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) - if err != nil { - return makeProcessError(process, operation, "", err) - } - } else { - finished, err := waitTimeoutHelper(process, timeout) - if !finished { - err = ErrTimeout - } - if err != nil { - return makeProcessError(process, operation, "", err) - } + err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) + if err != nil { + return makeProcessError(process, operation, "", err) } logrus.Debugf(title+" succeeded processid=%d", process.processID) return nil } -func (process *process) hcsWait(timeout uint32) (bool, error) { - var ( - resultp *uint16 - exitEvent syscall.Handle - ) - err := hcsCreateProcessWait(process.handle, &exitEvent, &resultp) - err = processHcsResult(err, resultp) - if err != nil { - return false, err - } - defer syscall.CloseHandle(exitEvent) - - return waitForSingleObject(exitEvent, timeout) -} - -func (process *process) waitTimeoutInternal(timeout uint32) (bool, error) { - return waitTimeoutInternalHelper(process, timeout) -} - // ExitCode returns the exit code of the process. The process must have // already terminated. func (process *process) ExitCode() (int, error) { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "ExitCode" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return 0, makeProcessError(process, operation, "", ErrAlreadyClosed) + } + properties, err := process.properties() if err != nil { return 0, makeProcessError(process, operation, "", err) @@ -162,16 +141,26 @@ func (process *process) ExitCode() (int, error) { 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) return int(properties.ExitCode), nil } // ResizeConsole resizes the console of the process. func (process *process) ResizeConsole(width, height uint16) error { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "ResizeConsole" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return makeProcessError(process, operation, "", ErrAlreadyClosed) + } + modifyRequest := processModifyRequest{ Operation: modifyConsoleSize, 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 // call this multiple times to get multiple interfaces. func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "Stdio" title := "HCSShim::Process::" + operation 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 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 // notified on the read side that there is no more data in stdin. func (process *process) CloseStdin() error { + process.handleLock.RLock() + defer process.handleLock.RUnlock() operation := "CloseStdin" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) + if process.handle == 0 { + return makeProcessError(process, operation, "", ErrAlreadyClosed) + } + modifyRequest := processModifyRequest{ Operation: modifyCloseHandle, CloseHandle: &closeHandle{ @@ -301,6 +302,8 @@ func (process *process) CloseStdin() error { // Close cleans up any state associated with the process but does not kill // or wait on it. func (process *process) Close() error { + process.handleLock.Lock() + defer process.handleLock.Unlock() operation := "Close" title := "HCSShim::Process::" + operation logrus.Debugf(title+" processid=%d", process.processID) @@ -310,10 +313,8 @@ func (process *process) Close() error { return nil } - if hcsCallbacksSupported { - if err := process.unregisterCallback(); err != nil { - return makeProcessError(process, operation, "", err) - } + if err := process.unregisterCallback(); err != nil { + return makeProcessError(process, operation, "", err) } if err := hcsCloseProcess(process.handle); err != nil { @@ -321,6 +322,7 @@ func (process *process) Close() error { } process.handle = 0 + runtime.SetFinalizer(process, nil) logrus.Debugf(title+" succeeded processid=%d", process.processID) return nil diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go index c219e2c0..bd6e2d94 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/utils.go @@ -7,12 +7,6 @@ import ( "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 // if there is an error. func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) { diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go index 8ce65ae1..89c94616 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waithelper.go @@ -1,53 +1,11 @@ package hcsshim import ( - "github.com/Sirupsen/logrus" - "syscall" "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 { err = processHcsResult(err, resultp) if IsPending(err) { @@ -68,37 +26,13 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific return ErrInvalidNotificationType } + var c <-chan time.Time if timeout != nil { timer := time.NewTimer(*timeout) + c = timer.C 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 { case err, ok := <-expectedChannel: if !ok { @@ -122,5 +56,7 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific // hcsNotificationServiceDisconnect should never be an expected notification // it does not need the same handling as hcsNotificationSystemExited return ErrUnexpectedProcessAbort + case <-c: + return ErrTimeout } } diff --git a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go index 3ae95864..7c3b7bdf 100644 --- a/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go +++ b/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go @@ -13,69 +13,57 @@ var ( modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") modvmcompute = syscall.NewLazyDLL("vmcompute.dll") - procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") - procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") - procActivateLayer = modvmcompute.NewProc("ActivateLayer") - procCopyLayer = modvmcompute.NewProc("CopyLayer") - procCreateLayer = modvmcompute.NewProc("CreateLayer") - procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer") - procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize") - procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer") - procDestroyLayer = modvmcompute.NewProc("DestroyLayer") - procExportLayer = modvmcompute.NewProc("ExportLayer") - procGetLayerMountPath = modvmcompute.NewProc("GetLayerMountPath") - procGetBaseImages = modvmcompute.NewProc("GetBaseImages") - procImportLayer = modvmcompute.NewProc("ImportLayer") - procLayerExists = modvmcompute.NewProc("LayerExists") - procNameToGuid = modvmcompute.NewProc("NameToGuid") - procPrepareLayer = modvmcompute.NewProc("PrepareLayer") - procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer") - procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage") - procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage") - procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin") - procImportLayerNext = modvmcompute.NewProc("ImportLayerNext") - procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite") - procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd") - procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin") - procExportLayerNext = modvmcompute.NewProc("ExportLayerNext") - procExportLayerRead = modvmcompute.NewProc("ExportLayerRead") - procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd") - procCreateComputeSystem = modvmcompute.NewProc("CreateComputeSystem") - procCreateProcessWithStdHandlesInComputeSystem = modvmcompute.NewProc("CreateProcessWithStdHandlesInComputeSystem") - procResizeConsoleInComputeSystem = modvmcompute.NewProc("ResizeConsoleInComputeSystem") - procShutdownComputeSystem = modvmcompute.NewProc("ShutdownComputeSystem") - procStartComputeSystem = modvmcompute.NewProc("StartComputeSystem") - procTerminateComputeSystem = modvmcompute.NewProc("TerminateComputeSystem") - procTerminateProcessInComputeSystem = modvmcompute.NewProc("TerminateProcessInComputeSystem") - procWaitForProcessInComputeSystem = modvmcompute.NewProc("WaitForProcessInComputeSystem") - procGetComputeSystemProperties = modvmcompute.NewProc("GetComputeSystemProperties") - procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems") - procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem") - procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem") - procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem") - procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem") - procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem") - procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem") - procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem") - procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem") - procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties") - procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem") - procHcsCreateComputeSystemWait = modvmcompute.NewProc("HcsCreateComputeSystemWait") - procHcsCreateProcess = modvmcompute.NewProc("HcsCreateProcess") - procHcsOpenProcess = modvmcompute.NewProc("HcsOpenProcess") - procHcsCloseProcess = modvmcompute.NewProc("HcsCloseProcess") - procHcsTerminateProcess = modvmcompute.NewProc("HcsTerminateProcess") - procHcsGetProcessInfo = modvmcompute.NewProc("HcsGetProcessInfo") - procHcsGetProcessProperties = modvmcompute.NewProc("HcsGetProcessProperties") - procHcsModifyProcess = modvmcompute.NewProc("HcsModifyProcess") - procHcsCreateProcessWait = modvmcompute.NewProc("HcsCreateProcessWait") - procHcsGetServiceProperties = modvmcompute.NewProc("HcsGetServiceProperties") - procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") - + procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") + procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") + procActivateLayer = modvmcompute.NewProc("ActivateLayer") + procCopyLayer = modvmcompute.NewProc("CopyLayer") + procCreateLayer = modvmcompute.NewProc("CreateLayer") + procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer") + procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize") + procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer") + procDestroyLayer = modvmcompute.NewProc("DestroyLayer") + procExportLayer = modvmcompute.NewProc("ExportLayer") + procGetLayerMountPath = modvmcompute.NewProc("GetLayerMountPath") + procGetBaseImages = modvmcompute.NewProc("GetBaseImages") + procImportLayer = modvmcompute.NewProc("ImportLayer") + procLayerExists = modvmcompute.NewProc("LayerExists") + procNameToGuid = modvmcompute.NewProc("NameToGuid") + procPrepareLayer = modvmcompute.NewProc("PrepareLayer") + procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer") + procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage") + procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage") + procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin") + procImportLayerNext = modvmcompute.NewProc("ImportLayerNext") + procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite") + procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd") + procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin") + procExportLayerNext = modvmcompute.NewProc("ExportLayerNext") + procExportLayerRead = modvmcompute.NewProc("ExportLayerRead") + procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd") + procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems") + procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem") + procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem") + procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem") + procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem") + procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem") + procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem") + procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem") + procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem") + procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties") + procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem") procHcsRegisterComputeSystemCallback = modvmcompute.NewProc("HcsRegisterComputeSystemCallback") 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") procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback") + procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") procHNSCall = modvmcompute.NewProc("HNSCall") ) @@ -599,196 +587,6 @@ func exportLayerEnd(context uintptr) (hr error) { 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) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(query) @@ -1005,11 +803,22 @@ func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, res return } -func hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) { - if hr = procHcsCreateComputeSystemWait.Find(); hr != nil { +func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { + if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil { 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 { hr = syscall.Errno(win32FromHresult(r0)) } @@ -1111,17 +920,6 @@ func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (h return } -func hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) { - if hr = procHcsCreateProcessWait.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsCreateProcessWait.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - func hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(propertyQuery) @@ -1142,128 +940,6 @@ func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result return } -func hcsModifyServiceSettings(settings string, result **uint16) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(settings) - if hr != nil { - return - } - return _hcsModifyServiceSettings(_p0, result) -} - -func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) { - if hr = procHcsModifyServiceSettings.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) { - var _p0 *uint16 - _p0, hr = syscall.UTF16PtrFromString(id) - if hr != nil { - return - } - var _p1 *uint16 - _p1, hr = syscall.UTF16PtrFromString(configuration) - if hr != nil { - return - } - return _hcsCreateComputeSystemTP5(_p0, _p1, computeSystem, result) -} - -func _hcsCreateComputeSystemTP5(id *uint16, configuration *uint16, computeSystem *hcsSystem, result **uint16) (hr error) { - if hr = procHcsCreateComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsStartComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsShutdownComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsTerminateComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsPauseComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) { - if hr = procHcsResumeComputeSystem.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { - if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - -func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) { - if hr = procHcsUnregisterComputeSystemCallback.Find(); hr != nil { - return - } - r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - return -} - func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) { if hr = procHcsRegisterProcessCallback.Find(); hr != nil { return @@ -1286,6 +962,26 @@ func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) { 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) { var _p0 *uint16 _p0, hr = syscall.UTF16PtrFromString(method) diff --git a/default_gateway.go b/default_gateway.go index 2f2e284f..163348b4 100644 --- a/default_gateway.go +++ b/default_gateway.go @@ -2,13 +2,14 @@ package libnetwork import ( "fmt" + "strings" + "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/types" ) const ( - libnGWNetwork = "docker_gwbridge" - gwEPlen = 12 + gwEPlen = 12 ) var procGwNetwork = make(chan (bool), 1) @@ -52,6 +53,21 @@ func (sb *sandbox) setupDefaultGW() error { 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...) if err != nil { 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 { for _, ep := range sb.getConnectedEndpoints() { - if ep.getNetwork().name == libnGWNetwork { + if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") { return ep } } @@ -127,7 +143,7 @@ func (sb *sandbox) getEndpointInGWNetwork() *endpoint { } func (ep *endpoint) endpointInGWNetwork() bool { - if ep.getNetwork().name == libnGWNetwork { + if ep.getNetwork().name == libnGWNetwork && strings.HasPrefix(ep.Name(), "gateway_") { return true } return false diff --git a/default_gateway_freebsd.go b/default_gateway_freebsd.go index a8268739..dc4b1bd5 100644 --- a/default_gateway_freebsd.go +++ b/default_gateway_freebsd.go @@ -2,6 +2,12 @@ package libnetwork import "github.com/docker/libnetwork/types" +const libnGWNetwork = "docker_gwbridge" + +func getPlatformOption() EndpointOption { + return nil +} + func (c *controller) createGWNetwork() (Network, error) { return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in freebsd") } diff --git a/default_gateway_linux.go b/default_gateway_linux.go index c08b0618..60df8567 100644 --- a/default_gateway_linux.go +++ b/default_gateway_linux.go @@ -7,6 +7,12 @@ import ( "github.com/docker/libnetwork/drivers/bridge" ) +const libnGWNetwork = "docker_gwbridge" + +func getPlatformOption() EndpointOption { + return nil +} + func (c *controller) createGWNetwork() (Network, error) { netOption := map[string]string{ bridge.BridgeName: libnGWNetwork, diff --git a/default_gateway_solaris.go b/default_gateway_solaris.go index 42f4d5c6..8d86a66c 100644 --- a/default_gateway_solaris.go +++ b/default_gateway_solaris.go @@ -7,6 +7,12 @@ import ( "github.com/docker/libnetwork/drivers/solaris/bridge" ) +const libnGWNetwork = "docker_gwbridge" + +func getPlatformOption() EndpointOption { + return nil +} + func (c *controller) createGWNetwork() (Network, error) { netOption := map[string]string{ bridge.BridgeName: libnGWNetwork, diff --git a/default_gateway_windows.go b/default_gateway_windows.go index 48eee2ba..f4ba198e 100644 --- a/default_gateway_windows.go +++ b/default_gateway_windows.go @@ -1,6 +1,21 @@ 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) { return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in windows") diff --git a/drivers/windows/labels.go b/drivers/windows/labels.go index 5740913c..b32c6ffb 100644 --- a/drivers/windows/labels.go +++ b/drivers/windows/labels.go @@ -30,4 +30,10 @@ const ( // SourceMac of the network SourceMac = "com.docker.network.windowsshim.sourcemac" + + // DisableICC label + DisableICC = "com.docker.network.windowsshim.disableicc" + + // DisableDNS label + DisableDNS = "com.docker.network.windowsshim.disable_dns" ) diff --git a/drivers/windows/overlay/joinleave_windows.go b/drivers/windows/overlay/joinleave_windows.go index 0bef47c7..bfdadf86 100644 --- a/drivers/windows/overlay/joinleave_windows.go +++ b/drivers/windows/overlay/joinleave_windows.go @@ -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) } - jinfo.DisableGatewayService() - d.pushLocalEndpointEvent("join", nid, eid) return nil diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index 01658141..f9c61d30 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -44,21 +44,28 @@ type networkConfiguration struct { } // endpointConfiguration represents the user specified configuration for the sandbox endpoint -type endpointConfiguration struct { - MacAddress net.HardwareAddr +type endpointOption struct { + MacAddress net.HardwareAddr + QosPolicies []types.QosPolicy + DNSServers []string + DisableDNS bool + DisableICC bool +} + +type endpointConnectivity struct { PortBindings []types.PortBinding ExposedPorts []types.TransportPort - QosPolicies []types.QosPolicy - DNSServers []string } type hnsEndpoint struct { - id string - profileID string - macAddress net.HardwareAddr - config *endpointConfiguration // User specified parameters - portMapping []types.PortBinding // Operation port bindings - addr *net.IPNet + id string + profileID string + macAddress net.HardwareAddr + epOption *endpointOption // User specified parameters + epConnectivity *endpointConnectivity // User specified parameters + portMapping []types.PortBinding // Operation port bindings + addr *net.IPNet + gateway net.IP } type hnsNetwork struct { @@ -391,12 +398,12 @@ func parsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, return bindings, nil } -func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) { +func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) { if epOptions == nil { return nil, nil } - ec := &endpointConfiguration{} + ec := &endpointOption{} if opt, ok := epOptions[netlabel.MacAddress]; 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 policies, ok := opt.([]types.QosPolicy); ok { 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 } @@ -457,7 +489,8 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, VirtualNetwork: n.config.HnsID, } - ec, err := parseEndpointOptions(epOptions) + epOption, err := parseEndpointOptions(epOptions) + epConnectivity, err := parseEndpointConnectivity(epOptions) macAddress := ifInfo.MacAddress() // 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.Policies, err = convertPortBindings(ec.PortBindings) + endpointStruct.Policies, err = convertPortBindings(epConnectivity.PortBindings) if err != nil { return err } - qosPolicies, err := convertQosPolicies(ec.QosPolicies) + qosPolicies, err := convertQosPolicies(epOption.QosPolicies) if err != nil { return err } @@ -480,12 +513,14 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, 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.DisableICC = epOption.DisableICC + configurationb, err := json.Marshal(endpointStruct) if err != nil { return err @@ -508,8 +543,13 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, macAddress: mac, } + if hnsresponse.GatewayAddress != "" { + endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress) + } + endpoint.profileID = hnsresponse.Id - endpoint.config = ec + endpoint.epConnectivity = epConnectivity + endpoint.epOption = epOption endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies) if err != nil { @@ -572,10 +612,10 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro } data["hnsid"] = ep.profileID - if ep.config.ExposedPorts != nil { + if ep.epConnectivity.ExposedPorts != nil { // Return a copy of the config data - epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts)) - for _, tp := range ep.config.ExposedPorts { + epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts)) + for _, tp := range ep.epConnectivity.ExposedPorts { epc = append(epc, tp.GetCopy()) } 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 - _, err = network.getEndpoint(eid) + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + err = jinfo.SetGateway(endpoint.gateway) if err != nil { return err } diff --git a/endpoint_info.go b/endpoint_info.go index 1042ddaa..6814de00 100644 --- a/endpoint_info.go +++ b/endpoint_info.go @@ -205,31 +205,6 @@ func (ep *endpoint) Info() EndpointInfo { 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 { ep.Lock() defer ep.Unlock() diff --git a/endpoint_info_unix.go b/endpoint_info_unix.go new file mode 100644 index 00000000..f2534f49 --- /dev/null +++ b/endpoint_info_unix.go @@ -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()) +} diff --git a/endpoint_info_windows.go b/endpoint_info_windows.go new file mode 100644 index 00000000..93ad8330 --- /dev/null +++ b/endpoint_info_windows.go @@ -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 +}