mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
4c43566925
docker will run the process(es) within the container with an SELinux label and will label all of the content within the container with mount label. Any temporary file systems created within the container need to be mounted with the same mount label. The user can override the process label by specifying -Z With a string of space separated options. -Z "user=unconfined_u role=unconfined_r type=unconfined_t level=s0" Would cause the process label to run with unconfined_u:unconfined_r:unconfined_t:s0" By default the processes will run execute within the container as svirt_lxc_net_t. All of the content in the container as svirt_sandbox_file_t. The process mcs level is based of the PID of the docker process that is creating the container. If you run the container in --priv mode, the labeling will be disabled. Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)
269 lines
9.4 KiB
Go
269 lines
9.4 KiB
Go
package runconfig
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/dotcloud/docker/nat"
|
|
"github.com/dotcloud/docker/opts"
|
|
"github.com/dotcloud/docker/pkg/label"
|
|
flag "github.com/dotcloud/docker/pkg/mflag"
|
|
"github.com/dotcloud/docker/pkg/sysinfo"
|
|
"github.com/dotcloud/docker/runtime/execdriver"
|
|
"github.com/dotcloud/docker/utils"
|
|
"io/ioutil"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
ErrInvalidWorikingDirectory = fmt.Errorf("The working directory is invalid. It needs to be an absolute path.")
|
|
ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
|
|
ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: --rm and -d")
|
|
)
|
|
|
|
//FIXME Only used in tests
|
|
func Parse(args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
|
cmd := flag.NewFlagSet("run", flag.ContinueOnError)
|
|
cmd.SetOutput(ioutil.Discard)
|
|
cmd.Usage = nil
|
|
return parseRun(cmd, args, sysInfo)
|
|
}
|
|
|
|
// FIXME: this maps the legacy commands.go code. It should be merged with Parse to only expose a single parse function.
|
|
func ParseSubcommand(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
|
return parseRun(cmd, args, sysInfo)
|
|
}
|
|
|
|
func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
|
var (
|
|
processLabel string
|
|
mountLabel string
|
|
)
|
|
var (
|
|
// FIXME: use utils.ListOpts for attach and volumes?
|
|
flAttach = opts.NewListOpts(opts.ValidateAttach)
|
|
flVolumes = opts.NewListOpts(opts.ValidatePath)
|
|
flLinks = opts.NewListOpts(opts.ValidateLink)
|
|
flEnv = opts.NewListOpts(opts.ValidateEnv)
|
|
|
|
flPublish opts.ListOpts
|
|
flExpose opts.ListOpts
|
|
flDns opts.ListOpts
|
|
flDnsSearch = opts.NewListOpts(opts.ValidateDomain)
|
|
flVolumesFrom opts.ListOpts
|
|
flLxcOpts opts.ListOpts
|
|
|
|
flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
|
|
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: Run container in the background, print new container id")
|
|
flNetwork = cmd.Bool([]string{"n", "-networking"}, true, "Enable networking for this container")
|
|
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
|
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to the host interfaces")
|
|
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep stdin open even if not attached")
|
|
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-tty")
|
|
flContainerIDFile = cmd.String([]string{"#cidfile", "-cidfile"}, "", "Write the container ID to the file")
|
|
flEntrypoint = cmd.String([]string{"#entrypoint", "-entrypoint"}, "", "Overwrite the default entrypoint of the image")
|
|
flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
|
|
flMemoryString = cmd.String([]string{"m", "-memory"}, "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
|
|
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID")
|
|
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
|
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
|
flLabelOptions = cmd.String([]string{"Z", "-label"}, "", "Options to pass to underlying labeling system")
|
|
|
|
// For documentation purpose
|
|
_ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
|
_ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
|
|
)
|
|
|
|
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to stdin, stdout or stderr.")
|
|
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
|
|
cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)")
|
|
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
|
|
|
cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat))
|
|
cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host")
|
|
cmd.Var(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers")
|
|
cmd.Var(&flDnsSearch, []string{"-dns-search"}, "Set custom dns search domains")
|
|
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
|
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "(lxc exec-driver only) Add custom lxc options --lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
|
|
|
|
if err := cmd.Parse(args); err != nil {
|
|
return nil, nil, cmd, err
|
|
}
|
|
|
|
// Check if the kernel supports memory limit cgroup.
|
|
if sysInfo != nil && *flMemoryString != "" && !sysInfo.MemoryLimit {
|
|
*flMemoryString = ""
|
|
}
|
|
|
|
// Validate input params
|
|
if *flDetach && flAttach.Len() > 0 {
|
|
return nil, nil, cmd, ErrConflictAttachDetach
|
|
}
|
|
if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
|
|
return nil, nil, cmd, ErrInvalidWorikingDirectory
|
|
}
|
|
if *flDetach && *flAutoRemove {
|
|
return nil, nil, cmd, ErrConflictDetachAutoRemove
|
|
}
|
|
|
|
// If neither -d or -a are set, attach to everything by default
|
|
if flAttach.Len() == 0 && !*flDetach {
|
|
if !*flDetach {
|
|
flAttach.Set("stdout")
|
|
flAttach.Set("stderr")
|
|
if *flStdin {
|
|
flAttach.Set("stdin")
|
|
}
|
|
}
|
|
}
|
|
|
|
var flMemory int64
|
|
if *flMemoryString != "" {
|
|
parsedMemory, err := utils.RAMInBytes(*flMemoryString)
|
|
if err != nil {
|
|
return nil, nil, cmd, err
|
|
}
|
|
flMemory = parsedMemory
|
|
}
|
|
|
|
var binds []string
|
|
// add any bind targets to the list of container volumes
|
|
for bind := range flVolumes.GetMap() {
|
|
if arr := strings.Split(bind, ":"); len(arr) > 1 {
|
|
if arr[0] == "/" {
|
|
return nil, nil, cmd, fmt.Errorf("Invalid bind mount: source can't be '/'")
|
|
}
|
|
dstDir := arr[1]
|
|
flVolumes.Set(dstDir)
|
|
binds = append(binds, bind)
|
|
flVolumes.Delete(bind)
|
|
} else if bind == "/" {
|
|
return nil, nil, cmd, fmt.Errorf("Invalid volume: path can't be '/'")
|
|
}
|
|
}
|
|
|
|
var (
|
|
parsedArgs = cmd.Args()
|
|
runCmd []string
|
|
entrypoint []string
|
|
image string
|
|
)
|
|
if len(parsedArgs) >= 1 {
|
|
image = cmd.Arg(0)
|
|
}
|
|
if len(parsedArgs) > 1 {
|
|
runCmd = parsedArgs[1:]
|
|
}
|
|
if *flEntrypoint != "" {
|
|
entrypoint = []string{*flEntrypoint}
|
|
}
|
|
|
|
if !*flPrivileged {
|
|
pLabel, mLabel, e := label.GenLabels(*flLabelOptions)
|
|
if e != nil {
|
|
return nil, nil, cmd, fmt.Errorf("Invalid security labels : %s", e)
|
|
}
|
|
processLabel = pLabel
|
|
mountLabel = mLabel
|
|
}
|
|
|
|
lxcConf, err := parseLxcConfOpts(flLxcOpts)
|
|
if err != nil {
|
|
return nil, nil, cmd, err
|
|
}
|
|
|
|
var (
|
|
domainname string
|
|
hostname = *flHostname
|
|
parts = strings.SplitN(hostname, ".", 2)
|
|
)
|
|
if len(parts) > 1 {
|
|
hostname = parts[0]
|
|
domainname = parts[1]
|
|
}
|
|
|
|
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
|
|
if err != nil {
|
|
return nil, nil, cmd, err
|
|
}
|
|
|
|
// Merge in exposed ports to the map of published ports
|
|
for _, e := range flExpose.GetAll() {
|
|
if strings.Contains(e, ":") {
|
|
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
|
|
}
|
|
p := nat.NewPort(nat.SplitProtoPort(e))
|
|
if _, exists := ports[p]; !exists {
|
|
ports[p] = struct{}{}
|
|
}
|
|
}
|
|
|
|
config := &Config{
|
|
Hostname: hostname,
|
|
Domainname: domainname,
|
|
PortSpecs: nil, // Deprecated
|
|
ExposedPorts: ports,
|
|
User: *flUser,
|
|
Tty: *flTty,
|
|
NetworkDisabled: !*flNetwork,
|
|
OpenStdin: *flStdin,
|
|
Memory: flMemory,
|
|
CpuShares: *flCpuShares,
|
|
AttachStdin: flAttach.Get("stdin"),
|
|
AttachStdout: flAttach.Get("stdout"),
|
|
AttachStderr: flAttach.Get("stderr"),
|
|
Env: flEnv.GetAll(),
|
|
Cmd: runCmd,
|
|
Dns: flDns.GetAll(),
|
|
DnsSearch: flDnsSearch.GetAll(),
|
|
Image: image,
|
|
Volumes: flVolumes.GetMap(),
|
|
VolumesFrom: strings.Join(flVolumesFrom.GetAll(), ","),
|
|
Entrypoint: entrypoint,
|
|
WorkingDir: *flWorkingDir,
|
|
Context: execdriver.Context{
|
|
"mount_label": mountLabel,
|
|
"process_label": processLabel,
|
|
},
|
|
}
|
|
|
|
hostConfig := &HostConfig{
|
|
Binds: binds,
|
|
ContainerIDFile: *flContainerIDFile,
|
|
LxcConf: lxcConf,
|
|
Privileged: *flPrivileged,
|
|
PortBindings: portBindings,
|
|
Links: flLinks.GetAll(),
|
|
PublishAllPorts: *flPublishAll,
|
|
}
|
|
|
|
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
|
|
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
|
config.MemorySwap = -1
|
|
}
|
|
|
|
// When allocating stdin in attached mode, close stdin at client disconnect
|
|
if config.OpenStdin && config.AttachStdin {
|
|
config.StdinOnce = true
|
|
}
|
|
return config, hostConfig, cmd, nil
|
|
}
|
|
|
|
func parseLxcConfOpts(opts opts.ListOpts) ([]KeyValuePair, error) {
|
|
out := make([]KeyValuePair, opts.Len())
|
|
for i, o := range opts.GetAll() {
|
|
k, v, err := parseLxcOpt(o)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out[i] = KeyValuePair{Key: k, Value: v}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func parseLxcOpt(opt string) (string, string, error) {
|
|
parts := strings.SplitN(opt, "=", 2)
|
|
if len(parts) != 2 {
|
|
return "", "", fmt.Errorf("Unable to parse lxc conf option: %s", opt)
|
|
}
|
|
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
|
}
|