Browse code

Better error message on stack deploy against not a swarm.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2016/11/22 05:03:43
Showing 2 changed files
... ...
@@ -1,6 +1,7 @@
1 1
 package stack
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"io/ioutil"
6 7
 	"os"
... ...
@@ -59,19 +60,36 @@ func newDeployCommand(dockerCli *command.DockerCli) *cobra.Command {
59 59
 }
60 60
 
61 61
 func runDeploy(dockerCli *command.DockerCli, opts deployOptions) error {
62
+	ctx := context.Background()
63
+
62 64
 	switch {
63 65
 	case opts.bundlefile == "" && opts.composefile == "":
64 66
 		return fmt.Errorf("Please specify either a bundle file (with --bundle-file) or a Compose file (with --compose-file).")
65 67
 	case opts.bundlefile != "" && opts.composefile != "":
66 68
 		return fmt.Errorf("You cannot specify both a bundle file and a Compose file.")
67 69
 	case opts.bundlefile != "":
68
-		return deployBundle(dockerCli, opts)
70
+		return deployBundle(ctx, dockerCli, opts)
69 71
 	default:
70
-		return deployCompose(dockerCli, opts)
72
+		return deployCompose(ctx, dockerCli, opts)
71 73
 	}
72 74
 }
73 75
 
74
-func deployCompose(dockerCli *command.DockerCli, opts deployOptions) error {
76
+// checkDaemonIsSwarmManager does an Info API call to verify that the daemon is
77
+// a swarm manager. This is necessary because we must create networks before we
78
+// create services, but the API call for creating a network does not return a
79
+// proper status code when it can't create a network in the "global" scope.
80
+func checkDaemonIsSwarmManager(ctx context.Context, dockerCli *command.DockerCli) error {
81
+	info, err := dockerCli.Client().Info(ctx)
82
+	if err != nil {
83
+		return err
84
+	}
85
+	if !info.Swarm.ControlAvailable {
86
+		return errors.New("This node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again.")
87
+	}
88
+	return nil
89
+}
90
+
91
+func deployCompose(ctx context.Context, dockerCli *command.DockerCli, opts deployOptions) error {
75 92
 	configDetails, err := getConfigDetails(opts)
76 93
 	if err != nil {
77 94
 		return err
... ...
@@ -99,7 +117,10 @@ func deployCompose(dockerCli *command.DockerCli, opts deployOptions) error {
99 99
 			propertyWarnings(deprecatedProperties))
100 100
 	}
101 101
 
102
-	ctx := context.Background()
102
+	if err := checkDaemonIsSwarmManager(ctx, dockerCli); err != nil {
103
+		return err
104
+	}
105
+
103 106
 	namespace := namespace{name: opts.namespace}
104 107
 
105 108
 	networks := convertNetworks(namespace, config.Networks)
... ...
@@ -8,12 +8,16 @@ import (
8 8
 	"github.com/docker/docker/cli/command"
9 9
 )
10 10
 
11
-func deployBundle(dockerCli *command.DockerCli, opts deployOptions) error {
11
+func deployBundle(ctx context.Context, dockerCli *command.DockerCli, opts deployOptions) error {
12 12
 	bundle, err := loadBundlefile(dockerCli.Err(), opts.namespace, opts.bundlefile)
13 13
 	if err != nil {
14 14
 		return err
15 15
 	}
16 16
 
17
+	if err := checkDaemonIsSwarmManager(ctx, dockerCli); err != nil {
18
+		return err
19
+	}
20
+
17 21
 	namespace := namespace{name: opts.namespace}
18 22
 
19 23
 	networks := make(map[string]types.NetworkCreate)
... ...
@@ -71,8 +75,6 @@ func deployBundle(dockerCli *command.DockerCli, opts deployOptions) error {
71 71
 		services[internalName] = serviceSpec
72 72
 	}
73 73
 
74
-	ctx := context.Background()
75
-
76 74
 	if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil {
77 75
 		return err
78 76
 	}