Ver código fonte

api: types: keep info.SecurityOptions a string slice

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
(cherry picked from commit 514ca09426e5d023753101ffa6ac3a21b0e0efb5)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
Antonio Murdaca 8 anos atrás
pai
commit
0a5732d1cf

+ 15 - 8
api/server/router/system/system_routes.go

@@ -16,7 +16,6 @@ import (
 	"github.com/docker/docker/api/types/registry"
 	timetypes "github.com/docker/docker/api/types/time"
 	"github.com/docker/docker/api/types/versions"
-	"github.com/docker/docker/api/types/versions/v1p24"
 	"github.com/docker/docker/pkg/ioutils"
 	"golang.org/x/net/context"
 )
@@ -42,16 +41,24 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
 
 	if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") {
 		// TODO: handle this conversion in engine-api
-		oldInfo := &v1p24.Info{
-			InfoBase:        info.InfoBase,
+		type oldInfo struct {
+			*types.Info
+			ExecutionDriver string
+		}
+		old := &oldInfo{
+			Info:            info,
 			ExecutionDriver: "<not supported>",
 		}
-		for _, s := range info.SecurityOptions {
-			if s.Key == "Name" {
-				oldInfo.SecurityOptions = append(oldInfo.SecurityOptions, s.Value)
-			}
+		nameOnlySecurityOptions := []string{}
+		kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions)
+		if err != nil {
+			return err
+		}
+		for _, s := range kvSecOpts {
+			nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name)
 		}
-		return httputils.WriteJSON(w, http.StatusOK, oldInfo)
+		old.SecurityOptions = nameOnlySecurityOptions
+		return httputils.WriteJSON(w, http.StatusOK, old)
 	}
 	return httputils.WriteJSON(w, http.StatusOK, info)
 }

+ 43 - 9
api/types/types.go

