2014-02-11 23:04:39 -05:00
package runconfig
import (
"fmt"
2014-08-04 19:14:43 -04:00
"strconv"
2014-04-30 18:46:56 -04:00
"strings"
2014-07-24 18:19:50 -04:00
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
2015-06-30 12:41:01 -04:00
"github.com/docker/docker/pkg/nat"
2014-07-28 20:23:38 -04:00
"github.com/docker/docker/pkg/parsers"
2015-08-04 16:51:48 -04:00
"github.com/docker/docker/pkg/signal"
2015-08-28 11:29:10 -04:00
"github.com/docker/docker/pkg/stringutils"
2014-07-24 18:19:50 -04:00
"github.com/docker/docker/pkg/units"
2015-09-09 22:23:06 -04:00
"github.com/docker/docker/volume"
2014-02-11 23:04:39 -05:00
)
var (
2015-07-25 05:11:45 -04:00
// ErrConflictContainerNetworkAndLinks conflict between --net=container and links
2015-05-12 23:04:07 -04:00
ErrConflictContainerNetworkAndLinks = fmt . Errorf ( "Conflicting options: --net=container can't be used with links. This would result in undefined behavior" )
2015-09-25 06:19:17 -04:00
// ErrConflictUserDefinedNetworkAndLinks conflict between --net=<NETWORK> and links
ErrConflictUserDefinedNetworkAndLinks = fmt . Errorf ( "Conflicting options: --net=<NETWORK> can't be used with links. This would result in undefined behavior" )
// ErrConflictSharedNetwork conflict between private and other networks
ErrConflictSharedNetwork = fmt . Errorf ( "Container sharing network namespace with another container or host cannot be connected to any other network" )
2015-11-08 21:19:53 -05:00
// ErrConflictHostNetwork conflict from being disconnected from host network or connected to host network.
ErrConflictHostNetwork = fmt . Errorf ( "Container cannot be disconnected from host network or connected to host network" )
2015-09-25 06:19:17 -04:00
// ErrConflictNoNetwork conflict between private and other networks
ErrConflictNoNetwork = fmt . Errorf ( "Container cannot be connected to multiple networks with one of the networks in --none mode" )
2015-07-25 05:11:45 -04:00
// ErrConflictNetworkAndDNS conflict between --dns and the network mode
ErrConflictNetworkAndDNS = fmt . Errorf ( "Conflicting options: --dns and the network mode (--net)" )
// ErrConflictNetworkHostname conflict between the hostname and the network mode
ErrConflictNetworkHostname = fmt . Errorf ( "Conflicting options: -h and the network mode (--net)" )
// ErrConflictHostNetworkAndLinks conflict between --net=host and links
ErrConflictHostNetworkAndLinks = fmt . Errorf ( "Conflicting options: --net=host can't be used with links. This would result in undefined behavior" )
// ErrConflictContainerNetworkAndMac conflict between the mac address and the network mode
ErrConflictContainerNetworkAndMac = fmt . Errorf ( "Conflicting options: --mac-address and the network mode (--net)" )
// ErrConflictNetworkHosts conflict between add-host and the network mode
ErrConflictNetworkHosts = fmt . Errorf ( "Conflicting options: --add-host and the network mode (--net)" )
// ErrConflictNetworkPublishPorts conflict between the pulbish options and the network mode
ErrConflictNetworkPublishPorts = fmt . Errorf ( "Conflicting options: -p, -P, --publish-all, --publish and the network mode (--net)" )
// ErrConflictNetworkExposePorts conflict between the expose option and the network mode
2015-11-16 17:45:08 -05:00
ErrConflictNetworkExposePorts = fmt . Errorf ( "Conflicting options: --expose and the network mode (--net)" )
2014-02-11 23:04:39 -05:00
)
2015-07-25 05:11:45 -04:00
// Parse parses the specified args for the specified command and generates a Config,
// a HostConfig and returns them with the specified command.
// If the specified args are not valid, it will return an error.
2014-10-30 12:35:49 -04:00
func Parse ( cmd * flag . FlagSet , args [ ] string ) ( * Config , * HostConfig , * flag . FlagSet , error ) {
2014-02-11 23:04:39 -05:00
var (
// FIXME: use utils.ListOpts for attach and volumes?
2015-06-11 20:34:20 -04:00
flAttach = opts . NewListOpts ( opts . ValidateAttach )
flVolumes = opts . NewListOpts ( nil )
flBlkioWeightDevice = opts . NewWeightdeviceOpt ( opts . ValidateWeightDevice )
flLinks = opts . NewListOpts ( opts . ValidateLink )
flEnv = opts . NewListOpts ( opts . ValidateEnv )
flLabels = opts . NewListOpts ( opts . ValidateEnv )
flDevices = opts . NewListOpts ( opts . ValidateDevice )
2014-02-11 23:04:39 -05:00
2015-05-05 00:18:28 -04:00
flUlimits = opts . NewUlimitOpt ( nil )
2015-02-11 14:21:38 -05:00
2015-09-18 21:21:57 -04:00
flPublish = opts . NewListOpts ( nil )
flExpose = opts . NewListOpts ( nil )
flDNS = opts . NewListOpts ( opts . ValidateIPAddress )
flDNSSearch = opts . NewListOpts ( opts . ValidateDNSSearch )
flDNSOptions = opts . NewListOpts ( nil )
flExtraHosts = opts . NewListOpts ( opts . ValidateExtraHost )
flVolumesFrom = opts . NewListOpts ( nil )
flEnvFile = opts . NewListOpts ( nil )
flCapAdd = opts . NewListOpts ( nil )
flCapDrop = opts . NewListOpts ( nil )
flGroupAdd = opts . NewListOpts ( nil )
flSecurityOpt = opts . NewListOpts ( nil )
flLabelsFile = opts . NewListOpts ( nil )
flLoggingOpts = opts . NewListOpts ( nil )
2015-11-09 09:37:24 -05:00
flPrivileged = cmd . Bool ( [ ] string { "-privileged" } , false , "Give extended privileges to this container" )
2015-09-23 02:02:45 -04:00
flPidMode = cmd . String ( [ ] string { "-pid" } , "" , "PID namespace to use" )
flUTSMode = cmd . String ( [ ] string { "-uts" } , "" , "UTS namespace to use" )
flPublishAll = cmd . Bool ( [ ] string { "P" , "-publish-all" } , false , "Publish all exposed ports to random ports" )
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" )
flOomKillDisable = cmd . Bool ( [ ] string { "-oom-kill-disable" } , false , "Disable OOM Killer" )
2015-11-09 09:37:24 -05:00
flContainerIDFile = cmd . String ( [ ] string { "-cidfile" } , "" , "Write the container ID to the file" )
flEntrypoint = cmd . String ( [ ] string { "-entrypoint" } , "" , "Overwrite the default ENTRYPOINT of the image" )
2015-09-23 02:02:45 -04:00
flHostname = cmd . String ( [ ] string { "h" , "-hostname" } , "" , "Container host name" )
flMemoryString = cmd . String ( [ ] string { "m" , "-memory" } , "" , "Memory limit" )
flMemoryReservation = cmd . String ( [ ] string { "-memory-reservation" } , "" , "Memory soft limit" )
flMemorySwap = cmd . String ( [ ] string { "-memory-swap" } , "" , "Total memory (memory + swap), '-1' to disable swap" )
flKernelMemory = cmd . String ( [ ] string { "-kernel-memory" } , "" , "Kernel memory limit" )
flUser = cmd . String ( [ ] string { "u" , "-user" } , "" , "Username or UID (format: <name|uid>[:<group|gid>])" )
flWorkingDir = cmd . String ( [ ] string { "w" , "-workdir" } , "" , "Working directory inside the container" )
flCPUShares = cmd . Int64 ( [ ] string { "#c" , "-cpu-shares" } , 0 , "CPU shares (relative weight)" )
flCPUPeriod = cmd . Int64 ( [ ] string { "-cpu-period" } , 0 , "Limit CPU CFS (Completely Fair Scheduler) period" )
flCPUQuota = cmd . Int64 ( [ ] string { "-cpu-quota" } , 0 , "Limit CPU CFS (Completely Fair Scheduler) quota" )
2015-11-09 09:37:24 -05:00
flCpusetCpus = cmd . String ( [ ] string { "-cpuset-cpus" } , "" , "CPUs in which to allow execution (0-3, 0,1)" )
2015-09-23 02:02:45 -04:00
flCpusetMems = cmd . String ( [ ] string { "-cpuset-mems" } , "" , "MEMs in which to allow execution (0-3, 0,1)" )
2015-10-06 11:21:43 -04:00
flBlkioWeight = cmd . Uint16 ( [ ] string { "-blkio-weight" } , 0 , "Block IO (relative weight), between 10 and 1000" )
2015-09-23 02:02:45 -04:00
flSwappiness = cmd . Int64 ( [ ] string { "-memory-swappiness" } , - 1 , "Tuning container memory swappiness (0 to 100)" )
2015-09-25 06:19:17 -04:00
flNetMode = cmd . String ( [ ] string { "-net" } , "default" , "Set the Network for the container" )
2015-09-23 02:02:45 -04:00
flMacAddress = cmd . String ( [ ] string { "-mac-address" } , "" , "Container MAC address (e.g. 92:d0:c6:0a:29:33)" )
flIpcMode = cmd . String ( [ ] string { "-ipc" } , "" , "IPC namespace to use" )
flRestartPolicy = cmd . String ( [ ] string { "-restart" } , "no" , "Restart policy to apply when a container exits" )
flReadonlyRootfs = cmd . Bool ( [ ] string { "-read-only" } , false , "Mount the container's root filesystem as read only" )
flLoggingDriver = cmd . String ( [ ] string { "-log-driver" } , "" , "Logging driver for container" )
flCgroupParent = cmd . String ( [ ] string { "-cgroup-parent" } , "" , "Optional parent cgroup for the container" )
flVolumeDriver = cmd . String ( [ ] string { "-volume-driver" } , "" , "Optional volume driver for the container" )
flStopSignal = cmd . String ( [ ] string { "-stop-signal" } , signal . DefaultStopSignal , fmt . Sprintf ( "Signal to stop a container, %v by default" , signal . DefaultStopSignal ) )
2015-10-29 20:58:00 -04:00
flIsolation = cmd . String ( [ ] string { "-isolation" } , "" , "Container isolation level" )
2014-02-11 23:04:39 -05:00
)
2015-03-03 12:04:06 -05:00
cmd . Var ( & flAttach , [ ] string { "a" , "-attach" } , "Attach to STDIN, STDOUT or STDERR" )
2015-06-11 20:34:20 -04:00
cmd . Var ( & flBlkioWeightDevice , [ ] string { "-blkio-weight-device" } , "Block IO weight (relative device weight)" )
2015-02-03 22:51:35 -05:00
cmd . Var ( & flVolumes , [ ] string { "v" , "-volume" } , "Bind mount a volume" )
2015-11-09 09:37:24 -05:00
cmd . Var ( & flLinks , [ ] string { "-link" } , "Add link to another container" )
2015-02-03 22:51:35 -05:00
cmd . Var ( & flDevices , [ ] string { "-device" } , "Add a host device to the container" )
2015-02-16 19:36:03 -05:00
cmd . Var ( & flLabels , [ ] string { "l" , "-label" } , "Set meta data on a container" )
2015-01-06 19:04:10 -05:00
cmd . Var ( & flLabelsFile , [ ] string { "-label-file" } , "Read in a line delimited file of labels" )
2014-02-11 23:04:39 -05:00
cmd . Var ( & flEnv , [ ] string { "e" , "-env" } , "Set environment variables" )
2015-02-03 22:51:35 -05:00
cmd . Var ( & flEnvFile , [ ] string { "-env-file" } , "Read in a file of environment variables" )
cmd . Var ( & flPublish , [ ] string { "p" , "-publish" } , "Publish a container's port(s) to the host" )
2015-11-09 09:37:24 -05:00
cmd . Var ( & flExpose , [ ] string { "-expose" } , "Expose a port or a range of ports" )
cmd . Var ( & flDNS , [ ] string { "-dns" } , "Set custom DNS servers" )
2015-07-25 05:11:45 -04:00
cmd . Var ( & flDNSSearch , [ ] string { "-dns-search" } , "Set custom DNS search domains" )
2015-08-31 14:47:25 -04:00
cmd . Var ( & flDNSOptions , [ ] string { "-dns-opt" } , "Set DNS options" )
2014-09-13 00:35:59 -04:00
cmd . Var ( & flExtraHosts , [ ] string { "-add-host" } , "Add a custom host-to-IP mapping (host:ip)" )
2015-11-09 09:37:24 -05:00
cmd . Var ( & flVolumesFrom , [ ] string { "-volumes-from" } , "Mount volumes from the specified container(s)" )
2014-07-10 19:50:45 -04:00
cmd . Var ( & flCapAdd , [ ] string { "-cap-add" } , "Add Linux capabilities" )
cmd . Var ( & flCapDrop , [ ] string { "-cap-drop" } , "Drop Linux capabilities" )
2015-06-17 14:39:17 -04:00
cmd . Var ( & flGroupAdd , [ ] string { "-group-add" } , "Add additional groups to join" )
2014-09-29 06:44:32 -04:00
cmd . Var ( & flSecurityOpt , [ ] string { "-security-opt" } , "Security Options" )
2015-02-11 14:21:38 -05:00
cmd . Var ( flUlimits , [ ] string { "-ulimit" } , "Ulimit options" )
2015-05-04 17:39:48 -04:00
cmd . Var ( & flLoggingOpts , [ ] string { "-log-opt" } , "Log driver options" )
2014-07-10 14:41:11 -04:00
2014-11-05 11:57:51 -05:00
cmd . Require ( flag . Min , 1 )
2015-03-28 21:22:46 -04:00
if err := cmd . ParseFlags ( args , true ) ; err != nil {
2014-02-11 23:04:39 -05:00
return nil , nil , cmd , err
}
2014-03-10 09:11:23 -04:00
var (
attachStdin = flAttach . Get ( "stdin" )
attachStdout = flAttach . Get ( "stdout" )
attachStderr = flAttach . Get ( "stderr" )
)
2014-02-11 23:04:39 -05:00
2015-05-05 07:27:07 -04:00
// Validate the input mac address
if * flMacAddress != "" {
if _ , err := opts . ValidateMACAddress ( * flMacAddress ) ; err != nil {
return nil , nil , cmd , fmt . Errorf ( "%s is not a valid mac address" , * flMacAddress )
}
2014-07-30 10:51:28 -04:00
}
2015-07-06 18:24:23 -04:00
if * flStdin {
attachStdin = true
}
// If -a is not set attach to the output stdio
2014-03-10 09:11:23 -04:00
if flAttach . Len ( ) == 0 {
attachStdout = true
attachStderr = true
2014-02-11 23:04:39 -05:00
}
2015-09-14 08:30:11 -04:00
var err error
2014-02-11 23:04:39 -05:00
var flMemory int64
if * flMemoryString != "" {
2015-09-14 08:30:11 -04:00
flMemory , err = units . RAMInBytes ( * flMemoryString )
2014-02-11 23:04:39 -05:00
if err != nil {
return nil , nil , cmd , err
}
}
2015-09-23 02:02:45 -04:00
var MemoryReservation int64
if * flMemoryReservation != "" {
MemoryReservation , err = units . RAMInBytes ( * flMemoryReservation )
if err != nil {
return nil , nil , cmd , err
}
}
2015-08-06 07:55:56 -04:00
var memorySwap int64
2014-12-10 19:53:43 -05:00
if * flMemorySwap != "" {
2015-02-08 21:36:49 -05:00
if * flMemorySwap == "-1" {
2015-08-06 07:55:56 -04:00
memorySwap = - 1
2015-02-08 21:36:49 -05:00
} else {
2015-09-14 08:30:11 -04:00
memorySwap , err = units . RAMInBytes ( * flMemorySwap )
2015-02-08 21:36:49 -05:00
if err != nil {
return nil , nil , cmd , err
}
2014-12-10 19:53:43 -05:00
}
}
2015-08-19 11:56:55 -04:00
var KernelMemory int64
if * flKernelMemory != "" {
2015-09-14 08:30:11 -04:00
KernelMemory , err = units . RAMInBytes ( * flKernelMemory )
2015-08-19 11:56:55 -04:00
if err != nil {
return nil , nil , cmd , err
}
}
2015-07-20 04:10:10 -04:00
swappiness := * flSwappiness
if swappiness != - 1 && ( swappiness < 0 || swappiness > 100 ) {
return nil , nil , cmd , fmt . Errorf ( "Invalid value: %d. Valid memory swappiness range is 0-100" , swappiness )
2015-07-12 03:46:33 -04:00
}
2014-02-11 23:04:39 -05:00
var binds [ ] string
// add any bind targets to the list of container volumes
for bind := range flVolumes . GetMap ( ) {
2015-09-09 22:23:06 -04:00
if arr := volume . SplitN ( bind , 2 ) ; len ( arr ) > 1 {
2014-05-19 18:18:37 -04:00
// 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
2014-02-11 23:04:39 -05:00
binds = append ( binds , bind )
flVolumes . Delete ( bind )
}
}
var (
parsedArgs = cmd . Args ( )
2015-08-28 11:29:10 -04:00
runCmd * stringutils . StrSlice
entrypoint * stringutils . StrSlice
2014-10-15 17:14:12 -04:00
image = cmd . Arg ( 0 )
2014-02-11 23:04:39 -05:00
)
if len ( parsedArgs ) > 1 {
2015-08-28 11:29:10 -04:00
runCmd = stringutils . NewStrSlice ( parsedArgs [ 1 : ] ... )
2014-02-11 23:04:39 -05:00
}
if * flEntrypoint != "" {
2015-08-28 11:29:10 -04:00
entrypoint = stringutils . NewStrSlice ( * flEntrypoint )
2014-02-11 23:04:39 -05:00
}
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 )
}
2014-09-16 21:08:30 -04:00
//support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
2015-02-17 10:12:02 -05:00
proto , port := nat . SplitProtoPort ( e )
//parse the start and end port and create a sequence of ports to expose
//if expose a port, the start and end port are the same
start , end , err := parsers . ParsePortRange ( port )
if err != nil {
return nil , nil , cmd , fmt . Errorf ( "Invalid range format for --expose: %s, error: %s" , e , err )
}
for i := start ; i <= end ; i ++ {
2015-07-15 23:45:48 -04:00
p , err := nat . NewPort ( proto , strconv . FormatUint ( i , 10 ) )
if err != nil {
return nil , nil , cmd , err
}
2014-09-16 21:08:30 -04:00
if _ , exists := ports [ p ] ; ! exists {
ports [ p ] = struct { } { }
}
2014-02-11 23:04:39 -05:00
}
}
2014-05-31 00:00:47 -04:00
// parse device mappings
deviceMappings := [ ] DeviceMapping { }
for _ , device := range flDevices . GetAll ( ) {
2015-07-29 05:08:30 -04:00
deviceMapping , err := ParseDevice ( device )
2014-05-31 00:00:47 -04:00
if err != nil {
return nil , nil , cmd , err
}
deviceMappings = append ( deviceMappings , deviceMapping )
}
2014-02-16 19:24:22 -05:00
// collect all the environment variables for the container
2015-01-06 19:04:10 -05:00
envVariables , err := readKVStrings ( flEnvFile . GetAll ( ) , flEnv . GetAll ( ) )
if err != nil {
return nil , nil , cmd , err
}
// collect all the labels for the container
labels , err := readKVStrings ( flLabelsFile . GetAll ( ) , flLabels . GetAll ( ) )
if err != nil {
return nil , nil , cmd , err
2014-02-16 19:24:22 -05:00
}
2014-11-10 16:14:17 -05:00
ipcMode := IpcMode ( * flIpcMode )
if ! ipcMode . Valid ( ) {
2014-11-25 15:10:53 -05:00
return nil , nil , cmd , fmt . Errorf ( "--ipc: invalid IPC mode" )
}
pidMode := PidMode ( * flPidMode )
if ! pidMode . Valid ( ) {
return nil , nil , cmd , fmt . Errorf ( "--pid: invalid PID mode" )
2014-11-10 16:14:17 -05:00
}
2015-05-05 18:32:36 -04:00
utsMode := UTSMode ( * flUTSMode )
if ! utsMode . Valid ( ) {
return nil , nil , cmd , fmt . Errorf ( "--uts: invalid UTS mode" )
}
2015-04-24 15:23:54 -04:00
restartPolicy , err := ParseRestartPolicy ( * flRestartPolicy )
2014-08-04 19:14:43 -04:00
if err != nil {
return nil , nil , cmd , err
}
2015-05-04 17:39:48 -04:00
loggingOpts , err := parseLoggingOpts ( * flLoggingDriver , flLoggingOpts . GetAll ( ) )
if err != nil {
return nil , nil , cmd , err
}
2014-02-11 23:04:39 -05:00
config := & Config {
2015-11-09 09:37:24 -05:00
Hostname : hostname ,
Domainname : domainname ,
ExposedPorts : ports ,
User : * flUser ,
Tty : * flTty ,
// TODO: deprecated, it comes from -n, --networking
// it's still needed internally to set the network to disabled
// if e.g. bridge is none in daemon opts, and in inspect
NetworkDisabled : false ,
2014-02-11 23:04:39 -05:00
OpenStdin : * flStdin ,
2014-03-10 09:11:23 -04:00
AttachStdin : attachStdin ,
AttachStdout : attachStdout ,
AttachStderr : attachStderr ,
2014-02-16 19:24:22 -05:00
Env : envVariables ,
2014-02-11 23:04:39 -05:00
Cmd : runCmd ,
Image : image ,
Volumes : flVolumes . GetMap ( ) ,
2014-10-03 17:02:17 -04:00
MacAddress : * flMacAddress ,
2014-02-11 23:04:39 -05:00
Entrypoint : entrypoint ,
WorkingDir : * flWorkingDir ,
2014-11-14 13:59:14 -05:00
Labels : ConvertKVStringsToMap ( labels ) ,
2015-08-04 16:51:48 -04:00
StopSignal : * flStopSignal ,
2014-02-11 23:04:39 -05:00
}
hostConfig := & HostConfig {
2015-09-23 02:02:45 -04:00
Binds : binds ,
ContainerIDFile : * flContainerIDFile ,
Memory : flMemory ,
MemoryReservation : MemoryReservation ,
MemorySwap : memorySwap ,
KernelMemory : KernelMemory ,
CPUShares : * flCPUShares ,
CPUPeriod : * flCPUPeriod ,
CpusetCpus : * flCpusetCpus ,
CpusetMems : * flCpusetMems ,
CPUQuota : * flCPUQuota ,
BlkioWeight : * flBlkioWeight ,
2015-06-11 20:34:20 -04:00
BlkioWeightDevice : flBlkioWeightDevice . GetList ( ) ,
2015-09-23 02:02:45 -04:00
OomKillDisable : * flOomKillDisable ,
MemorySwappiness : flSwappiness ,
Privileged : * flPrivileged ,
PortBindings : portBindings ,
Links : flLinks . GetAll ( ) ,
PublishAllPorts : * flPublishAll ,
2015-11-06 17:22:48 -05:00
// Make sure the dns fields are never nil.
// New containers don't ever have those fields nil,
// but pre created containers can still have those nil values.
// See https://github.com/docker/docker/pull/17779
// for a more detailed explanation on why we don't want that.
DNS : flDNS . GetAllOrEmpty ( ) ,
DNSSearch : flDNSSearch . GetAllOrEmpty ( ) ,
DNSOptions : flDNSOptions . GetAllOrEmpty ( ) ,
ExtraHosts : flExtraHosts . GetAll ( ) ,
VolumesFrom : flVolumesFrom . GetAll ( ) ,
NetworkMode : NetworkMode ( * flNetMode ) ,
IpcMode : ipcMode ,
PidMode : pidMode ,
UTSMode : utsMode ,
Devices : deviceMappings ,
CapAdd : stringutils . NewStrSlice ( flCapAdd . GetAll ( ) ... ) ,
CapDrop : stringutils . NewStrSlice ( flCapDrop . GetAll ( ) ... ) ,
GroupAdd : flGroupAdd . GetAll ( ) ,
RestartPolicy : restartPolicy ,
SecurityOpt : flSecurityOpt . GetAll ( ) ,
ReadonlyRootfs : * flReadonlyRootfs ,
Ulimits : flUlimits . GetList ( ) ,
LogConfig : LogConfig { Type : * flLoggingDriver , Config : loggingOpts } ,
CgroupParent : * flCgroupParent ,
VolumeDriver : * flVolumeDriver ,
Isolation : IsolationLevel ( * flIsolation ) ,
2014-02-11 23:04:39 -05:00
}
// When allocating stdin in attached mode, close stdin at client disconnect
if config . OpenStdin && config . AttachStdin {
config . StdinOnce = true
}
return config , hostConfig , cmd , nil
}
2015-01-06 19:04:10 -05:00
// reads a file of line terminated key=value pairs and override that with override parameter
func readKVStrings ( files [ ] string , override [ ] string ) ( [ ] string , error ) {
envVariables := [ ] string { }
for _ , ef := range files {
parsedVars , err := opts . ParseEnvFile ( ef )
if err != nil {
return nil , err
}
envVariables = append ( envVariables , parsedVars ... )
}
// parse the '-e' and '--env' after, to allow override
envVariables = append ( envVariables , override ... )
return envVariables , nil
}
2014-11-14 13:59:14 -05:00
// ConvertKVStringsToMap converts ["key=value"] to {"key":"value"}
func ConvertKVStringsToMap ( values [ ] string ) map [ string ] string {
2015-01-06 19:04:10 -05:00
result := make ( map [ string ] string , len ( values ) )
for _ , value := range values {
kv := strings . SplitN ( value , "=" , 2 )
if len ( kv ) == 1 {
result [ kv [ 0 ] ] = ""
} else {
result [ kv [ 0 ] ] = kv [ 1 ]
}
}
return result
}
2015-05-04 17:39:48 -04:00
func parseLoggingOpts ( loggingDriver string , loggingOpts [ ] string ) ( map [ string ] string , error ) {
2014-11-14 13:59:14 -05:00
loggingOptsMap := ConvertKVStringsToMap ( loggingOpts )
2015-05-04 17:39:48 -04:00
if loggingDriver == "none" && len ( loggingOpts ) > 0 {
return map [ string ] string { } , fmt . Errorf ( "Invalid logging opts for driver %s" , loggingDriver )
}
return loggingOptsMap , nil
}
2015-04-24 15:23:54 -04:00
// ParseRestartPolicy returns the parsed policy or an error indicating what is incorrect
func ParseRestartPolicy ( policy string ) ( RestartPolicy , error ) {
2014-08-04 19:14:43 -04:00
p := RestartPolicy { }
if policy == "" {
return p , nil
}
var (
parts = strings . Split ( policy , ":" )
name = parts [ 0 ]
)
2015-01-08 04:15:55 -05:00
p . Name = name
2014-08-04 19:14:43 -04:00
switch name {
2015-08-05 17:09:08 -04:00
case "always" , "unless-stopped" :
2015-07-03 05:33:33 -04:00
if len ( parts ) > 1 {
2015-08-05 17:09:08 -04:00
return p , fmt . Errorf ( "maximum restart count not valid with restart policy of \"%s\"" , name )
2014-08-04 21:20:53 -04:00
}
case "no" :
// do nothing
case "on-failure" :
2015-07-03 05:33:33 -04:00
if len ( parts ) > 2 {
return p , fmt . Errorf ( "restart count format is not valid, usage: 'on-failure:N' or 'on-failure'" )
}
2014-08-04 19:14:43 -04:00
if len ( parts ) == 2 {
count , err := strconv . Atoi ( parts [ 1 ] )
if err != nil {
return p , err
}
p . MaximumRetryCount = count
}
default :
return p , fmt . Errorf ( "invalid restart policy %s" , name )
}
return p , nil
}
2015-03-29 17:17:23 -04:00
func parseKeyValueOpts ( opts opts . ListOpts ) ( [ ] KeyValuePair , error ) {
out := make ( [ ] KeyValuePair , opts . Len ( ) )
2014-03-13 12:03:09 -04:00
for i , o := range opts . GetAll ( ) {
2014-07-28 20:23:38 -04:00
k , v , err := parsers . ParseKeyValueOpt ( o )
2014-03-13 12:03:09 -04:00
if err != nil {
return nil , err
}
2015-03-29 17:17:23 -04:00
out [ i ] = KeyValuePair { Key : k , Value : v }
2014-02-11 23:04:39 -05:00
}
2014-03-13 12:03:09 -04:00
return out , nil
2014-02-11 23:04:39 -05:00
}
2014-04-30 18:46:56 -04:00
2015-07-29 05:08:30 -04:00
// ParseDevice parses a device mapping string to a DeviceMapping struct
func ParseDevice ( device string ) ( DeviceMapping , error ) {
2014-05-31 00:00:47 -04:00
src := ""
dst := ""
permissions := "rwm"
arr := strings . Split ( device , ":" )
switch len ( arr ) {
case 3 :
permissions = arr [ 2 ]
fallthrough
case 2 :
2015-08-24 05:57:12 -04:00
if opts . ValidDeviceMode ( arr [ 1 ] ) {
permissions = arr [ 1 ]
} else {
dst = arr [ 1 ]
}
2014-05-31 00:00:47 -04:00
fallthrough
case 1 :
src = arr [ 0 ]
default :
return DeviceMapping { } , fmt . Errorf ( "Invalid device specification: %s" , device )
}
if dst == "" {
dst = src
}
deviceMapping := DeviceMapping {
PathOnHost : src ,
PathInContainer : dst ,
CgroupPermissions : permissions ,
}
return deviceMapping , nil
}