Browse code

Ignore certificate expiry error for top-level inspect

The top-level `docker inspect` command could return
an error if the nodes Swarm certificates were expired.

In situations where the user did not explicitly
ask for an object-type (`--type=foo`), we should
ignore these errors, and consider them equal to
"node is not a swarm manager".

This change makes `docker inspect` ignore these
errors if no type was specified.

As a further optimization, the "swarm status"
result is now stored in a variable, so that
other swarm-specific API calls can be skipped.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2016/12/08 20:04:22
Showing 1 changed files
... ...
@@ -2,7 +2,6 @@ package system
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"strings"
6 5
 
7 6
 	"golang.org/x/net/context"
8 7
 
... ...
@@ -103,38 +102,94 @@ func inspectPlugin(ctx context.Context, dockerCli *command.DockerCli) inspect.Ge
103 103
 
104 104
 func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc {
105 105
 	var inspectAutodetect = []struct {
106
-		ObjectType      string
107
-		IsSizeSupported bool
108
-		ObjectInspector func(string) (interface{}, []byte, error)
106
+		objectType      string
107
+		isSizeSupported bool
108
+		isSwarmObject   bool
109
+		objectInspector func(string) (interface{}, []byte, error)
109 110
 	}{
110
-		{"container", true, inspectContainers(ctx, dockerCli, getSize)},
111
-		{"image", false, inspectImages(ctx, dockerCli)},
112
-		{"network", false, inspectNetwork(ctx, dockerCli)},
113
-		{"volume", false, inspectVolume(ctx, dockerCli)},
114
-		{"service", false, inspectService(ctx, dockerCli)},
115
-		{"task", false, inspectTasks(ctx, dockerCli)},
116
-		{"node", false, inspectNode(ctx, dockerCli)},
117
-		{"plugin", false, inspectPlugin(ctx, dockerCli)},
111
+		{
112
+			objectType:      "container",
113
+			isSizeSupported: true,
114
+			objectInspector: inspectContainers(ctx, dockerCli, getSize),
115
+		},
116
+		{
117
+			objectType:      "image",
118
+			objectInspector: inspectImages(ctx, dockerCli),
119
+		},
120
+		{
121
+			objectType:      "network",
122
+			objectInspector: inspectNetwork(ctx, dockerCli),
123
+		},
124
+		{
125
+			objectType:      "volume",
126
+			objectInspector: inspectVolume(ctx, dockerCli),
127
+		},
128
+		{
129
+			objectType:      "service",
130
+			isSwarmObject:   true,
131
+			objectInspector: inspectService(ctx, dockerCli),
132
+		},
133
+		{
134
+			objectType:      "task",
135
+			isSwarmObject:   true,
136
+			objectInspector: inspectTasks(ctx, dockerCli),
137
+		},
138
+		{
139
+			objectType:      "node",
140
+			isSwarmObject:   true,
141
+			objectInspector: inspectNode(ctx, dockerCli),
142
+		},
143
+		{
144
+			objectType:      "plugin",
145
+			objectInspector: inspectPlugin(ctx, dockerCli),
146
+		},
118 147
 	}
119 148
 
120
-	isErrNotSwarmManager := func(err error) bool {
121
-		return strings.Contains(err.Error(), "This node is not a swarm manager")
149
+	// isSwarmManager does an Info API call to verify that the daemon is
150
+	// a swarm manager.
151
+	isSwarmManager := func() bool {
152
+		info, err := dockerCli.Client().Info(ctx)
153
+		if err != nil {
154
+			fmt.Fprintln(dockerCli.Err(), err)
155
+			return false
156
+		}
157
+		return info.Swarm.ControlAvailable
122 158
 	}
123 159
 
124 160
 	return func(ref string) (interface{}, []byte, error) {
161
+		const (
162
+			swarmSupportUnknown = iota
163
+			swarmSupported
164
+			swarmUnsupported
165
+		)
166
+
167
+		isSwarmSupported := swarmSupportUnknown
168
+
125 169
 		for _, inspectData := range inspectAutodetect {
126
-			if typeConstraint != "" && inspectData.ObjectType != typeConstraint {
170
+			if typeConstraint != "" && inspectData.objectType != typeConstraint {
127 171
 				continue
128 172
 			}
129
-			v, raw, err := inspectData.ObjectInspector(ref)
173
+			if typeConstraint == "" && inspectData.isSwarmObject {
174
+				if isSwarmSupported == swarmSupportUnknown {
175
+					if isSwarmManager() {
176
+						isSwarmSupported = swarmSupported
177
+					} else {
178
+						isSwarmSupported = swarmUnsupported
179
+					}
180
+				}
181
+				if isSwarmSupported == swarmUnsupported {
182
+					continue
183
+				}
184
+			}
185
+			v, raw, err := inspectData.objectInspector(ref)
130 186
 			if err != nil {
131
-				if typeConstraint == "" && (apiclient.IsErrNotFound(err) || isErrNotSwarmManager(err)) {
187
+				if typeConstraint == "" && apiclient.IsErrNotFound(err) {
132 188
 					continue
133 189
 				}
134 190
 				return v, raw, err
135 191
 			}
136
-			if getSize && !inspectData.IsSizeSupported {
137
-				fmt.Fprintf(dockerCli.Err(), "WARNING: --size ignored for %s\n", inspectData.ObjectType)
192
+			if getSize && !inspectData.isSizeSupported {
193
+				fmt.Fprintf(dockerCli.Err(), "WARNING: --size ignored for %s\n", inspectData.objectType)
138 194
 			}
139 195
 			return v, raw, err
140 196
 		}