Browse code

Merge pull request #34928 from darrenstahlmsft/HnsRunning

Ensure Host Network Service exists

Sebastiaan van Stijn authored on 2017/09/28 00:35:08
Showing 2 changed files
... ...
@@ -27,8 +27,10 @@ import (
27 27
 	"github.com/docker/libnetwork/netlabel"
28 28
 	"github.com/docker/libnetwork/options"
29 29
 	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
30
+	"github.com/pkg/errors"
30 31
 	"github.com/sirupsen/logrus"
31 32
 	"golang.org/x/sys/windows"
33
+	"golang.org/x/sys/windows/svc/mgr"
32 34
 )
33 35
 
34 36
 const (
... ...
@@ -238,6 +240,29 @@ func checkSystem() error {
238 238
 		return fmt.Errorf("failed to load vmcompute.dll, ensure that the Containers feature is installed")
239 239
 	}
240 240
 
241
+	// Ensure that the required Host Network Service and vmcompute services
242
+	// are running. Docker will fail in unexpected ways if this is not present.
243
+	var requiredServices = []string{"hns", "vmcompute"}
244
+	if err := ensureServicesInstalled(requiredServices); err != nil {
245
+		return errors.Wrap(err, "a required service is not installed, ensure the Containers feature is installed")
246
+	}
247
+
248
+	return nil
249
+}
250
+
251
+func ensureServicesInstalled(services []string) error {
252
+	m, err := mgr.Connect()
253
+	if err != nil {
254
+		return err
255
+	}
256
+	defer m.Disconnect()
257
+	for _, service := range services {
258
+		s, err := m.OpenService(service)
259
+		if err != nil {
260
+			return errors.Wrapf(err, "failed to open service %s", service)
261
+		}
262
+		s.Close()
263
+	}
241 264
 	return nil
242 265
 }
243 266
 
244 267
new file mode 100644
... ...
@@ -0,0 +1,72 @@
0
+// +build windows
1
+
2
+package daemon
3
+
4
+import (
5
+	"strings"
6
+	"testing"
7
+
8
+	"golang.org/x/sys/windows/svc/mgr"
9
+)
10
+
11
+const existingService = "Power"
12
+
13
+func TestEnsureServicesExist(t *testing.T) {
14
+	m, err := mgr.Connect()
15
+	if err != nil {
16
+		t.Fatal("failed to connect to service manager, this test needs admin")
17
+	}
18
+	defer m.Disconnect()
19
+	s, err := m.OpenService(existingService)
20
+	if err != nil {
21
+		t.Fatalf("expected to find known inbox service %q, this test needs a known inbox service to run correctly", existingService)
22
+	}
23
+	defer s.Close()
24
+
25
+	input := []string{existingService}
26
+	err = ensureServicesInstalled(input)
27
+	if err != nil {
28
+		t.Fatalf("unexpected error for input %q: %q", input, err)
29
+	}
30
+}
31
+
32
+func TestEnsureServicesExistErrors(t *testing.T) {
33
+	m, err := mgr.Connect()
34
+	if err != nil {
35
+		t.Fatal("failed to connect to service manager, this test needs admin")
36
+	}
37
+	defer m.Disconnect()
38
+	s, err := m.OpenService(existingService)
39
+	if err != nil {
40
+		t.Fatalf("expected to find known inbox service %q, this test needs a known inbox service to run correctly", existingService)
41
+	}
42
+	defer s.Close()
43
+
44
+	for _, testcase := range []struct {
45
+		input         []string
46
+		expectedError string
47
+	}{
48
+		{
49
+			input:         []string{"daemon_windows_test_fakeservice"},
50
+			expectedError: "failed to open service daemon_windows_test_fakeservice",
51
+		},
52
+		{
53
+			input:         []string{"daemon_windows_test_fakeservice1", "daemon_windows_test_fakeservice2"},
54
+			expectedError: "failed to open service daemon_windows_test_fakeservice1",
55
+		},
56
+		{
57
+			input:         []string{existingService, "daemon_windows_test_fakeservice"},
58
+			expectedError: "failed to open service daemon_windows_test_fakeservice",
59
+		},
60
+	} {
61
+		t.Run(strings.Join(testcase.input, ";"), func(t *testing.T) {
62
+			err := ensureServicesInstalled(testcase.input)
63
+			if err == nil {
64
+				t.Fatalf("expected error for input %v", testcase.input)
65
+			}
66
+			if !strings.Contains(err.Error(), testcase.expectedError) {
67
+				t.Fatalf("expected error %q to contain %q", err.Error(), testcase.expectedError)
68
+			}
69
+		})
70
+	}
71
+}