Преглед на файлове

Windows: Wait for OOBE to prevent crashing during host update

Signed-off-by: Darren Stahl <darst@microsoft.com>
Darren Stahl преди 8 години
родител
ревизия
e128a65685
променени са 6 файла, в които са добавени 61 реда и са изтрити 3 реда
  1. 3 0
      cmd/dockerd/daemon.go
  2. 4 0
      cmd/dockerd/daemon_freebsd.go
  3. 4 0
      cmd/dockerd/daemon_linux.go
  4. 4 0
      cmd/dockerd/daemon_solaris.go
  5. 8 2
      cmd/dockerd/daemon_windows.go
  6. 38 1
      daemon/daemon_windows.go

+ 3 - 0
cmd/dockerd/daemon.go

@@ -260,6 +260,9 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) {
 		<-stopc // wait for daemonCli.start() to return
 	})
 
+	// Notify that the API is active, but before daemon is set up.
+	preNotifySystem()
+
 	d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote)
 	if err != nil {
 		return fmt.Errorf("Error starting daemon: %v", err)

+ 4 - 0
cmd/dockerd/daemon_freebsd.go

@@ -1,5 +1,9 @@
 package main
 
+// preNotifySystem sends a message to the host when the API is active, but before the daemon is
+func preNotifySystem() {
+}
+
 // notifySystem sends a message to the host when the server is ready to be used
 func notifySystem() {
 }

+ 4 - 0
cmd/dockerd/daemon_linux.go

@@ -4,6 +4,10 @@ package main
 
 import systemdDaemon "github.com/coreos/go-systemd/daemon"
 
+// preNotifySystem sends a message to the host when the API is active, but before the daemon is
+func preNotifySystem() {
+}
+
 // notifySystem sends a message to the host when the server is ready to be used
 func notifySystem() {
 	// Tell the init daemon we are accepting requests

+ 4 - 0
cmd/dockerd/daemon_solaris.go

@@ -46,6 +46,10 @@ func getDaemonConfDir(_ string) string {
 func (cli *DaemonCli) setupConfigReloadTrap() {
 }
 
+// preNotifySystem sends a message to the host when the API is active, but before the daemon is
+func preNotifySystem() {
+}
+
 // notifySystem sends a message to the host when the server is ready to be used
 func notifySystem() {
 }

+ 8 - 2
cmd/dockerd/daemon_windows.go

@@ -29,8 +29,10 @@ func getDaemonConfDir(root string) string {
 	return filepath.Join(root, `\config`)
 }
 
-// notifySystem sends a message to the host when the server is ready to be used
-func notifySystem() {
+// preNotifySystem sends a message to the host when the API is active, but before the daemon is
+func preNotifySystem() {
+	// start the service now to prevent timeouts waiting for daemon to start
+	// but still (eventually) complete all requests that are sent after this
 	if service != nil {
 		err := service.started()
 		if err != nil {
@@ -39,6 +41,10 @@ func notifySystem() {
 	}
 }
 
+// notifySystem sends a message to the host when the server is ready to be used
+func notifySystem() {
+}
+
 // notifyShutdown is called after the daemon shuts down but before the process exits.
 func notifyShutdown(err error) {
 	if service != nil {

+ 38 - 1
daemon/daemon_windows.go

@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"os"
 	"strings"
+	"syscall"
+	"unsafe"
 
 	"github.com/Microsoft/hcsshim"
 	"github.com/Sirupsen/logrus"
@@ -35,6 +37,8 @@ const (
 	windowsMinCPUPercent = 1
 	windowsMaxCPUPercent = 100
 	windowsMinCPUCount   = 1
+
+	errInvalidState = syscall.Errno(0x139F)
 )
 
 func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
@@ -229,7 +233,8 @@ func checkSystem() error {
 	if vmcompute.Load() != nil {
 		return fmt.Errorf("Failed to load vmcompute.dll. Ensure that the Containers role is installed.")
 	}
-	return nil
+
+	return waitOOBEComplete()
 }
 
 // configureKernelSecuritySupport configures and validate security support for the kernel
@@ -601,3 +606,35 @@ func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
 func (daemon *Daemon) setupSeccompProfile() error {
 	return nil
 }
+
+func waitOOBEComplete() error {
+	kernel32 := windows.NewLazySystemDLL("kernel32.dll")
+	registerWaitUntilOOBECompleted := kernel32.NewProc("RegisterWaitUntilOOBECompleted")
+	unregisterWaitUntilOOBECompleted := kernel32.NewProc("UnregisterWaitUntilOOBECompleted")
+
+	callbackChan := make(chan struct{})
+	callbackFunc := func(uintptr) uintptr {
+		close(callbackChan)
+		return 0
+	}
+	callbackFuncPtr := syscall.NewCallback(callbackFunc)
+
+	var callbackHandle syscall.Handle
+	ret, _, err := registerWaitUntilOOBECompleted.Call(callbackFuncPtr, 0, uintptr(unsafe.Pointer(&callbackHandle)))
+	if ret == 0 {
+		if err == errInvalidState {
+			return nil
+		}
+		return fmt.Errorf("failed to register OOBEComplete callback. Error: %v", err)
+	}
+
+	// Wait for the callback when OOBE is finished
+	<-callbackChan
+
+	ret, _, err = unregisterWaitUntilOOBECompleted.Call(uintptr(callbackHandle))
+	if ret == 0 {
+		return fmt.Errorf("failed to unregister OOBEComplete callback. Error: %v", err)
+	}
+
+	return nil
+}