@@ -1,8 +1,11 @@
 package types
 
 import (
+	"errors"
+	"fmt"
 	"io"
 	"os"
+	"strings"
 	"time"
 
 	"github.com/docker/docker/api/types/container"
@@ -158,9 +161,9 @@ type Commit struct {
 	Expected string
 }
 
-// InfoBase contains the base response of Remote API:
+// Info contains response of Remote API:
 // GET "/info"
-type InfoBase struct {
+type Info struct {
 	ID                 string
 	Containers         int
 	ContainersRunning  int
@@ -219,18 +222,49 @@ type InfoBase struct {
 	ContainerdCommit   Commit
 	RuncCommit         Commit
 	InitCommit         Commit
+	SecurityOptions    []string
 }
 
-// SecurityOpt holds key/value pair about a security option
-type SecurityOpt struct {
+// KeyValue holds a key/value pair
+type KeyValue struct {
 	Key, Value string
 }
 
-// Info contains response of Remote API:
-// GET "/info"
-type Info struct {
-	*InfoBase
-	SecurityOptions []SecurityOpt
+// SecurityOpt contains the name and options of a security option
+type SecurityOpt struct {
+	Name    string
+	Options []KeyValue
+}
+
+// DecodeSecurityOptions decodes a security options string slice to a type safe
+// SecurityOpt
+func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) {
+	so := []SecurityOpt{}
+	for _, opt := range opts {
+		// support output from a < 1.13 docker daemon
+		if !strings.Contains(opt, "=") {
+			so = append(so, SecurityOpt{Name: opt})
+			continue
+		}
+		secopt := SecurityOpt{}
+		split := strings.Split(opt, ",")
+		for _, s := range split {
+			kv := strings.SplitN(s, "=", 2)
+			if len(kv) != 2 {
+				return nil, fmt.Errorf("invalid security option %q", s)
+			}
+			if kv[0] == "" || kv[1] == "" {
+				return nil, errors.New("invalid empty security option")
+			}
+			if kv[0] == "name" {
+				secopt.Name = kv[1]
+				continue
+			}
+			secopt.Options = append(secopt.Options, KeyValue{Key: kv[0], Value: kv[1]})
+		}
+		so = append(so, secopt)
+	}
+	return so, nil
 }
 
 // PluginsInfo is a temp struct holding Plugins name

+ 0 - 11
api/types/versions/v1p24/types.go

@@ -1,11 +0,0 @@
-// Package v1p24 provides specific API types for the API version 1, patch 24.
-package v1p24
-
-import "github.com/docker/docker/api/types"
-
-// Info is a backcompatibility struct for the API 1.24
-type Info struct {
-	*types.InfoBase
-	ExecutionDriver string
-	SecurityOptions []string
-}

+ 13 - 8
cli/command/system/info.go

@@ -172,16 +172,21 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
 			fmt.Fprintf(dockerCli.Out(), "\n")
 		}
 		if len(info.SecurityOptions) != 0 {
+			kvs, err := types.DecodeSecurityOptions(info.SecurityOptions)
+			if err != nil {
+				return err
+			}
 			fmt.Fprintf(dockerCli.Out(), "Security Options:\n")
-			for _, o := range info.SecurityOptions {
-				switch o.Key {
-				case "Name":
-					fmt.Fprintf(dockerCli.Out(), " %s\n", o.Value)
-				case "Profile":
-					if o.Value != "default" {
-						fmt.Fprintf(dockerCli.Err(), "  WARNING: You're not using the default seccomp profile\n")
+			for _, so := range kvs {
+				fmt.Fprintf(dockerCli.Out(), " %s\n", so.Name)
+				for _, o := range so.Options {
+					switch o.Key {
+					case "profile":
+						if o.Value != "default" {
+							fmt.Fprintf(dockerCli.Err(), "  WARNING: You're not using the default seccomp profile\n")
+						}
+						fmt.Fprintf(dockerCli.Out(), "  Profile: %s\n", o.Value)
 					}
-					fmt.Fprintf(dockerCli.Out(), "  %s: %s\n", o.Key, o.Value)
 				}
 			}
 		}

+ 2 - 4
client/info_test.go

@@ -46,10 +46,8 @@ func TestInfo(t *testing.T) {
 				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
 			}
 			info := &types.Info{
-				InfoBase: &types.InfoBase{
-					ID:         "daemonID",
-					Containers: 3,
-				},
+				ID:         "daemonID",
+				Containers: 3,
 			}
 			b, err := json.Marshal(info)
 			if err != nil {

+ 9 - 15
daemon/info.go

@@ -1,6 +1,7 @@
 package daemon
 
 import (
+	"fmt"
 	"os"
 	"runtime"
 	"sync/atomic"
@@ -69,29 +70,26 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
 		}
 	})
 
-	securityOptions := []types.SecurityOpt{}
+	securityOptions := []string{}
 	if sysInfo.AppArmor {
-		securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "apparmor"})
+		securityOptions = append(securityOptions, "name=apparmor")
 	}
 	if sysInfo.Seccomp && supportsSeccomp {
 		profile := daemon.seccompProfilePath
 		if profile == "" {
 			profile = "default"
 		}
-		securityOptions = append(securityOptions,
-			types.SecurityOpt{Key: "Name", Value: "seccomp"},
-			types.SecurityOpt{Key: "Profile", Value: profile},
-		)
+		securityOptions = append(securityOptions, fmt.Sprintf("name=seccomp,profile=%s", profile))
 	}
 	if selinuxEnabled() {
-		securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "selinux"})
+		securityOptions = append(securityOptions, "name=selinux")
 	}
 	uid, gid := daemon.GetRemappedUIDGID()
 	if uid != 0 || gid != 0 {
-		securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "userns"})
+		securityOptions = append(securityOptions, "name=userns")
 	}
 
-	v := &types.InfoBase{
+	v := &types.Info{
 		ID:                 daemon.ID,
 		Containers:         int(cRunning + cPaused + cStopped),
 		ContainersRunning:  int(cRunning),
@@ -129,6 +127,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
 		HTTPSProxy:         sockets.GetProxyEnv("https_proxy"),
 		NoProxy:            sockets.GetProxyEnv("no_proxy"),
 		LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
+		SecurityOptions:    securityOptions,
 		Isolation:          daemon.defaultIsolation,
 	}
 
@@ -143,12 +142,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
 	}
 	v.Name = hostname
 
-	i := &types.Info{
-		InfoBase:        v,
-		SecurityOptions: securityOptions,
-	}
-
-	return i, nil
+	return v, nil
 }
 
 // SystemVersion returns version information about the daemon.

+ 1 - 1
daemon/info_unix.go

@@ -14,7 +14,7 @@ import (
 )
 
 // FillPlatformInfo fills the platform related info.
-func (daemon *Daemon) FillPlatformInfo(v *types.InfoBase, sysInfo *sysinfo.SysInfo) {
+func (daemon *Daemon) FillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
 	v.MemoryLimit = sysInfo.MemoryLimit
 	v.SwapLimit = sysInfo.SwapLimit
 	v.KernelMemory = sysInfo.KernelMemory

+ 1 - 1
daemon/info_windows.go

@@ -6,5 +6,5 @@ import (
 )
 
 // FillPlatformInfo fills the platform related info.
-func (daemon *Daemon) FillPlatformInfo(v *types.InfoBase, sysInfo *sysinfo.SysInfo) {
+func (daemon *Daemon) FillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
 }