Add support for --cap-add and --cap-drop
| ... | ... |
@@ -254,6 +254,8 @@ func populateCommand(c *Container, env []string) error {
|
| 254 | 254 |
Resources: resources, |
| 255 | 255 |
AllowedDevices: allowedDevices, |
| 256 | 256 |
AutoCreatedDevices: autoCreatedDevices, |
| 257 |
+ CapAdd: c.hostConfig.CapAdd, |
|
| 258 |
+ CapDrop: c.hostConfig.CapDrop, |
|
| 257 | 259 |
} |
| 258 | 260 |
c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
| 259 | 261 |
c.command.Env = env |
| ... | ... |
@@ -60,6 +60,8 @@ type InitArgs struct {
|
| 60 | 60 |
Console string |
| 61 | 61 |
Pipe int |
| 62 | 62 |
Root string |
| 63 |
+ CapAdd string |
|
| 64 |
+ CapDrop string |
|
| 63 | 65 |
} |
| 64 | 66 |
|
| 65 | 67 |
// Driver specific information based on |
| ... | ... |
@@ -140,6 +142,8 @@ type Command struct {
|
| 140 | 140 |
Mounts []Mount `json:"mounts"` |
| 141 | 141 |
AllowedDevices []*devices.Device `json:"allowed_devices"` |
| 142 | 142 |
AutoCreatedDevices []*devices.Device `json:"autocreated_devices"` |
| 143 |
+ CapAdd []string `json:"cap_add"` |
|
| 144 |
+ CapDrop []string `json:"cap_drop"` |
|
| 143 | 145 |
|
| 144 | 146 |
Terminal Terminal `json:"-"` // standard or tty terminal |
| 145 | 147 |
Console string `json:"-"` // dev/console path |
| ... | ... |
@@ -122,6 +122,14 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 122 | 122 |
params = append(params, "-w", c.WorkingDir) |
| 123 | 123 |
} |
| 124 | 124 |
|
| 125 |
+ if len(c.CapAdd) > 0 {
|
|
| 126 |
+ params = append(params, "-cap-add", strings.Join(c.CapAdd, " ")) |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ if len(c.CapDrop) > 0 {
|
|
| 130 |
+ params = append(params, "-cap-drop", strings.Join(c.CapDrop, " ")) |
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 125 | 133 |
params = append(params, "--", c.Entrypoint) |
| 126 | 134 |
params = append(params, c.Arguments...) |
| 127 | 135 |
|
| ... | ... |
@@ -4,6 +4,7 @@ package lxc |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 | 6 |
"fmt" |
| 7 |
+ "strings" |
|
| 7 | 8 |
"syscall" |
| 8 | 9 |
|
| 9 | 10 |
"github.com/docker/libcontainer/namespaces" |
| ... | ... |
@@ -48,8 +49,13 @@ func finalizeNamespace(args *execdriver.InitArgs) error {
|
| 48 | 48 |
return fmt.Errorf("clear keep caps %s", err)
|
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 |
+ caps, err := execdriver.TweakCapabilities(container.Capabilities, strings.Split(args.CapAdd, " "), strings.Split(args.CapDrop, " ")) |
|
| 52 |
+ if err != nil {
|
|
| 53 |
+ return err |
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 51 | 56 |
// drop all other capabilities |
| 52 |
- if err := capabilities.DropCapabilities(container.Capabilities); err != nil {
|
|
| 57 |
+ if err := capabilities.DropCapabilities(caps); err != nil {
|
|
| 53 | 58 |
return fmt.Errorf("drop capabilities %s", err)
|
| 54 | 59 |
} |
| 55 | 60 |
} |
| ... | ... |
@@ -42,6 +42,10 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e |
| 42 | 42 |
if err := d.setPrivileged(container); err != nil {
|
| 43 | 43 |
return nil, err |
| 44 | 44 |
} |
| 45 |
+ } else {
|
|
| 46 |
+ if err := d.setCapabilities(container, c); err != nil {
|
|
| 47 |
+ return nil, err |
|
| 48 |
+ } |
|
| 45 | 49 |
} |
| 46 | 50 |
|
| 47 | 51 |
if err := d.setupCgroups(container, c); err != nil {
|
| ... | ... |
@@ -136,6 +140,11 @@ func (d *driver) setPrivileged(container *libcontainer.Config) (err error) {
|
| 136 | 136 |
return nil |
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 |
+func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) (err error) {
|
|
| 140 |
+ container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) |
|
| 141 |
+ return err |
|
| 142 |
+} |
|
| 143 |
+ |
|
| 139 | 144 |
func (d *driver) setupCgroups(container *libcontainer.Config, c *execdriver.Command) error {
|
| 140 | 145 |
if c.Resources != nil {
|
| 141 | 146 |
container.Cgroups.CpuShares = c.Resources.CpuShares |
| 142 | 147 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,63 @@ |
| 0 |
+package execdriver |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/libcontainer/security/capabilities" |
|
| 7 |
+ "github.com/dotcloud/docker/utils" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
|
|
| 11 |
+ var ( |
|
| 12 |
+ newCaps []string |
|
| 13 |
+ allCaps = capabilities.GetAllCapabilities() |
|
| 14 |
+ ) |
|
| 15 |
+ |
|
| 16 |
+ // look for invalid cap in the drop list |
|
| 17 |
+ for _, cap := range drops {
|
|
| 18 |
+ if strings.ToLower(cap) == "all" {
|
|
| 19 |
+ continue |
|
| 20 |
+ } |
|
| 21 |
+ if !utils.StringsContainsNoCase(allCaps, cap) {
|
|
| 22 |
+ return nil, fmt.Errorf("Unknown capability: %s", cap)
|
|
| 23 |
+ } |
|
| 24 |
+ } |
|
| 25 |
+ |
|
| 26 |
+ // handle --cap-add=all |
|
| 27 |
+ if utils.StringsContainsNoCase(adds, "all") {
|
|
| 28 |
+ basics = capabilities.GetAllCapabilities() |
|
| 29 |
+ } |
|
| 30 |
+ |
|
| 31 |
+ if !utils.StringsContainsNoCase(drops, "all") {
|
|
| 32 |
+ for _, cap := range basics {
|
|
| 33 |
+ // skip `all` aready handled above |
|
| 34 |
+ if strings.ToLower(cap) == "all" {
|
|
| 35 |
+ continue |
|
| 36 |
+ } |
|
| 37 |
+ |
|
| 38 |
+ // if we don't drop `all`, add back all the non-dropped caps |
|
| 39 |
+ if !utils.StringsContainsNoCase(drops, cap) {
|
|
| 40 |
+ newCaps = append(newCaps, cap) |
|
| 41 |
+ } |
|
| 42 |
+ } |
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ for _, cap := range adds {
|
|
| 46 |
+ // skip `all` aready handled above |
|
| 47 |
+ if strings.ToLower(cap) == "all" {
|
|
| 48 |
+ continue |
|
| 49 |
+ } |
|
| 50 |
+ |
|
| 51 |
+ // look for invalid cap in the drop list |
|
| 52 |
+ if !utils.StringsContainsNoCase(allCaps, cap) {
|
|
| 53 |
+ return nil, fmt.Errorf("Unknown capability: %s", cap)
|
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 56 |
+ // add cap if not already in the list |
|
| 57 |
+ if !utils.StringsContainsNoCase(newCaps, cap) {
|
|
| 58 |
+ newCaps = append(newCaps, cap) |
|
| 59 |
+ } |
|
| 60 |
+ } |
|
| 61 |
+ return newCaps, nil |
|
| 62 |
+} |
| ... | ... |
@@ -43,6 +43,12 @@ You can now use the `stop` parameter to stop running containers before removal |
| 43 | 43 |
**New!** |
| 44 | 44 |
You can now use the `kill` parameter to kill running containers before removal. |
| 45 | 45 |
|
| 46 |
+`POST /containers/(id)/start` |
|
| 47 |
+ |
|
| 48 |
+**New!** |
|
| 49 |
+The `hostConfig` option now accepts the field `CapAdd`, which specifies a list of capabilities |
|
| 50 |
+to add, and the field `CapDrop`, which specifies a list of capabilities to drop. |
|
| 51 |
+ |
|
| 46 | 52 |
## v1.13 |
| 47 | 53 |
|
| 48 | 54 |
### Full Documentation |
| ... | ... |
@@ -241,7 +241,9 @@ Return low-level information on the container `id` |
| 241 | 241 |
] |
| 242 | 242 |
}, |
| 243 | 243 |
"Links": ["/name:alias"], |
| 244 |
- "PublishAllPorts": false |
|
| 244 |
+ "PublishAllPorts": false, |
|
| 245 |
+ "CapAdd: ["NET_ADMIN"], |
|
| 246 |
+ "CapDrop: ["MKNOD"] |
|
| 245 | 247 |
} |
| 246 | 248 |
} |
| 247 | 249 |
|
| ... | ... |
@@ -410,7 +412,9 @@ Start the container `id` |
| 410 | 410 |
"PublishAllPorts":false, |
| 411 | 411 |
"Privileged":false, |
| 412 | 412 |
"Dns": ["8.8.8.8"], |
| 413 |
- "VolumesFrom": ["parent", "other:ro"] |
|
| 413 |
+ "VolumesFrom": ["parent", "other:ro"], |
|
| 414 |
+ "CapAdd: ["NET_ADMIN"], |
|
| 415 |
+ "CapDrop: ["MKNOD"] |
|
| 414 | 416 |
} |
| 415 | 417 |
|
| 416 | 418 |
**Example response**: |
| ... | ... |
@@ -55,7 +55,7 @@ following options. |
| 55 | 55 |
- [Network Settings](#network-settings) |
| 56 | 56 |
- [Clean Up (--rm)](#clean-up-rm) |
| 57 | 57 |
- [Runtime Constraints on CPU and Memory](#runtime-constraints-on-cpu-and-memory) |
| 58 |
- - [Runtime Privilege and LXC Configuration](#runtime-privilege-and-lxc-configuration) |
|
| 58 |
+ - [Runtime Privilege, Linux Capabilities, and LXC Configuration](#runtime-privilege-linux-capabilities-and-lxc-configuration) |
|
| 59 | 59 |
|
| 60 | 60 |
## Detached vs Foreground |
| 61 | 61 |
|
| ... | ... |
@@ -222,8 +222,10 @@ get the same proportion of CPU cycles, but you can tell the kernel to |
| 222 | 222 |
give more shares of CPU time to one or more containers when you start |
| 223 | 223 |
them via Docker. |
| 224 | 224 |
|
| 225 |
-## Runtime Privilege and LXC Configuration |
|
| 225 |
+## Runtime Privilege, Linux Capabilities, and LXC Configuration |
|
| 226 | 226 |
|
| 227 |
+ --cap-add: Add Linux capabilities |
|
| 228 |
+ --cap-drop: Drop Linux capabilities |
|
| 227 | 229 |
--privileged=false: Give extended privileges to this container |
| 228 | 230 |
--lxc-conf=[]: (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" |
| 229 | 231 |
|
| ... | ... |
@@ -242,6 +244,16 @@ host as processes running outside containers on the host. Additional |
| 242 | 242 |
information about running with `--privileged` is available on the |
| 243 | 243 |
[Docker Blog](http://blog.docker.com/2013/09/docker-can-now-run-within-docker/). |
| 244 | 244 |
|
| 245 |
+In addition to `--privileged`, the operator can have fine grain control over the |
|
| 246 |
+capabilities using `--cap-add` and `--cap-drop`. By default, Docker has a default |
|
| 247 |
+list of capabilities that are kept. Both flags support the value `all`, so if the |
|
| 248 |
+operator wants to have all capabilities but `MKNOD` they could use: |
|
| 249 |
+ |
|
| 250 |
+ $ docker run --cap-add=ALL --cap-drop=MKNOD ... |
|
| 251 |
+ |
|
| 252 |
+For interacting with the network stack, instead of using `--privileged` they |
|
| 253 |
+should use `--cap-add=NET_ADMIN` to modify the network interfaces. |
|
| 254 |
+ |
|
| 245 | 255 |
If the Docker daemon was started using the `lxc` exec-driver |
| 246 | 256 |
(`docker -d --exec-driver=lxc`) then the operator can also specify LXC options |
| 247 | 257 |
using one or more `--lxc-conf` parameters. These can be new parameters or |
| ... | ... |
@@ -783,6 +783,116 @@ func TestUnPrivilegedCanMknod(t *testing.T) {
|
| 783 | 783 |
logDone("run - test un-privileged can mknod")
|
| 784 | 784 |
} |
| 785 | 785 |
|
| 786 |
+func TestCapDropInvalid(t *testing.T) {
|
|
| 787 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-drop=CHPASS", "busybox", "ls") |
|
| 788 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 789 |
+ if err == nil {
|
|
| 790 |
+ t.Fatal(err, out) |
|
| 791 |
+ } |
|
| 792 |
+ |
|
| 793 |
+ logDone("run - test --cap-drop=CHPASS invalid")
|
|
| 794 |
+} |
|
| 795 |
+ |
|
| 796 |
+func TestCapDropCannotMknod(t *testing.T) {
|
|
| 797 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") |
|
| 798 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 799 |
+ if err == nil {
|
|
| 800 |
+ t.Fatal(err, out) |
|
| 801 |
+ } |
|
| 802 |
+ |
|
| 803 |
+ if actual := strings.Trim(out, "\r\n"); actual == "ok" {
|
|
| 804 |
+ t.Fatalf("expected output not ok received %s", actual)
|
|
| 805 |
+ } |
|
| 806 |
+ deleteAllContainers() |
|
| 807 |
+ |
|
| 808 |
+ logDone("run - test --cap-drop=MKNOD cannot mknod")
|
|
| 809 |
+} |
|
| 810 |
+ |
|
| 811 |
+func TestCapDropALLCannotMknod(t *testing.T) {
|
|
| 812 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") |
|
| 813 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 814 |
+ if err == nil {
|
|
| 815 |
+ t.Fatal(err, out) |
|
| 816 |
+ } |
|
| 817 |
+ |
|
| 818 |
+ if actual := strings.Trim(out, "\r\n"); actual == "ok" {
|
|
| 819 |
+ t.Fatalf("expected output not ok received %s", actual)
|
|
| 820 |
+ } |
|
| 821 |
+ deleteAllContainers() |
|
| 822 |
+ |
|
| 823 |
+ logDone("run - test --cap-drop=ALL cannot mknod")
|
|
| 824 |
+} |
|
| 825 |
+ |
|
| 826 |
+func TestCapDropALLAddMknodCannotMknod(t *testing.T) {
|
|
| 827 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") |
|
| 828 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 829 |
+ if err != nil {
|
|
| 830 |
+ t.Fatal(err, out) |
|
| 831 |
+ } |
|
| 832 |
+ |
|
| 833 |
+ if actual := strings.Trim(out, "\r\n"); actual != "ok" {
|
|
| 834 |
+ t.Fatalf("expected output ok received %s", actual)
|
|
| 835 |
+ } |
|
| 836 |
+ deleteAllContainers() |
|
| 837 |
+ |
|
| 838 |
+ logDone("run - test --cap-drop=ALL --cap-add=MKNOD can mknod")
|
|
| 839 |
+} |
|
| 840 |
+ |
|
| 841 |
+func TestCapAddInvalid(t *testing.T) {
|
|
| 842 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-add=CHPASS", "busybox", "ls") |
|
| 843 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 844 |
+ if err == nil {
|
|
| 845 |
+ t.Fatal(err, out) |
|
| 846 |
+ } |
|
| 847 |
+ |
|
| 848 |
+ logDone("run - test --cap-add=CHPASS invalid")
|
|
| 849 |
+} |
|
| 850 |
+ |
|
| 851 |
+func TestCapAddCanDownInterface(t *testing.T) {
|
|
| 852 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") |
|
| 853 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 854 |
+ if err != nil {
|
|
| 855 |
+ t.Fatal(err, out) |
|
| 856 |
+ } |
|
| 857 |
+ |
|
| 858 |
+ if actual := strings.Trim(out, "\r\n"); actual != "ok" {
|
|
| 859 |
+ t.Fatalf("expected output ok received %s", actual)
|
|
| 860 |
+ } |
|
| 861 |
+ deleteAllContainers() |
|
| 862 |
+ |
|
| 863 |
+ logDone("run - test --cap-add=NET_ADMIN can set eth0 down")
|
|
| 864 |
+} |
|
| 865 |
+ |
|
| 866 |
+func TestCapAddALLCanDownInterface(t *testing.T) {
|
|
| 867 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") |
|
| 868 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 869 |
+ if err != nil {
|
|
| 870 |
+ t.Fatal(err, out) |
|
| 871 |
+ } |
|
| 872 |
+ |
|
| 873 |
+ if actual := strings.Trim(out, "\r\n"); actual != "ok" {
|
|
| 874 |
+ t.Fatalf("expected output ok received %s", actual)
|
|
| 875 |
+ } |
|
| 876 |
+ deleteAllContainers() |
|
| 877 |
+ |
|
| 878 |
+ logDone("run - test --cap-add=ALL can set eth0 down")
|
|
| 879 |
+} |
|
| 880 |
+ |
|
| 881 |
+func TestCapAddALLDropNetAdminCanDownInterface(t *testing.T) {
|
|
| 882 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") |
|
| 883 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 884 |
+ if err == nil {
|
|
| 885 |
+ t.Fatal(err, out) |
|
| 886 |
+ } |
|
| 887 |
+ |
|
| 888 |
+ if actual := strings.Trim(out, "\r\n"); actual == "ok" {
|
|
| 889 |
+ t.Fatalf("expected output not ok received %s", actual)
|
|
| 890 |
+ } |
|
| 891 |
+ deleteAllContainers() |
|
| 892 |
+ |
|
| 893 |
+ logDone("run - test --cap-add=ALL --cap-drop=NET_ADMIN cannot set eth0 down")
|
|
| 894 |
+} |
|
| 895 |
+ |
|
| 786 | 896 |
func TestPrivilegedCanMount(t *testing.T) {
|
| 787 | 897 |
cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok") |
| 788 | 898 |
|
| ... | ... |
@@ -38,6 +38,8 @@ type HostConfig struct {
|
| 38 | 38 |
VolumesFrom []string |
| 39 | 39 |
Devices []DeviceMapping |
| 40 | 40 |
NetworkMode NetworkMode |
| 41 |
+ CapAdd []string |
|
| 42 |
+ CapDrop []string |
|
| 41 | 43 |
} |
| 42 | 44 |
|
| 43 | 45 |
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| ... | ... |
@@ -65,5 +67,11 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| 65 | 65 |
if VolumesFrom := job.GetenvList("VolumesFrom"); VolumesFrom != nil {
|
| 66 | 66 |
hostConfig.VolumesFrom = VolumesFrom |
| 67 | 67 |
} |
| 68 |
+ if CapAdd := job.GetenvList("CapAdd"); CapAdd != nil {
|
|
| 69 |
+ hostConfig.CapAdd = CapAdd |
|
| 70 |
+ } |
|
| 71 |
+ if CapDrop := job.GetenvList("CapDrop"); CapDrop != nil {
|
|
| 72 |
+ hostConfig.CapDrop = CapDrop |
|
| 73 |
+ } |
|
| 68 | 74 |
return hostConfig |
| 69 | 75 |
} |
| ... | ... |
@@ -50,6 +50,8 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 50 | 50 |
flVolumesFrom opts.ListOpts |
| 51 | 51 |
flLxcOpts opts.ListOpts |
| 52 | 52 |
flEnvFile opts.ListOpts |
| 53 |
+ flCapAdd opts.ListOpts |
|
| 54 |
+ flCapDrop opts.ListOpts |
|
| 53 | 55 |
|
| 54 | 56 |
flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
|
| 55 | 57 |
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run container in the background and print new container ID")
|
| ... | ... |
@@ -86,6 +88,9 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 86 | 86 |
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
| 87 | 87 |
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "(lxc exec-driver only) Add custom lxc options --lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
|
| 88 | 88 |
|
| 89 |
+ cmd.Var(&flCapAdd, []string{"-cap-add"}, "Add Linux capabilities")
|
|
| 90 |
+ cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
|
|
| 91 |
+ |
|
| 89 | 92 |
if err := cmd.Parse(args); err != nil {
|
| 90 | 93 |
return nil, nil, cmd, err |
| 91 | 94 |
} |
| ... | ... |
@@ -258,6 +263,8 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 258 | 258 |
VolumesFrom: flVolumesFrom.GetAll(), |
| 259 | 259 |
NetworkMode: netMode, |
| 260 | 260 |
Devices: deviceMappings, |
| 261 |
+ CapAdd: flCapAdd.GetAll(), |
|
| 262 |
+ CapDrop: flCapDrop.GetAll(), |
|
| 261 | 263 |
} |
| 262 | 264 |
|
| 263 | 265 |
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
|
| ... | ... |
@@ -3,11 +3,12 @@ package sysinit |
| 3 | 3 |
import ( |
| 4 | 4 |
"flag" |
| 5 | 5 |
"fmt" |
| 6 |
+ "log" |
|
| 7 |
+ "os" |
|
| 8 |
+ |
|
| 6 | 9 |
"github.com/dotcloud/docker/daemon/execdriver" |
| 7 | 10 |
_ "github.com/dotcloud/docker/daemon/execdriver/lxc" |
| 8 | 11 |
_ "github.com/dotcloud/docker/daemon/execdriver/native" |
| 9 |
- "log" |
|
| 10 |
- "os" |
|
| 11 | 12 |
) |
| 12 | 13 |
|
| 13 | 14 |
func executeProgram(args *execdriver.InitArgs) error {
|
| ... | ... |
@@ -39,6 +40,8 @@ func SysInit() {
|
| 39 | 39 |
pipe = flag.Int("pipe", 0, "sync pipe fd")
|
| 40 | 40 |
console = flag.String("console", "", "console (pty slave) path")
|
| 41 | 41 |
root = flag.String("root", ".", "root path for configuration files")
|
| 42 |
+ capAdd = flag.String("cap-add", "", "capabilities to add")
|
|
| 43 |
+ capDrop = flag.String("cap-drop", "", "capabilities to drop")
|
|
| 42 | 44 |
) |
| 43 | 45 |
flag.Parse() |
| 44 | 46 |
|
| ... | ... |
@@ -54,6 +57,8 @@ func SysInit() {
|
| 54 | 54 |
Console: *console, |
| 55 | 55 |
Pipe: *pipe, |
| 56 | 56 |
Root: *root, |
| 57 |
+ CapAdd: *capAdd, |
|
| 58 |
+ CapDrop: *capDrop, |
|
| 57 | 59 |
} |
| 58 | 60 |
|
| 59 | 61 |
if err := executeProgram(args); err != nil {
|
| ... | ... |
@@ -907,3 +907,12 @@ func ValidateContextDirectory(srcPath string) error {
|
| 907 | 907 |
}) |
| 908 | 908 |
return finalError |
| 909 | 909 |
} |
| 910 |
+ |
|
| 911 |
+func StringsContainsNoCase(slice []string, s string) bool {
|
|
| 912 |
+ for _, ss := range slice {
|
|
| 913 |
+ if strings.ToLower(s) == strings.ToLower(ss) {
|
|
| 914 |
+ return true |
|
| 915 |
+ } |
|
| 916 |
+ } |
|
| 917 |
+ return false |
|
| 918 |
+} |