func parseRun(cmd *flag.FlagSet, args []string) (*docker.CreateContainerOptions, error) { var ( 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") flDetach = cmd.Bool([]string{"d", "-detach"}, false, "[NOT SUPPORTED] Run container in background and print container ID") flName = cmd.String([]string{"-name"}, "", "Assign a name to the container") // the caller should handle "-rm" with cmd.IsSet() _ = cmd.Bool([]string{"-rm"}, false, "Automatically remove the container when it exits") // the caller should handle "-eq-config" _ = cmd.String([]string{"-eq-config"}, "", "Earthquake configuration file") ) if err := cmd.Parse(args); err != nil { return nil, err } if !*flStdin { return nil, fmt.Errorf("-interactive is expected.") } if !*flTty { return nil, fmt.Errorf("-tty is expected.") } if *flDetach { return nil, fmt.Errorf("Currently, -detach is not supported.") } parsedArgs := cmd.Args() if len(parsedArgs) < 2 { return nil, fmt.Errorf("requires a minimum of 2 arguments") } image := parsedArgs[0] execCmd := parsedArgs[1:] dockerOpt := docker.CreateContainerOptions{ Name: *flName, Config: &docker.Config{ Image: image, Cmd: execCmd, OpenStdin: *flStdin, StdinOnce: true, AttachStdin: true, AttachStdout: true, AttachStderr: true, Tty: *flTty, }, HostConfig: &docker.HostConfig{}, } return &dockerOpt, nil }
// ParseFlags is a utility function that adds a help flag if withHelp is true, // calls cmd.Parse(args) and prints a relevant error message if there are // incorrect number of arguments. It returns error only if error handling is // set to ContinueOnError and parsing fails. If error handling is set to // ExitOnError, it's safe to ignore the return value. // TODO: move this to a better package than utils func ParseFlags(cmd *flag.FlagSet, args []string, withHelp bool) error { var help *bool if withHelp { help = cmd.Bool([]string{"#help", "-help"}, false, "Print usage") } if err := cmd.Parse(args); err != nil { return err } if help != nil && *help { cmd.Usage() // just in case Usage does not exit os.Exit(0) } if str := cmd.CheckArgs(); str != "" { ReportError(cmd, str, withHelp) } return nil }
func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) { var ( 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") flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background") execCmd []string container string ) if err := cmd.Parse(args); err != nil { return nil, err } parsedArgs := cmd.Args() if len(parsedArgs) > 1 { container = cmd.Arg(0) execCmd = parsedArgs[1:] } execConfig := &ExecConfig{ // TODO(vishh): Expose '-u' flag once it is supported. User: "", // TODO(vishh): Expose '-p' flag once it is supported. Privileged: false, Tty: *flTty, Cmd: execCmd, Container: container, Detach: *flDetach, } // If -d is not set, attach to everything by default if !*flDetach { execConfig.AttachStdout = true execConfig.AttachStderr = true if *flStdin { execConfig.AttachStdin = true } } return execConfig, nil }
func Parse(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) { 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) flDevices = opts.NewListOpts(opts.ValidatePath) flPublish = opts.NewListOpts(nil) flExpose = opts.NewListOpts(nil) flDns = opts.NewListOpts(opts.ValidateIPAddress) flDnsSearch = opts.NewListOpts(opts.ValidateDnsSearch) flExtraHosts = opts.NewListOpts(opts.ValidateExtraHost) flVolumesFrom = opts.NewListOpts(nil) flLxcOpts = opts.NewListOpts(nil) flEnvFile = opts.NewListOpts(nil) flCapAdd = opts.NewListOpts(nil) flCapDrop = opts.NewListOpts(nil) flSecurityOpt = opts.NewListOpts(nil) 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)") flCpuset = cmd.String([]string{"-cpuset"}, "", "CPUs in which to allow execution (0-3, 0,1)") flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container\n'bridge': creates a new network stack for the container on the docker bridge\n'none': no networking for this container\n'container:<name|id>': reuses another container network stack\n'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.") flRestartPolicy = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)") flMonitorDriver = cmd.String([]string{"-mon"}, "builtin", "Monitor driver") ) 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 in the form of name:alias") cmd.Var(&flDevices, []string{"-device"}, "Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc)") cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables") cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a line delimited file of environment variables") cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host\nformat: %s\n(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(&flExtraHosts, []string{"-add-host"}, "Add a custom host-to-IP mapping (host:ip)") 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\"") cmd.Var(&flCapAdd, []string{"-cap-add"}, "Add Linux capabilities") cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities") cmd.Var(&flSecurityOpt, []string{"-security-opt"}, "Security Options") 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 *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) { return nil, nil, cmd, ErrInvalidWorkingDirectory } var ( attachStdin = flAttach.Get("stdin") attachStdout = flAttach.Get("stdout") attachStderr = flAttach.Get("stderr") ) if *flNetMode != "bridge" && *flNetMode != "none" && *flHostname != "" { return nil, nil, cmd, ErrConflictNetworkHostname } if *flNetMode == "host" && flLinks.Len() > 0 { return nil, nil, cmd, ErrConflictHostNetworkAndLinks } if *flNetMode == "container" && flLinks.Len() > 0 { return nil, nil, cmd, ErrConflictContainerNetworkAndLinks } if *flNetMode == "host" && flDns.Len() > 0 { return nil, nil, cmd, ErrConflictHostNetworkAndDns } if *flNetMode == "container" && flDns.Len() > 0 { return nil, nil, cmd, ErrConflictContainerNetworkAndDns } // If neither -d or -a are set, attach to everything by default if flAttach.Len() == 0 { attachStdout = true attachStderr = true if *flStdin { attachStdin = true } } var flMemory int64 if *flMemoryString != "" { parsedMemory, err := units.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[1] == "/" { return nil, nil, cmd, fmt.Errorf("Invalid bind mount: destination can't be '/'") } // after creating the bind mount we want to delete it from the flVolumes values because // we do not want bind mounts being committed to image configs 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} } lxcConf, err := parseKeyValueOpts(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{}{} } } // parse device mappings deviceMappings := []DeviceMapping{} for _, device := range flDevices.GetAll() { deviceMapping, err := ParseDevice(device) if err != nil { return nil, nil, cmd, err } deviceMappings = append(deviceMappings, deviceMapping) } // collect all the environment variables for the container envVariables := []string{} for _, ef := range flEnvFile.GetAll() { parsedVars, err := opts.ParseEnvFile(ef) if err != nil { return nil, nil, cmd, err } envVariables = append(envVariables, parsedVars...) } // parse the '-e' and '--env' after, to allow override envVariables = append(envVariables, flEnv.GetAll()...) netMode, err := parseNetMode(*flNetMode) if err != nil { return nil, nil, cmd, fmt.Errorf("--net: invalid net mode: %v", err) } restartPolicy, err := parseRestartPolicy(*flRestartPolicy) if err != nil { return nil, nil, cmd, err } config := &Config{ Hostname: hostname, Domainname: domainname, PortSpecs: nil, // Deprecated ExposedPorts: ports, User: *flUser, Tty: *flTty, NetworkDisabled: !*flNetwork, OpenStdin: *flStdin, Memory: flMemory, CpuShares: *flCpuShares, Cpuset: *flCpuset, AttachStdin: attachStdin, AttachStdout: attachStdout, AttachStderr: attachStderr, Env: envVariables, Cmd: runCmd, Image: image, Volumes: flVolumes.GetMap(), Entrypoint: entrypoint, WorkingDir: *flWorkingDir, MonitorDriver: *flMonitorDriver, } hostConfig := &HostConfig{ Binds: binds, ContainerIDFile: *flContainerIDFile, LxcConf: lxcConf, Privileged: *flPrivileged, PortBindings: portBindings, Links: flLinks.GetAll(), PublishAllPorts: *flPublishAll, Dns: flDns.GetAll(), DnsSearch: flDnsSearch.GetAll(), ExtraHosts: flExtraHosts.GetAll(), VolumesFrom: flVolumesFrom.GetAll(), NetworkMode: netMode, Devices: deviceMappings, CapAdd: flCapAdd.GetAll(), CapDrop: flCapDrop.GetAll(), RestartPolicy: restartPolicy, SecurityOpt: flSecurityOpt.GetAll(), } 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 }