diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go index 3fc02281fa..0d851b684a 100644 --- a/api/server/router/system/system_routes.go +++ b/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: "", } - 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 } - return httputils.WriteJSON(w, http.StatusOK, oldInfo) + for _, s := range kvSecOpts { + nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name) + } + old.SecurityOptions = nameOnlySecurityOptions + return httputils.WriteJSON(w, http.StatusOK, old) } return httputils.WriteJSON(w, http.StatusOK, info) } diff --git a/api/types/types.go b/api/types/types.go index 41a902cbee..de0392a9d1 100644 --- a/api/types/types.go +++ b/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 diff --git a/api/types/versions/v1p24/types.go b/api/types/versions/v1p24/types.go deleted file mode 100644 index 470711335b..0000000000 --- a/api/types/versions/v1p24/types.go +++ /dev/null @@ -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 -} diff --git a/cli/command/system/info.go b/cli/command/system/info.go index b751bbff13..e0b8767377 100644 --- a/cli/command/system/info.go +++ b/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) } } } diff --git a/client/info_test.go b/client/info_test.go index 7af82a8a31..79f23c8af2 100644 --- a/client/info_test.go +++ b/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 { diff --git a/daemon/info.go b/daemon/info.go index 1758fafdc6..1ab9f29592 100644 --- a/daemon/info.go +++ b/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. diff --git a/daemon/info_unix.go b/daemon/info_unix.go index 00e3414936..9c41c0e4cd 100644 --- a/daemon/info_unix.go +++ b/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 diff --git a/daemon/info_windows.go b/daemon/info_windows.go index 84305240ec..c700911eb0 100644 --- a/daemon/info_windows.go +++ b/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) { }