Fix regression in parsing capabilities list when a single string is given

Signed-off-by: Antonio Murdaca <runcom@linux.com>
This commit is contained in:
Antonio Murdaca 2015-07-01 19:59:18 +02:00
parent 53b897ce9c
commit 10a3061c5f
6 changed files with 116 additions and 10 deletions

View File

@ -297,8 +297,8 @@ func populateCommand(c *Container, env []string) error {
Resources: resources, Resources: resources,
AllowedDevices: allowedDevices, AllowedDevices: allowedDevices,
AutoCreatedDevices: autoCreatedDevices, AutoCreatedDevices: autoCreatedDevices,
CapAdd: c.hostConfig.CapAdd, CapAdd: c.hostConfig.CapAdd.Slice(),
CapDrop: c.hostConfig.CapDrop, CapDrop: c.hostConfig.CapDrop.Slice(),
ProcessConfig: processConfig, ProcessConfig: processConfig,
ProcessLabel: c.GetProcessLabel(), ProcessLabel: c.GetProcessLabel(),
MountLabel: c.GetMountLabel(), MountLabel: c.GetMountLabel(),

View File

@ -111,8 +111,8 @@ func populateCommand(c *Container, env []string) error {
Network: en, Network: en,
Pid: pid, Pid: pid,
Resources: resources, Resources: resources,
CapAdd: c.hostConfig.CapAdd, CapAdd: c.hostConfig.CapAdd.Slice(),
CapDrop: c.hostConfig.CapDrop, CapDrop: c.hostConfig.CapDrop.Slice(),
ProcessConfig: processConfig, ProcessConfig: processConfig,
ProcessLabel: c.GetProcessLabel(), ProcessLabel: c.GetProcessLabel(),
MountLabel: c.GetMountLabel(), MountLabel: c.GetMountLabel(),

View File

@ -1705,3 +1705,24 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *check.C) {
out, _ = dockerCmd(c, "start", "-a", "echotest2") out, _ = dockerCmd(c, "start", "-a", "echotest2")
c.Assert(strings.TrimSpace(out), check.Equals, "hello world") c.Assert(strings.TrimSpace(out), check.Equals, "hello world")
} }
// regression #14318
func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *check.C) {
config := struct {
Image string
CapAdd string
CapDrop string
}{"busybox", "NET_ADMIN", "SYS_ADMIN"}
status, _, err := sockRequest("POST", "/containers/create?name=capaddtest0", config)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusCreated)
config2 := struct {
Image string
CapAdd []string
CapDrop []string
}{"busybox", []string{"NET_ADMIN", "SYS_ADMIN"}, []string{"SETGID"}}
status, _, err = sockRequest("POST", "/containers/create?name=capaddtest1", config2)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusCreated)
}

View File

@ -173,6 +173,53 @@ func NewLxcConfig(values []KeyValuePair) *LxcConfig {
return &LxcConfig{values} return &LxcConfig{values}
} }
type CapList struct {
caps []string
}
func (c *CapList) MarshalJSON() ([]byte, error) {
if c == nil {
return []byte{}, nil
}
return json.Marshal(c.Slice())
}
func (c *CapList) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
return nil
}
var caps []string
if err := json.Unmarshal(b, &caps); err != nil {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
caps = append(caps, s)
}
c.caps = caps
return nil
}
func (c *CapList) Len() int {
if c == nil {
return 0
}
return len(c.caps)
}
func (c *CapList) Slice() []string {
if c == nil {
return nil
}
return c.caps
}
func NewCapList(caps []string) *CapList {
return &CapList{caps}
}
type HostConfig struct { type HostConfig struct {
Binds []string Binds []string
ContainerIDFile string ContainerIDFile string
@ -199,8 +246,8 @@ type HostConfig struct {
IpcMode IpcMode IpcMode IpcMode
PidMode PidMode PidMode PidMode
UTSMode UTSMode UTSMode UTSMode
CapAdd []string CapAdd *CapList
CapDrop []string CapDrop *CapList
RestartPolicy RestartPolicy RestartPolicy RestartPolicy
SecurityOpt []string SecurityOpt []string
ReadonlyRootfs bool ReadonlyRootfs bool

View File

@ -2,6 +2,7 @@ package runconfig
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"testing" "testing"
@ -254,12 +255,49 @@ func TestDecodeHostConfig(t *testing.T) {
t.Fatalf("Expected 1 bind, found %v\n", c.Binds) t.Fatalf("Expected 1 bind, found %v\n", c.Binds)
} }
if len(c.CapAdd) != 1 && c.CapAdd[0] != "NET_ADMIN" { if c.CapAdd.Len() != 1 && c.CapAdd.Slice()[0] != "NET_ADMIN" {
t.Fatalf("Expected CapAdd NET_ADMIN, got %v", c.CapAdd) t.Fatalf("Expected CapAdd NET_ADMIN, got %v", c.CapAdd)
} }
if len(c.CapDrop) != 1 && c.CapDrop[0] != "NET_ADMIN" { if c.CapDrop.Len() != 1 && c.CapDrop.Slice()[0] != "NET_ADMIN" {
t.Fatalf("Expected CapDrop MKNOD, got %v", c.CapDrop) t.Fatalf("Expected CapDrop MKNOD, got %v", c.CapDrop)
} }
} }
} }
func TestCapListUnmarshalSliceAndString(t *testing.T) {
var cl *CapList
cap0, err := json.Marshal([]string{"CAP_SOMETHING"})
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(cap0, &cl); err != nil {
t.Fatal(err)
}
slice := cl.Slice()
if len(slice) != 1 {
t.Fatalf("expected 1 element after unmarshal: %q", slice)
}
if slice[0] != "CAP_SOMETHING" {
t.Fatalf("expected `CAP_SOMETHING`, got: %q", slice[0])
}
cap1, err := json.Marshal("CAP_SOMETHING")
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(cap1, &cl); err != nil {
t.Fatal(err)
}
slice = cl.Slice()
if len(slice) != 1 {
t.Fatalf("expected 1 element after unmarshal: %q", slice)
}
if slice[0] != "CAP_SOMETHING" {
t.Fatalf("expected `CAP_SOMETHING`, got: %q", slice[0])
}
}

View File

@ -353,8 +353,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
PidMode: pidMode, PidMode: pidMode,
UTSMode: utsMode, UTSMode: utsMode,
Devices: deviceMappings, Devices: deviceMappings,
CapAdd: flCapAdd.GetAll(), CapAdd: NewCapList(flCapAdd.GetAll()),
CapDrop: flCapDrop.GetAll(), CapDrop: NewCapList(flCapDrop.GetAll()),
RestartPolicy: restartPolicy, RestartPolicy: restartPolicy,
SecurityOpt: flSecurityOpt.GetAll(), SecurityOpt: flSecurityOpt.GetAll(),
ReadonlyRootfs: *flReadonlyRootfs, ReadonlyRootfs: *flReadonlyRootfs,