Browse code

api: types: keep info.SecurityOptions a string slice

Signed-off-by: Antonio Murdaca <runcom@redhat.com>

Antonio Murdaca authored on 2016/11/17 06:30:29
Showing 8 changed files
... ...
@@ -16,7 +16,6 @@ import (
16 16
 	"github.com/docker/docker/api/types/registry"
17 17
 	timetypes "github.com/docker/docker/api/types/time"
18 18
 	"github.com/docker/docker/api/types/versions"
19
-	"github.com/docker/docker/api/types/versions/v1p24"
20 19
 	"github.com/docker/docker/pkg/ioutils"
21 20
 	"golang.org/x/net/context"
22 21
 )
... ...
@@ -42,16 +41,24 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
42 42
 
43 43
 	if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") {
44 44
 		// TODO: handle this conversion in engine-api
45
-		oldInfo := &v1p24.Info{
46
-			InfoBase:        info.InfoBase,
45
+		type oldInfo struct {
46
+			*types.Info
47
+			ExecutionDriver string
48
+		}
49
+		old := &oldInfo{
50
+			Info:            info,
47 51
 			ExecutionDriver: "<not supported>",
48 52
 		}
49
-		for _, s := range info.SecurityOptions {
50
-			if s.Key == "Name" {
51
-				oldInfo.SecurityOptions = append(oldInfo.SecurityOptions, s.Value)
52
-			}
53
+		nameOnlySecurityOptions := []string{}
54
+		kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions)
55
+		if err != nil {
56
+			return err
57
+		}
58
+		for _, s := range kvSecOpts {
59
+			nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name)
53 60
 		}
54
-		return httputils.WriteJSON(w, http.StatusOK, oldInfo)
61
+		old.SecurityOptions = nameOnlySecurityOptions
62
+		return httputils.WriteJSON(w, http.StatusOK, old)
55 63
 	}
56 64
 	return httputils.WriteJSON(w, http.StatusOK, info)
57 65
 }
... ...
@@ -1,8 +1,11 @@
1 1
 package types
2 2
 
3 3
 import (
4
+	"errors"
5
+	"fmt"
4 6
 	"io"
5 7
 	"os"
8
+	"strings"
6 9
 	"time"
7 10
 
8 11
 	"github.com/docker/docker/api/types/container"
... ...
@@ -158,9 +161,9 @@ type Commit struct {
158 158
 	Expected string
159 159
 }
160 160
 
161
-// InfoBase contains the base response of Remote API:
161
+// Info contains response of Remote API:
162 162
 // GET "/info"
163
-type InfoBase struct {
163
+type Info struct {
164 164
 	ID                 string
165 165
 	Containers         int
166 166
 	ContainersRunning  int
... ...
@@ -219,18 +222,49 @@ type InfoBase struct {
219 219
 	ContainerdCommit   Commit
220 220
 	RuncCommit         Commit
221 221
 	InitCommit         Commit
222
+	SecurityOptions    []string
222 223
 }
223 224
 
224
-// SecurityOpt holds key/value pair about a security option
225
-type SecurityOpt struct {
225
+// KeyValue holds a key/value pair
226
+type KeyValue struct {
226 227
 	Key, Value string
227 228
 }
228 229
 
229
-// Info contains response of Remote API:
230
-// GET "/info"
231
-type Info struct {
232
-	*InfoBase
233
-	SecurityOptions []SecurityOpt
230
+// SecurityOpt contains the name and options of a security option
231
+type SecurityOpt struct {
232
+	Name    string
233
+	Options []KeyValue
234
+}
235
+
236
+// DecodeSecurityOptions decodes a security options string slice to a type safe
237
+// SecurityOpt
238
+func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) {
239
+	so := []SecurityOpt{}
240
+	for _, opt := range opts {
241
+		// support output from a < 1.13 docker daemon
242
+		if !strings.Contains(opt, "=") {
243
+			so = append(so, SecurityOpt{Name: opt})
244
+			continue
245
+		}
246
+		secopt := SecurityOpt{}
247
+		split := strings.Split(opt, ",")
248
+		for _, s := range split {
249
+			kv := strings.SplitN(s, "=", 2)
250
+			if len(kv) != 2 {
251
+				return nil, fmt.Errorf("invalid security option %q", s)
252
+			}
253
+			if kv[0] == "" || kv[1] == "" {
254
+				return nil, errors.New("invalid empty security option")
255
+			}
256
+			if kv[0] == "name" {
257
+				secopt.Name = kv[1]
258
+				continue
259
+			}
260
+			secopt.Options = append(secopt.Options, KeyValue{Key: kv[0], Value: kv[1]})
261
+		}
262
+		so = append(so, secopt)
263
+	}
264
+	return so, nil
234 265
 }
235 266
 
236 267
 // PluginsInfo is a temp struct holding Plugins name
237 268
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-// Package v1p24 provides specific API types for the API version 1, patch 24.
2
-package v1p24
3
-
4
-import "github.com/docker/docker/api/types"
5
-
6
-// Info is a backcompatibility struct for the API 1.24
7
-type Info struct {
8
-	*types.InfoBase
9
-	ExecutionDriver string
10
-	SecurityOptions []string
11
-}
... ...
@@ -172,16 +172,21 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
172 172
 			fmt.Fprintf(dockerCli.Out(), "\n")
173 173
 		}
174 174
 		if len(info.SecurityOptions) != 0 {
175
+			kvs, err := types.DecodeSecurityOptions(info.SecurityOptions)
176
+			if err != nil {
177
+				return err
178
+			}
175 179
 			fmt.Fprintf(dockerCli.Out(), "Security Options:\n")
176
-			for _, o := range info.SecurityOptions {
177
-				switch o.Key {
178
-				case "Name":
179
-					fmt.Fprintf(dockerCli.Out(), " %s\n", o.Value)
180
-				case "Profile":
181
-					if o.Value != "default" {
182
-						fmt.Fprintf(dockerCli.Err(), "  WARNING: You're not using the default seccomp profile\n")
180
+			for _, so := range kvs {
181
+				fmt.Fprintf(dockerCli.Out(), " %s\n", so.Name)
182
+				for _, o := range so.Options {
183
+					switch o.Key {
184
+					case "profile":
185
+						if o.Value != "default" {
186
+							fmt.Fprintf(dockerCli.Err(), "  WARNING: You're not using the default seccomp profile\n")
187
+						}
188
+						fmt.Fprintf(dockerCli.Out(), "  Profile: %s\n", o.Value)
183 189
 					}
184
-					fmt.Fprintf(dockerCli.Out(), "  %s: %s\n", o.Key, o.Value)
185 190
 				}
186 191
 			}
187 192
 		}
... ...
@@ -46,10 +46,8 @@ func TestInfo(t *testing.T) {
46 46
 				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
47 47
 			}
48 48
 			info := &types.Info{
49
-				InfoBase: &types.InfoBase{
50
-					ID:         "daemonID",
51
-					Containers: 3,
52
-				},
49
+				ID:         "daemonID",
50
+				Containers: 3,
53 51
 			}
54 52
 			b, err := json.Marshal(info)
55 53
 			if err != nil {
... ...
@@ -1,6 +1,7 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"os"
5 6
 	"runtime"
6 7
 	"sync/atomic"
... ...
@@ -69,29 +70,26 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
69 69
 		}
70 70
 	})
71 71
 
72
-	securityOptions := []types.SecurityOpt{}
72
+	securityOptions := []string{}
73 73
 	if sysInfo.AppArmor {
74
-		securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "apparmor"})
74
+		securityOptions = append(securityOptions, "name=apparmor")
75 75
 	}
76 76
 	if sysInfo.Seccomp && supportsSeccomp {
77 77
 		profile := daemon.seccompProfilePath
78 78
 		if profile == "" {
79 79
 			profile = "default"
80 80
 		}
81
-		securityOptions = append(securityOptions,
82
-			types.SecurityOpt{Key: "Name", Value: "seccomp"},
83
-			types.SecurityOpt{Key: "Profile", Value: profile},
84
-		)
81
+		securityOptions = append(securityOptions, fmt.Sprintf("name=seccomp,profile=%s", profile))
85 82
 	}
86 83
 	if selinuxEnabled() {
87
-		securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "selinux"})
84
+		securityOptions = append(securityOptions, "name=selinux")
88 85
 	}
89 86
 	uid, gid := daemon.GetRemappedUIDGID()
90 87
 	if uid != 0 || gid != 0 {
91
-		securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "userns"})
88
+		securityOptions = append(securityOptions, "name=userns")
92 89
 	}
93 90
 
94
-	v := &types.InfoBase{
91
+	v := &types.Info{
95 92
 		ID:                 daemon.ID,
96 93
 		Containers:         int(cRunning + cPaused + cStopped),
97 94
 		ContainersRunning:  int(cRunning),
... ...
@@ -129,6 +127,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
129 129
 		HTTPSProxy:         sockets.GetProxyEnv("https_proxy"),
130 130
 		NoProxy:            sockets.GetProxyEnv("no_proxy"),
131 131
 		LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
132
+		SecurityOptions:    securityOptions,
132 133
 		Isolation:          daemon.defaultIsolation,
133 134
 	}
134 135
 
... ...
@@ -143,12 +142,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
143 143
 	}
144 144
 	v.Name = hostname
145 145
 
146
-	i := &types.Info{
147
-		InfoBase:        v,
148
-		SecurityOptions: securityOptions,
149
-	}
150
-
151
-	return i, nil
146
+	return v, nil
152 147
 }
153 148
 
154 149
 // SystemVersion returns version information about the daemon.
... ...
@@ -14,7 +14,7 @@ import (
14 14
 )
15 15
 
16 16
 // FillPlatformInfo fills the platform related info.
17
-func (daemon *Daemon) FillPlatformInfo(v *types.InfoBase, sysInfo *sysinfo.SysInfo) {
17
+func (daemon *Daemon) FillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
18 18
 	v.MemoryLimit = sysInfo.MemoryLimit
19 19
 	v.SwapLimit = sysInfo.SwapLimit
20 20
 	v.KernelMemory = sysInfo.KernelMemory
... ...
@@ -6,5 +6,5 @@ import (
6 6
 )
7 7
 
8 8
 // FillPlatformInfo fills the platform related info.
9
-func (daemon *Daemon) FillPlatformInfo(v *types.InfoBase, sysInfo *sysinfo.SysInfo) {
9
+func (daemon *Daemon) FillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
10 10
 }