api: types: keep info.SecurityOptions a string slice
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
(cherry picked from commit 514ca09426
)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
This commit is contained in:
parent
2737519f9a
commit
0a5732d1cf
8 changed files with 84 additions and 57 deletions
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
timetypes "github.com/docker/docker/api/types/time"
|
timetypes "github.com/docker/docker/api/types/time"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/docker/api/types/versions/v1p24"
|
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"golang.org/x/net/context"
|
"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") {
|
if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") {
|
||||||
// TODO: handle this conversion in engine-api
|
// TODO: handle this conversion in engine-api
|
||||||
oldInfo := &v1p24.Info{
|
type oldInfo struct {
|
||||||
InfoBase: info.InfoBase,
|
*types.Info
|
||||||
|
ExecutionDriver string
|
||||||
|
}
|
||||||
|
old := &oldInfo{
|
||||||
|
Info: info,
|
||||||
ExecutionDriver: "<not supported>",
|
ExecutionDriver: "<not supported>",
|
||||||
}
|
}
|
||||||
for _, s := range info.SecurityOptions {
|
nameOnlySecurityOptions := []string{}
|
||||||
if s.Key == "Name" {
|
kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions)
|
||||||
oldInfo.SecurityOptions = append(oldInfo.SecurityOptions, s.Value)
|
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)
|
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
@ -158,9 +161,9 @@ type Commit struct {
|
||||||
Expected string
|
Expected string
|
||||||
}
|
}
|
||||||
|
|
||||||
// InfoBase contains the base response of Remote API:
|
// Info contains response of Remote API:
|
||||||
// GET "/info"
|
// GET "/info"
|
||||||
type InfoBase struct {
|
type Info struct {
|
||||||
ID string
|
ID string
|
||||||
Containers int
|
Containers int
|
||||||
ContainersRunning int
|
ContainersRunning int
|
||||||
|
@ -219,18 +222,49 @@ type InfoBase struct {
|
||||||
ContainerdCommit Commit
|
ContainerdCommit Commit
|
||||||
RuncCommit Commit
|
RuncCommit Commit
|
||||||
InitCommit Commit
|
InitCommit Commit
|
||||||
|
SecurityOptions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecurityOpt holds key/value pair about a security option
|
// KeyValue holds a key/value pair
|
||||||
type SecurityOpt struct {
|
type KeyValue struct {
|
||||||
Key, Value string
|
Key, Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info contains response of Remote API:
|
// SecurityOpt contains the name and options of a security option
|
||||||
// GET "/info"
|
type SecurityOpt struct {
|
||||||
type Info struct {
|
Name string
|
||||||
*InfoBase
|
Options []KeyValue
|
||||||
SecurityOptions []SecurityOpt
|
}
|
||||||
|
|
||||||
|
// 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
|
// PluginsInfo is a temp struct holding Plugins name
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -172,16 +172,21 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
|
||||||
fmt.Fprintf(dockerCli.Out(), "\n")
|
fmt.Fprintf(dockerCli.Out(), "\n")
|
||||||
}
|
}
|
||||||
if len(info.SecurityOptions) != 0 {
|
if len(info.SecurityOptions) != 0 {
|
||||||
|
kvs, err := types.DecodeSecurityOptions(info.SecurityOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
fmt.Fprintf(dockerCli.Out(), "Security Options:\n")
|
fmt.Fprintf(dockerCli.Out(), "Security Options:\n")
|
||||||
for _, o := range info.SecurityOptions {
|
for _, so := range kvs {
|
||||||
switch o.Key {
|
fmt.Fprintf(dockerCli.Out(), " %s\n", so.Name)
|
||||||
case "Name":
|
for _, o := range so.Options {
|
||||||
fmt.Fprintf(dockerCli.Out(), " %s\n", o.Value)
|
switch o.Key {
|
||||||
case "Profile":
|
case "profile":
|
||||||
if o.Value != "default" {
|
if o.Value != "default" {
|
||||||
fmt.Fprintf(dockerCli.Err(), " WARNING: You're not using the default seccomp profile\n")
|
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,10 +46,8 @@ func TestInfo(t *testing.T) {
|
||||||
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
|
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
|
||||||
}
|
}
|
||||||
info := &types.Info{
|
info := &types.Info{
|
||||||
InfoBase: &types.InfoBase{
|
ID: "daemonID",
|
||||||
ID: "daemonID",
|
Containers: 3,
|
||||||
Containers: 3,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(info)
|
b, err := json.Marshal(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -69,29 +70,26 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
securityOptions := []types.SecurityOpt{}
|
securityOptions := []string{}
|
||||||
if sysInfo.AppArmor {
|
if sysInfo.AppArmor {
|
||||||
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "apparmor"})
|
securityOptions = append(securityOptions, "name=apparmor")
|
||||||
}
|
}
|
||||||
if sysInfo.Seccomp && supportsSeccomp {
|
if sysInfo.Seccomp && supportsSeccomp {
|
||||||
profile := daemon.seccompProfilePath
|
profile := daemon.seccompProfilePath
|
||||||
if profile == "" {
|
if profile == "" {
|
||||||
profile = "default"
|
profile = "default"
|
||||||
}
|
}
|
||||||
securityOptions = append(securityOptions,
|
securityOptions = append(securityOptions, fmt.Sprintf("name=seccomp,profile=%s", profile))
|
||||||
types.SecurityOpt{Key: "Name", Value: "seccomp"},
|
|
||||||
types.SecurityOpt{Key: "Profile", Value: profile},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if selinuxEnabled() {
|
if selinuxEnabled() {
|
||||||
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "selinux"})
|
securityOptions = append(securityOptions, "name=selinux")
|
||||||
}
|
}
|
||||||
uid, gid := daemon.GetRemappedUIDGID()
|
uid, gid := daemon.GetRemappedUIDGID()
|
||||||
if uid != 0 || gid != 0 {
|
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,
|
ID: daemon.ID,
|
||||||
Containers: int(cRunning + cPaused + cStopped),
|
Containers: int(cRunning + cPaused + cStopped),
|
||||||
ContainersRunning: int(cRunning),
|
ContainersRunning: int(cRunning),
|
||||||
|
@ -129,6 +127,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
||||||
HTTPSProxy: sockets.GetProxyEnv("https_proxy"),
|
HTTPSProxy: sockets.GetProxyEnv("https_proxy"),
|
||||||
NoProxy: sockets.GetProxyEnv("no_proxy"),
|
NoProxy: sockets.GetProxyEnv("no_proxy"),
|
||||||
LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
|
LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
|
||||||
|
SecurityOptions: securityOptions,
|
||||||
Isolation: daemon.defaultIsolation,
|
Isolation: daemon.defaultIsolation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,12 +142,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
||||||
}
|
}
|
||||||
v.Name = hostname
|
v.Name = hostname
|
||||||
|
|
||||||
i := &types.Info{
|
return v, nil
|
||||||
InfoBase: v,
|
|
||||||
SecurityOptions: securityOptions,
|
|
||||||
}
|
|
||||||
|
|
||||||
return i, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemVersion returns version information about the daemon.
|
// SystemVersion returns version information about the daemon.
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// FillPlatformInfo fills the platform related info.
|
// 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.MemoryLimit = sysInfo.MemoryLimit
|
||||||
v.SwapLimit = sysInfo.SwapLimit
|
v.SwapLimit = sysInfo.SwapLimit
|
||||||
v.KernelMemory = sysInfo.KernelMemory
|
v.KernelMemory = sysInfo.KernelMemory
|
||||||
|
|
|
@ -6,5 +6,5 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// FillPlatformInfo fills the platform related info.
|
// 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) {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue