Vendor integration dependencies.
This commit is contained in:
parent
dd5e3fba01
commit
55b57c736b
2451 changed files with 731611 additions and 0 deletions
67
integration/vendor/github.com/docker/docker/runconfig/opts/envfile.go
generated
vendored
Normal file
67
integration/vendor/github.com/docker/docker/runconfig/opts/envfile.go
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseEnvFile reads a file with environment variables enumerated by lines
|
||||
//
|
||||
// ``Environment variable names used by the utilities in the Shell and
|
||||
// Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase
|
||||
// letters, digits, and the '_' (underscore) from the characters defined in
|
||||
// Portable Character Set and do not begin with a digit. *But*, other
|
||||
// characters may be permitted by an implementation; applications shall
|
||||
// tolerate the presence of such names.''
|
||||
// -- http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
|
||||
//
|
||||
// As of #16585, it's up to application inside docker to validate or not
|
||||
// environment variables, that's why we just strip leading whitespace and
|
||||
// nothing more.
|
||||
func ParseEnvFile(filename string) ([]string, error) {
|
||||
fh, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
lines := []string{}
|
||||
scanner := bufio.NewScanner(fh)
|
||||
for scanner.Scan() {
|
||||
// trim the line from all leading whitespace first
|
||||
line := strings.TrimLeft(scanner.Text(), whiteSpaces)
|
||||
// line is not empty, and not starting with '#'
|
||||
if len(line) > 0 && !strings.HasPrefix(line, "#") {
|
||||
data := strings.SplitN(line, "=", 2)
|
||||
|
||||
// trim the front of a variable, but nothing else
|
||||
variable := strings.TrimLeft(data[0], whiteSpaces)
|
||||
if strings.ContainsAny(variable, whiteSpaces) {
|
||||
return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' has white spaces", variable)}
|
||||
}
|
||||
|
||||
if len(data) > 1 {
|
||||
|
||||
// pass the value through, no trimming
|
||||
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
|
||||
} else {
|
||||
// if only a pass-through variable is given, clean it up.
|
||||
lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines, scanner.Err()
|
||||
}
|
||||
|
||||
var whiteSpaces = " \t"
|
||||
|
||||
// ErrBadEnvVariable typed error for bad environment variable
|
||||
type ErrBadEnvVariable struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (e ErrBadEnvVariable) Error() string {
|
||||
return fmt.Sprintf("poorly formatted environment: %s", e.msg)
|
||||
}
|
70
integration/vendor/github.com/docker/docker/runconfig/opts/opts.go
generated
vendored
Normal file
70
integration/vendor/github.com/docker/docker/runconfig/opts/opts.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
fopts "github.com/docker/docker/opts"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ValidateAttach validates that the specified string is a valid attach option.
|
||||
func ValidateAttach(val string) (string, error) {
|
||||
s := strings.ToLower(val)
|
||||
for _, str := range []string{"stdin", "stdout", "stderr"} {
|
||||
if s == str {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR")
|
||||
}
|
||||
|
||||
// ValidateEnv validates an environment variable and returns it.
|
||||
// If no value is specified, it returns the current value using os.Getenv.
|
||||
//
|
||||
// As on ParseEnvFile and related to #16585, environment variable names
|
||||
// are not validate what so ever, it's up to application inside docker
|
||||
// to validate them or not.
|
||||
func ValidateEnv(val string) (string, error) {
|
||||
arr := strings.Split(val, "=")
|
||||
if len(arr) > 1 {
|
||||
return val, nil
|
||||
}
|
||||
if !doesEnvExist(val) {
|
||||
return val, nil
|
||||
}
|
||||
return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
|
||||
}
|
||||
|
||||
func doesEnvExist(name string) bool {
|
||||
for _, entry := range os.Environ() {
|
||||
parts := strings.SplitN(entry, "=", 2)
|
||||
if parts[0] == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidateExtraHost validates that the specified string is a valid extrahost and returns it.
|
||||
// ExtraHost is in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6).
|
||||
func ValidateExtraHost(val string) (string, error) {
|
||||
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
|
||||
arr := strings.SplitN(val, ":", 2)
|
||||
if len(arr) != 2 || len(arr[0]) == 0 {
|
||||
return "", fmt.Errorf("bad format for add-host: %q", val)
|
||||
}
|
||||
if _, err := fopts.ValidateIPAddress(arr[1]); err != nil {
|
||||
return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// ValidateMACAddress validates a MAC address.
|
||||
func ValidateMACAddress(val string) (string, error) {
|
||||
_, err := net.ParseMAC(strings.TrimSpace(val))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return val, nil
|
||||
}
|
934
integration/vendor/github.com/docker/docker/runconfig/opts/parse.go
generated
vendored
Normal file
934
integration/vendor/github.com/docker/docker/runconfig/opts/parse.go
generated
vendored
Normal file
|
@ -0,0 +1,934 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/engine-api/types/container"
|
||||
networktypes "github.com/docker/engine-api/types/network"
|
||||
"github.com/docker/engine-api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// ContainerOptions is a data object with all the options for creating a container
|
||||
// TODO: remove fl prefix
|
||||
type ContainerOptions struct {
|
||||
flAttach opts.ListOpts
|
||||
flVolumes opts.ListOpts
|
||||
flTmpfs opts.ListOpts
|
||||
flBlkioWeightDevice WeightdeviceOpt
|
||||
flDeviceReadBps ThrottledeviceOpt
|
||||
flDeviceWriteBps ThrottledeviceOpt
|
||||
flLinks opts.ListOpts
|
||||
flAliases opts.ListOpts
|
||||
flLinkLocalIPs opts.ListOpts
|
||||
flDeviceReadIOps ThrottledeviceOpt
|
||||
flDeviceWriteIOps ThrottledeviceOpt
|
||||
flEnv opts.ListOpts
|
||||
flLabels opts.ListOpts
|
||||
flDevices opts.ListOpts
|
||||
flUlimits *UlimitOpt
|
||||
flSysctls *opts.MapOpts
|
||||
flPublish opts.ListOpts
|
||||
flExpose opts.ListOpts
|
||||
flDNS opts.ListOpts
|
||||
flDNSSearch opts.ListOpts
|
||||
flDNSOptions opts.ListOpts
|
||||
flExtraHosts opts.ListOpts
|
||||
flVolumesFrom opts.ListOpts
|
||||
flEnvFile opts.ListOpts
|
||||
flCapAdd opts.ListOpts
|
||||
flCapDrop opts.ListOpts
|
||||
flGroupAdd opts.ListOpts
|
||||
flSecurityOpt opts.ListOpts
|
||||
flStorageOpt opts.ListOpts
|
||||
flLabelsFile opts.ListOpts
|
||||
flLoggingOpts opts.ListOpts
|
||||
flPrivileged *bool
|
||||
flPidMode *string
|
||||
flUTSMode *string
|
||||
flUsernsMode *string
|
||||
flPublishAll *bool
|
||||
flStdin *bool
|
||||
flTty *bool
|
||||
flOomKillDisable *bool
|
||||
flOomScoreAdj *int
|
||||
flContainerIDFile *string
|
||||
flEntrypoint *string
|
||||
flHostname *string
|
||||
flMemoryString *string
|
||||
flMemoryReservation *string
|
||||
flMemorySwap *string
|
||||
flKernelMemory *string
|
||||
flUser *string
|
||||
flWorkingDir *string
|
||||
flCPUShares *int64
|
||||
flCPUPercent *int64
|
||||
flCPUPeriod *int64
|
||||
flCPUQuota *int64
|
||||
flCpusetCpus *string
|
||||
flCpusetMems *string
|
||||
flBlkioWeight *uint16
|
||||
flIOMaxBandwidth *string
|
||||
flIOMaxIOps *uint64
|
||||
flSwappiness *int64
|
||||
flNetMode *string
|
||||
flMacAddress *string
|
||||
flIPv4Address *string
|
||||
flIPv6Address *string
|
||||
flIpcMode *string
|
||||
flPidsLimit *int64
|
||||
flRestartPolicy *string
|
||||
flReadonlyRootfs *bool
|
||||
flLoggingDriver *string
|
||||
flCgroupParent *string
|
||||
flVolumeDriver *string
|
||||
flStopSignal *string
|
||||
flIsolation *string
|
||||
flShmSize *string
|
||||
flNoHealthcheck *bool
|
||||
flHealthCmd *string
|
||||
flHealthInterval *time.Duration
|
||||
flHealthTimeout *time.Duration
|
||||
flHealthRetries *int
|
||||
flRuntime *string
|
||||
|
||||
Image string
|
||||
Args []string
|
||||
}
|
||||
|
||||
// AddFlags adds all command line flags that will be used by Parse to the FlagSet
|
||||
func AddFlags(flags *pflag.FlagSet) *ContainerOptions {
|
||||
copts := &ContainerOptions{
|
||||
flAttach: opts.NewListOpts(ValidateAttach),
|
||||
flVolumes: opts.NewListOpts(nil),
|
||||
flTmpfs: opts.NewListOpts(nil),
|
||||
flBlkioWeightDevice: NewWeightdeviceOpt(ValidateWeightDevice),
|
||||
flDeviceReadBps: NewThrottledeviceOpt(ValidateThrottleBpsDevice),
|
||||
flDeviceWriteBps: NewThrottledeviceOpt(ValidateThrottleBpsDevice),
|
||||
flLinks: opts.NewListOpts(ValidateLink),
|
||||
flAliases: opts.NewListOpts(nil),
|
||||
flLinkLocalIPs: opts.NewListOpts(nil),
|
||||
flDeviceReadIOps: NewThrottledeviceOpt(ValidateThrottleIOpsDevice),
|
||||
flDeviceWriteIOps: NewThrottledeviceOpt(ValidateThrottleIOpsDevice),
|
||||
flEnv: opts.NewListOpts(ValidateEnv),
|
||||
flLabels: opts.NewListOpts(ValidateEnv),
|
||||
flDevices: opts.NewListOpts(ValidateDevice),
|
||||
|
||||
flUlimits: NewUlimitOpt(nil),
|
||||
flSysctls: opts.NewMapOpts(nil, opts.ValidateSysctl),
|
||||
|
||||
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(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),
|
||||
flStorageOpt: opts.NewListOpts(nil),
|
||||
flLabelsFile: opts.NewListOpts(nil),
|
||||
flLoggingOpts: opts.NewListOpts(nil),
|
||||
|
||||
flPrivileged: flags.Bool("privileged", false, "Give extended privileges to this container"),
|
||||
flPidMode: flags.String("pid", "", "PID namespace to use"),
|
||||
flUTSMode: flags.String("uts", "", "UTS namespace to use"),
|
||||
flUsernsMode: flags.String("userns", "", "User namespace to use"),
|
||||
flPublishAll: flags.BoolP("publish-all", "P", false, "Publish all exposed ports to random ports"),
|
||||
flStdin: flags.BoolP("interactive", "i", false, "Keep STDIN open even if not attached"),
|
||||
flTty: flags.BoolP("tty", "t", false, "Allocate a pseudo-TTY"),
|
||||
flOomKillDisable: flags.Bool("oom-kill-disable", false, "Disable OOM Killer"),
|
||||
flOomScoreAdj: flags.Int("oom-score-adj", 0, "Tune host's OOM preferences (-1000 to 1000)"),
|
||||
flContainerIDFile: flags.String("cidfile", "", "Write the container ID to the file"),
|
||||
flEntrypoint: flags.String("entrypoint", "", "Overwrite the default ENTRYPOINT of the image"),
|
||||
flHostname: flags.StringP("hostname", "h", "", "Container host name"),
|
||||
flMemoryString: flags.StringP("memory", "m", "", "Memory limit"),
|
||||
flMemoryReservation: flags.String("memory-reservation", "", "Memory soft limit"),
|
||||
flMemorySwap: flags.String("memory-swap", "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap"),
|
||||
flKernelMemory: flags.String("kernel-memory", "", "Kernel memory limit"),
|
||||
flUser: flags.StringP("user", "u", "", "Username or UID (format: <name|uid>[:<group|gid>])"),
|
||||
flWorkingDir: flags.StringP("workdir", "w", "", "Working directory inside the container"),
|
||||
flCPUShares: flags.Int64P("cpu-shares", "c", 0, "CPU shares (relative weight)"),
|
||||
flCPUPercent: flags.Int64("cpu-percent", 0, "CPU percent (Windows only)"),
|
||||
flCPUPeriod: flags.Int64("cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period"),
|
||||
flCPUQuota: flags.Int64("cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota"),
|
||||
flCpusetCpus: flags.String("cpuset-cpus", "", "CPUs in which to allow execution (0-3, 0,1)"),
|
||||
flCpusetMems: flags.String("cpuset-mems", "", "MEMs in which to allow execution (0-3, 0,1)"),
|
||||
flBlkioWeight: flags.Uint16("blkio-weight", 0, "Block IO (relative weight), between 10 and 1000"),
|
||||
flIOMaxBandwidth: flags.String("io-maxbandwidth", "", "Maximum IO bandwidth limit for the system drive (Windows only)"),
|
||||
flIOMaxIOps: flags.Uint64("io-maxiops", 0, "Maximum IOps limit for the system drive (Windows only)"),
|
||||
flSwappiness: flags.Int64("memory-swappiness", -1, "Tune container memory swappiness (0 to 100)"),
|
||||
flNetMode: flags.String("net", "default", "Connect a container to a network"),
|
||||
flMacAddress: flags.String("mac-address", "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)"),
|
||||
flIPv4Address: flags.String("ip", "", "Container IPv4 address (e.g. 172.30.100.104)"),
|
||||
flIPv6Address: flags.String("ip6", "", "Container IPv6 address (e.g. 2001:db8::33)"),
|
||||
flIpcMode: flags.String("ipc", "", "IPC namespace to use"),
|
||||
flPidsLimit: flags.Int64("pids-limit", 0, "Tune container pids limit (set -1 for unlimited)"),
|
||||
flRestartPolicy: flags.String("restart", "no", "Restart policy to apply when a container exits"),
|
||||
flReadonlyRootfs: flags.Bool("read-only", false, "Mount the container's root filesystem as read only"),
|
||||
flLoggingDriver: flags.String("log-driver", "", "Logging driver for container"),
|
||||
flCgroupParent: flags.String("cgroup-parent", "", "Optional parent cgroup for the container"),
|
||||
flVolumeDriver: flags.String("volume-driver", "", "Optional volume driver for the container"),
|
||||
flStopSignal: flags.String("stop-signal", signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal)),
|
||||
flIsolation: flags.String("isolation", "", "Container isolation technology"),
|
||||
flShmSize: flags.String("shm-size", "", "Size of /dev/shm, default value is 64MB"),
|
||||
flNoHealthcheck: flags.Bool("no-healthcheck", false, "Disable any container-specified HEALTHCHECK"),
|
||||
flHealthCmd: flags.String("health-cmd", "", "Command to run to check health"),
|
||||
flHealthInterval: flags.Duration("health-interval", 0, "Time between running the check"),
|
||||
flHealthTimeout: flags.Duration("health-timeout", 0, "Maximum time to allow one check to run"),
|
||||
flHealthRetries: flags.Int("health-retries", 0, "Consecutive failures needed to report unhealthy"),
|
||||
flRuntime: flags.String("runtime", "", "Runtime to use for this container"),
|
||||
}
|
||||
|
||||
flags.VarP(&copts.flAttach, "attach", "a", "Attach to STDIN, STDOUT or STDERR")
|
||||
flags.Var(&copts.flBlkioWeightDevice, "blkio-weight-device", "Block IO weight (relative device weight)")
|
||||
flags.Var(&copts.flDeviceReadBps, "device-read-bps", "Limit read rate (bytes per second) from a device")
|
||||
flags.Var(&copts.flDeviceWriteBps, "device-write-bps", "Limit write rate (bytes per second) to a device")
|
||||
flags.Var(&copts.flDeviceReadIOps, "device-read-iops", "Limit read rate (IO per second) from a device")
|
||||
flags.Var(&copts.flDeviceWriteIOps, "device-write-iops", "Limit write rate (IO per second) to a device")
|
||||
flags.VarP(&copts.flVolumes, "volume", "v", "Bind mount a volume")
|
||||
flags.Var(&copts.flTmpfs, "tmpfs", "Mount a tmpfs directory")
|
||||
flags.Var(&copts.flLinks, "link", "Add link to another container")
|
||||
flags.Var(&copts.flAliases, "net-alias", "Add network-scoped alias for the container")
|
||||
flags.Var(&copts.flLinkLocalIPs, "link-local-ip", "Container IPv4/IPv6 link-local addresses")
|
||||
flags.Var(&copts.flDevices, "device", "Add a host device to the container")
|
||||
flags.VarP(&copts.flLabels, "label", "l", "Set meta data on a container")
|
||||
flags.Var(&copts.flLabelsFile, "label-file", "Read in a line delimited file of labels")
|
||||
flags.VarP(&copts.flEnv, "env", "e", "Set environment variables")
|
||||
flags.Var(&copts.flEnvFile, "env-file", "Read in a file of environment variables")
|
||||
flags.VarP(&copts.flPublish, "publish", "p", "Publish a container's port(s) to the host")
|
||||
flags.Var(&copts.flExpose, "expose", "Expose a port or a range of ports")
|
||||
flags.Var(&copts.flDNS, "dns", "Set custom DNS servers")
|
||||
flags.Var(&copts.flDNSSearch, "dns-search", "Set custom DNS search domains")
|
||||
flags.Var(&copts.flDNSOptions, "dns-opt", "Set DNS options")
|
||||
flags.Var(&copts.flExtraHosts, "add-host", "Add a custom host-to-IP mapping (host:ip)")
|
||||
flags.Var(&copts.flVolumesFrom, "volumes-from", "Mount volumes from the specified container(s)")
|
||||
flags.Var(&copts.flCapAdd, "cap-add", "Add Linux capabilities")
|
||||
flags.Var(&copts.flCapDrop, "cap-drop", "Drop Linux capabilities")
|
||||
flags.Var(&copts.flGroupAdd, "group-add", "Add additional groups to join")
|
||||
flags.Var(&copts.flSecurityOpt, "security-opt", "Security Options")
|
||||
flags.Var(&copts.flStorageOpt, "storage-opt", "Set storage driver options per container")
|
||||
flags.Var(copts.flUlimits, "ulimit", "Ulimit options")
|
||||
flags.Var(copts.flSysctls, "sysctl", "Sysctl options")
|
||||
flags.Var(&copts.flLoggingOpts, "log-opt", "Log driver options")
|
||||
|
||||
return copts
|
||||
}
|
||||
|
||||
// Parse parses the 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.
|
||||
func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
|
||||
var (
|
||||
attachStdin = copts.flAttach.Get("stdin")
|
||||
attachStdout = copts.flAttach.Get("stdout")
|
||||
attachStderr = copts.flAttach.Get("stderr")
|
||||
)
|
||||
|
||||
// Validate the input mac address
|
||||
if *copts.flMacAddress != "" {
|
||||
if _, err := ValidateMACAddress(*copts.flMacAddress); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("%s is not a valid mac address", *copts.flMacAddress)
|
||||
}
|
||||
}
|
||||
if *copts.flStdin {
|
||||
attachStdin = true
|
||||
}
|
||||
// If -a is not set, attach to stdout and stderr
|
||||
if copts.flAttach.Len() == 0 {
|
||||
attachStdout = true
|
||||
attachStderr = true
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
var flMemory int64
|
||||
if *copts.flMemoryString != "" {
|
||||
flMemory, err = units.RAMInBytes(*copts.flMemoryString)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var MemoryReservation int64
|
||||
if *copts.flMemoryReservation != "" {
|
||||
MemoryReservation, err = units.RAMInBytes(*copts.flMemoryReservation)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var memorySwap int64
|
||||
if *copts.flMemorySwap != "" {
|
||||
if *copts.flMemorySwap == "-1" {
|
||||
memorySwap = -1
|
||||
} else {
|
||||
memorySwap, err = units.RAMInBytes(*copts.flMemorySwap)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var KernelMemory int64
|
||||
if *copts.flKernelMemory != "" {
|
||||
KernelMemory, err = units.RAMInBytes(*copts.flKernelMemory)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
swappiness := *copts.flSwappiness
|
||||
if swappiness != -1 && (swappiness < 0 || swappiness > 100) {
|
||||
return nil, nil, nil, fmt.Errorf("invalid value: %d. Valid memory swappiness range is 0-100", swappiness)
|
||||
}
|
||||
|
||||
var shmSize int64
|
||||
if *copts.flShmSize != "" {
|
||||
shmSize, err = units.RAMInBytes(*copts.flShmSize)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO FIXME units.RAMInBytes should have a uint64 version
|
||||
var maxIOBandwidth int64
|
||||
if *copts.flIOMaxBandwidth != "" {
|
||||
maxIOBandwidth, err = units.RAMInBytes(*copts.flIOMaxBandwidth)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if maxIOBandwidth < 0 {
|
||||
return nil, nil, nil, fmt.Errorf("invalid value: %s. Maximum IO Bandwidth must be positive", *copts.flIOMaxBandwidth)
|
||||
}
|
||||
}
|
||||
|
||||
var binds []string
|
||||
// add any bind targets to the list of container volumes
|
||||
for bind := range copts.flVolumes.GetMap() {
|
||||
if arr := volumeSplitN(bind, 2); len(arr) > 1 {
|
||||
// after creating the bind mount we want to delete it from the copts.flVolumes values because
|
||||
// we do not want bind mounts being committed to image configs
|
||||
binds = append(binds, bind)
|
||||
copts.flVolumes.Delete(bind)
|
||||
}
|
||||
}
|
||||
|
||||
// Can't evaluate options passed into --tmpfs until we actually mount
|
||||
tmpfs := make(map[string]string)
|
||||
for _, t := range copts.flTmpfs.GetAll() {
|
||||
if arr := strings.SplitN(t, ":", 2); len(arr) > 1 {
|
||||
if _, _, err := mount.ParseTmpfsOptions(arr[1]); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
tmpfs[arr[0]] = arr[1]
|
||||
} else {
|
||||
tmpfs[arr[0]] = ""
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
runCmd strslice.StrSlice
|
||||
entrypoint strslice.StrSlice
|
||||
)
|
||||
if len(copts.Args) > 0 {
|
||||
runCmd = strslice.StrSlice(copts.Args)
|
||||
}
|
||||
if *copts.flEntrypoint != "" {
|
||||
entrypoint = strslice.StrSlice{*copts.flEntrypoint}
|
||||
}
|
||||
|
||||
ports, portBindings, err := nat.ParsePortSpecs(copts.flPublish.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Merge in exposed ports to the map of published ports
|
||||
for _, e := range copts.flExpose.GetAll() {
|
||||
if strings.Contains(e, ":") {
|
||||
return nil, nil, nil, fmt.Errorf("invalid port format for --expose: %s", e)
|
||||
}
|
||||
//support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
|
||||
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 := nat.ParsePortRange(port)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("invalid range format for --expose: %s, error: %s", e, err)
|
||||
}
|
||||
for i := start; i <= end; i++ {
|
||||
p, err := nat.NewPort(proto, strconv.FormatUint(i, 10))
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if _, exists := ports[p]; !exists {
|
||||
ports[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse device mappings
|
||||
deviceMappings := []container.DeviceMapping{}
|
||||
for _, device := range copts.flDevices.GetAll() {
|
||||
deviceMapping, err := ParseDevice(device)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
deviceMappings = append(deviceMappings, deviceMapping)
|
||||
}
|
||||
|
||||
// collect all the environment variables for the container
|
||||
envVariables, err := readKVStrings(copts.flEnvFile.GetAll(), copts.flEnv.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// collect all the labels for the container
|
||||
labels, err := readKVStrings(copts.flLabelsFile.GetAll(), copts.flLabels.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
ipcMode := container.IpcMode(*copts.flIpcMode)
|
||||
if !ipcMode.Valid() {
|
||||
return nil, nil, nil, fmt.Errorf("--ipc: invalid IPC mode")
|
||||
}
|
||||
|
||||
pidMode := container.PidMode(*copts.flPidMode)
|
||||
if !pidMode.Valid() {
|
||||
return nil, nil, nil, fmt.Errorf("--pid: invalid PID mode")
|
||||
}
|
||||
|
||||
utsMode := container.UTSMode(*copts.flUTSMode)
|
||||
if !utsMode.Valid() {
|
||||
return nil, nil, nil, fmt.Errorf("--uts: invalid UTS mode")
|
||||
}
|
||||
|
||||
usernsMode := container.UsernsMode(*copts.flUsernsMode)
|
||||
if !usernsMode.Valid() {
|
||||
return nil, nil, nil, fmt.Errorf("--userns: invalid USER mode")
|
||||
}
|
||||
|
||||
restartPolicy, err := ParseRestartPolicy(*copts.flRestartPolicy)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
loggingOpts, err := parseLoggingOpts(*copts.flLoggingDriver, copts.flLoggingOpts.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
securityOpts, err := parseSecurityOpts(copts.flSecurityOpt.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
storageOpts, err := parseStorageOpts(copts.flStorageOpt.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Healthcheck
|
||||
var healthConfig *container.HealthConfig
|
||||
haveHealthSettings := *copts.flHealthCmd != "" ||
|
||||
*copts.flHealthInterval != 0 ||
|
||||
*copts.flHealthTimeout != 0 ||
|
||||
*copts.flHealthRetries != 0
|
||||
if *copts.flNoHealthcheck {
|
||||
if haveHealthSettings {
|
||||
return nil, nil, nil, fmt.Errorf("--no-healthcheck conflicts with --health-* options")
|
||||
}
|
||||
test := strslice.StrSlice{"NONE"}
|
||||
healthConfig = &container.HealthConfig{Test: test}
|
||||
} else if haveHealthSettings {
|
||||
var probe strslice.StrSlice
|
||||
if *copts.flHealthCmd != "" {
|
||||
args := []string{"CMD-SHELL", *copts.flHealthCmd}
|
||||
probe = strslice.StrSlice(args)
|
||||
}
|
||||
if *copts.flHealthInterval < 0 {
|
||||
return nil, nil, nil, fmt.Errorf("--health-interval cannot be negative")
|
||||
}
|
||||
if *copts.flHealthTimeout < 0 {
|
||||
return nil, nil, nil, fmt.Errorf("--health-timeout cannot be negative")
|
||||
}
|
||||
|
||||
healthConfig = &container.HealthConfig{
|
||||
Test: probe,
|
||||
Interval: *copts.flHealthInterval,
|
||||
Timeout: *copts.flHealthTimeout,
|
||||
Retries: *copts.flHealthRetries,
|
||||
}
|
||||
}
|
||||
|
||||
resources := container.Resources{
|
||||
CgroupParent: *copts.flCgroupParent,
|
||||
Memory: flMemory,
|
||||
MemoryReservation: MemoryReservation,
|
||||
MemorySwap: memorySwap,
|
||||
MemorySwappiness: copts.flSwappiness,
|
||||
KernelMemory: KernelMemory,
|
||||
OomKillDisable: copts.flOomKillDisable,
|
||||
CPUPercent: *copts.flCPUPercent,
|
||||
CPUShares: *copts.flCPUShares,
|
||||
CPUPeriod: *copts.flCPUPeriod,
|
||||
CpusetCpus: *copts.flCpusetCpus,
|
||||
CpusetMems: *copts.flCpusetMems,
|
||||
CPUQuota: *copts.flCPUQuota,
|
||||
PidsLimit: *copts.flPidsLimit,
|
||||
BlkioWeight: *copts.flBlkioWeight,
|
||||
BlkioWeightDevice: copts.flBlkioWeightDevice.GetList(),
|
||||
BlkioDeviceReadBps: copts.flDeviceReadBps.GetList(),
|
||||
BlkioDeviceWriteBps: copts.flDeviceWriteBps.GetList(),
|
||||
BlkioDeviceReadIOps: copts.flDeviceReadIOps.GetList(),
|
||||
BlkioDeviceWriteIOps: copts.flDeviceWriteIOps.GetList(),
|
||||
IOMaximumIOps: *copts.flIOMaxIOps,
|
||||
IOMaximumBandwidth: uint64(maxIOBandwidth),
|
||||
Ulimits: copts.flUlimits.GetList(),
|
||||
Devices: deviceMappings,
|
||||
}
|
||||
|
||||
config := &container.Config{
|
||||
Hostname: *copts.flHostname,
|
||||
ExposedPorts: ports,
|
||||
User: *copts.flUser,
|
||||
Tty: *copts.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,
|
||||
OpenStdin: *copts.flStdin,
|
||||
AttachStdin: attachStdin,
|
||||
AttachStdout: attachStdout,
|
||||
AttachStderr: attachStderr,
|
||||
Env: envVariables,
|
||||
Cmd: runCmd,
|
||||
Image: copts.Image,
|
||||
Volumes: copts.flVolumes.GetMap(),
|
||||
MacAddress: *copts.flMacAddress,
|
||||
Entrypoint: entrypoint,
|
||||
WorkingDir: *copts.flWorkingDir,
|
||||
Labels: ConvertKVStringsToMap(labels),
|
||||
Healthcheck: healthConfig,
|
||||
}
|
||||
if flags.Changed("stop-signal") {
|
||||
config.StopSignal = *copts.flStopSignal
|
||||
}
|
||||
|
||||
hostConfig := &container.HostConfig{
|
||||
Binds: binds,
|
||||
ContainerIDFile: *copts.flContainerIDFile,
|
||||
OomScoreAdj: *copts.flOomScoreAdj,
|
||||
Privileged: *copts.flPrivileged,
|
||||
PortBindings: portBindings,
|
||||
Links: copts.flLinks.GetAll(),
|
||||
PublishAllPorts: *copts.flPublishAll,
|
||||
// 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: copts.flDNS.GetAllOrEmpty(),
|
||||
DNSSearch: copts.flDNSSearch.GetAllOrEmpty(),
|
||||
DNSOptions: copts.flDNSOptions.GetAllOrEmpty(),
|
||||
ExtraHosts: copts.flExtraHosts.GetAll(),
|
||||
VolumesFrom: copts.flVolumesFrom.GetAll(),
|
||||
NetworkMode: container.NetworkMode(*copts.flNetMode),
|
||||
IpcMode: ipcMode,
|
||||
PidMode: pidMode,
|
||||
UTSMode: utsMode,
|
||||
UsernsMode: usernsMode,
|
||||
CapAdd: strslice.StrSlice(copts.flCapAdd.GetAll()),
|
||||
CapDrop: strslice.StrSlice(copts.flCapDrop.GetAll()),
|
||||
GroupAdd: copts.flGroupAdd.GetAll(),
|
||||
RestartPolicy: restartPolicy,
|
||||
SecurityOpt: securityOpts,
|
||||
StorageOpt: storageOpts,
|
||||
ReadonlyRootfs: *copts.flReadonlyRootfs,
|
||||
LogConfig: container.LogConfig{Type: *copts.flLoggingDriver, Config: loggingOpts},
|
||||
VolumeDriver: *copts.flVolumeDriver,
|
||||
Isolation: container.Isolation(*copts.flIsolation),
|
||||
ShmSize: shmSize,
|
||||
Resources: resources,
|
||||
Tmpfs: tmpfs,
|
||||
Sysctls: copts.flSysctls.GetAll(),
|
||||
Runtime: *copts.flRuntime,
|
||||
}
|
||||
|
||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||
if config.OpenStdin && config.AttachStdin {
|
||||
config.StdinOnce = true
|
||||
}
|
||||
|
||||
networkingConfig := &networktypes.NetworkingConfig{
|
||||
EndpointsConfig: make(map[string]*networktypes.EndpointSettings),
|
||||
}
|
||||
|
||||
if *copts.flIPv4Address != "" || *copts.flIPv6Address != "" || copts.flLinkLocalIPs.Len() > 0 {
|
||||
epConfig := &networktypes.EndpointSettings{}
|
||||
networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig
|
||||
|
||||
epConfig.IPAMConfig = &networktypes.EndpointIPAMConfig{
|
||||
IPv4Address: *copts.flIPv4Address,
|
||||
IPv6Address: *copts.flIPv6Address,
|
||||
}
|
||||
|
||||
if copts.flLinkLocalIPs.Len() > 0 {
|
||||
epConfig.IPAMConfig.LinkLocalIPs = make([]string, copts.flLinkLocalIPs.Len())
|
||||
copy(epConfig.IPAMConfig.LinkLocalIPs, copts.flLinkLocalIPs.GetAll())
|
||||
}
|
||||
}
|
||||
|
||||
if hostConfig.NetworkMode.IsUserDefined() && len(hostConfig.Links) > 0 {
|
||||
epConfig := networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)]
|
||||
if epConfig == nil {
|
||||
epConfig = &networktypes.EndpointSettings{}
|
||||
}
|
||||
epConfig.Links = make([]string, len(hostConfig.Links))
|
||||
copy(epConfig.Links, hostConfig.Links)
|
||||
networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig
|
||||
}
|
||||
|
||||
if copts.flAliases.Len() > 0 {
|
||||
epConfig := networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)]
|
||||
if epConfig == nil {
|
||||
epConfig = &networktypes.EndpointSettings{}
|
||||
}
|
||||
epConfig.Aliases = make([]string, copts.flAliases.Len())
|
||||
copy(epConfig.Aliases, copts.flAliases.GetAll())
|
||||
networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig
|
||||
}
|
||||
|
||||
return config, hostConfig, networkingConfig, nil
|
||||
}
|
||||
|
||||
// reads a file of line terminated key=value pairs, and overrides any keys
|
||||
// present in the file with additional pairs specified in the override parameter
|
||||
func readKVStrings(files []string, override []string) ([]string, error) {
|
||||
envVariables := []string{}
|
||||
for _, ef := range files {
|
||||
parsedVars, err := 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
|
||||
}
|
||||
|
||||
// ConvertKVStringsToMap converts ["key=value"] to {"key":"value"}
|
||||
func ConvertKVStringsToMap(values []string) map[string]string {
|
||||
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
|
||||
}
|
||||
|
||||
func parseLoggingOpts(loggingDriver string, loggingOpts []string) (map[string]string, error) {
|
||||
loggingOptsMap := ConvertKVStringsToMap(loggingOpts)
|
||||
if loggingDriver == "none" && len(loggingOpts) > 0 {
|
||||
return map[string]string{}, fmt.Errorf("invalid logging opts for driver %s", loggingDriver)
|
||||
}
|
||||
return loggingOptsMap, nil
|
||||
}
|
||||
|
||||
// takes a local seccomp daemon, reads the file contents for sending to the daemon
|
||||
func parseSecurityOpts(securityOpts []string) ([]string, error) {
|
||||
for key, opt := range securityOpts {
|
||||
con := strings.SplitN(opt, "=", 2)
|
||||
if len(con) == 1 && con[0] != "no-new-privileges" {
|
||||
if strings.Index(opt, ":") != -1 {
|
||||
con = strings.SplitN(opt, ":", 2)
|
||||
} else {
|
||||
return securityOpts, fmt.Errorf("Invalid --security-opt: %q", opt)
|
||||
}
|
||||
}
|
||||
if con[0] == "seccomp" && con[1] != "unconfined" {
|
||||
f, err := ioutil.ReadFile(con[1])
|
||||
if err != nil {
|
||||
return securityOpts, fmt.Errorf("opening seccomp profile (%s) failed: %v", con[1], err)
|
||||
}
|
||||
b := bytes.NewBuffer(nil)
|
||||
if err := json.Compact(b, f); err != nil {
|
||||
return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err)
|
||||
}
|
||||
securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
return securityOpts, nil
|
||||
}
|
||||
|
||||
// parses storage options per container into a map
|
||||
func parseStorageOpts(storageOpts []string) (map[string]string, error) {
|
||||
m := make(map[string]string)
|
||||
for _, option := range storageOpts {
|
||||
if strings.Contains(option, "=") {
|
||||
opt := strings.SplitN(option, "=", 2)
|
||||
m[opt[0]] = opt[1]
|
||||
} else {
|
||||
return nil, fmt.Errorf("Invalid storage option.")
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// ParseRestartPolicy returns the parsed policy or an error indicating what is incorrect
|
||||
func ParseRestartPolicy(policy string) (container.RestartPolicy, error) {
|
||||
p := container.RestartPolicy{}
|
||||
|
||||
if policy == "" {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var (
|
||||
parts = strings.Split(policy, ":")
|
||||
name = parts[0]
|
||||
)
|
||||
|
||||
p.Name = name
|
||||
switch name {
|
||||
case "always", "unless-stopped":
|
||||
if len(parts) > 1 {
|
||||
return p, fmt.Errorf("maximum restart count not valid with restart policy of \"%s\"", name)
|
||||
}
|
||||
case "no":
|
||||
// do nothing
|
||||
case "on-failure":
|
||||
if len(parts) > 2 {
|
||||
return p, fmt.Errorf("restart count format is not valid, usage: 'on-failure:N' or 'on-failure'")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// ParseDevice parses a device mapping string to a container.DeviceMapping struct
|
||||
func ParseDevice(device string) (container.DeviceMapping, error) {
|
||||
src := ""
|
||||
dst := ""
|
||||
permissions := "rwm"
|
||||
arr := strings.Split(device, ":")
|
||||
switch len(arr) {
|
||||
case 3:
|
||||
permissions = arr[2]
|
||||
fallthrough
|
||||
case 2:
|
||||
if ValidDeviceMode(arr[1]) {
|
||||
permissions = arr[1]
|
||||
} else {
|
||||
dst = arr[1]
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
src = arr[0]
|
||||
default:
|
||||
return container.DeviceMapping{}, fmt.Errorf("invalid device specification: %s", device)
|
||||
}
|
||||
|
||||
if dst == "" {
|
||||
dst = src
|
||||
}
|
||||
|
||||
deviceMapping := container.DeviceMapping{
|
||||
PathOnHost: src,
|
||||
PathInContainer: dst,
|
||||
CgroupPermissions: permissions,
|
||||
}
|
||||
return deviceMapping, nil
|
||||
}
|
||||
|
||||
// ParseLink parses and validates the specified string as a link format (name:alias)
|
||||
func ParseLink(val string) (string, string, error) {
|
||||
if val == "" {
|
||||
return "", "", fmt.Errorf("empty string specified for links")
|
||||
}
|
||||
arr := strings.Split(val, ":")
|
||||
if len(arr) > 2 {
|
||||
return "", "", fmt.Errorf("bad format for links: %s", val)
|
||||
}
|
||||
if len(arr) == 1 {
|
||||
return val, val, nil
|
||||
}
|
||||
// This is kept because we can actually get a HostConfig with links
|
||||
// from an already created container and the format is not `foo:bar`
|
||||
// but `/foo:/c1/bar`
|
||||
if strings.HasPrefix(arr[0], "/") {
|
||||
_, alias := path.Split(arr[1])
|
||||
return arr[0][1:], alias, nil
|
||||
}
|
||||
return arr[0], arr[1], nil
|
||||
}
|
||||
|
||||
// ValidateLink validates that the specified string has a valid link format (containerName:alias).
|
||||
func ValidateLink(val string) (string, error) {
|
||||
if _, _, err := ParseLink(val); err != nil {
|
||||
return val, err
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// ValidDeviceMode checks if the mode for device is valid or not.
|
||||
// Valid mode is a composition of r (read), w (write), and m (mknod).
|
||||
func ValidDeviceMode(mode string) bool {
|
||||
var legalDeviceMode = map[rune]bool{
|
||||
'r': true,
|
||||
'w': true,
|
||||
'm': true,
|
||||
}
|
||||
if mode == "" {
|
||||
return false
|
||||
}
|
||||
for _, c := range mode {
|
||||
if !legalDeviceMode[c] {
|
||||
return false
|
||||
}
|
||||
legalDeviceMode[c] = false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ValidateDevice validates a path for devices
|
||||
// It will make sure 'val' is in the form:
|
||||
// [host-dir:]container-path[:mode]
|
||||
// It also validates the device mode.
|
||||
func ValidateDevice(val string) (string, error) {
|
||||
return validatePath(val, ValidDeviceMode)
|
||||
}
|
||||
|
||||
func validatePath(val string, validator func(string) bool) (string, error) {
|
||||
var containerPath string
|
||||
var mode string
|
||||
|
||||
if strings.Count(val, ":") > 2 {
|
||||
return val, fmt.Errorf("bad format for path: %s", val)
|
||||
}
|
||||
|
||||
split := strings.SplitN(val, ":", 3)
|
||||
if split[0] == "" {
|
||||
return val, fmt.Errorf("bad format for path: %s", val)
|
||||
}
|
||||
switch len(split) {
|
||||
case 1:
|
||||
containerPath = split[0]
|
||||
val = path.Clean(containerPath)
|
||||
case 2:
|
||||
if isValid := validator(split[1]); isValid {
|
||||
containerPath = split[0]
|
||||
mode = split[1]
|
||||
val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode)
|
||||
} else {
|
||||
containerPath = split[1]
|
||||
val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath))
|
||||
}
|
||||
case 3:
|
||||
containerPath = split[1]
|
||||
mode = split[2]
|
||||
if isValid := validator(split[2]); !isValid {
|
||||
return val, fmt.Errorf("bad mode specified: %s", mode)
|
||||
}
|
||||
val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode)
|
||||
}
|
||||
|
||||
if !path.IsAbs(containerPath) {
|
||||
return val, fmt.Errorf("%s is not an absolute path", containerPath)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// volumeSplitN splits raw into a maximum of n parts, separated by a separator colon.
|
||||
// A separator colon is the last `:` character in the regex `[:\\]?[a-zA-Z]:` (note `\\` is `\` escaped).
|
||||
// In Windows driver letter appears in two situations:
|
||||
// a. `^[a-zA-Z]:` (A colon followed by `^[a-zA-Z]:` is OK as colon is the separator in volume option)
|
||||
// b. A string in the format like `\\?\C:\Windows\...` (UNC).
|
||||
// Therefore, a driver letter can only follow either a `:` or `\\`
|
||||
// This allows to correctly split strings such as `C:\foo:D:\:rw` or `/tmp/q:/foo`.
|
||||
func volumeSplitN(raw string, n int) []string {
|
||||
var array []string
|
||||
if len(raw) == 0 || raw[0] == ':' {
|
||||
// invalid
|
||||
return nil
|
||||
}
|
||||
// numberOfParts counts the number of parts separated by a separator colon
|
||||
numberOfParts := 0
|
||||
// left represents the left-most cursor in raw, updated at every `:` character considered as a separator.
|
||||
left := 0
|
||||
// right represents the right-most cursor in raw incremented with the loop. Note this
|
||||
// starts at index 1 as index 0 is already handle above as a special case.
|
||||
for right := 1; right < len(raw); right++ {
|
||||
// stop parsing if reached maximum number of parts
|
||||
if n >= 0 && numberOfParts >= n {
|
||||
break
|
||||
}
|
||||
if raw[right] != ':' {
|
||||
continue
|
||||
}
|
||||
potentialDriveLetter := raw[right-1]
|
||||
if (potentialDriveLetter >= 'A' && potentialDriveLetter <= 'Z') || (potentialDriveLetter >= 'a' && potentialDriveLetter <= 'z') {
|
||||
if right > 1 {
|
||||
beforePotentialDriveLetter := raw[right-2]
|
||||
// Only `:` or `\\` are checked (`/` could fall into the case of `/tmp/q:/foo`)
|
||||
if beforePotentialDriveLetter != ':' && beforePotentialDriveLetter != '\\' {
|
||||
// e.g. `C:` is not preceded by any delimiter, therefore it was not a drive letter but a path ending with `C:`.
|
||||
array = append(array, raw[left:right])
|
||||
left = right + 1
|
||||
numberOfParts++
|
||||
}
|
||||
// else, `C:` is considered as a drive letter and not as a delimiter, so we continue parsing.
|
||||
}
|
||||
// if right == 1, then `C:` is the beginning of the raw string, therefore `:` is again not considered a delimiter and we continue parsing.
|
||||
} else {
|
||||
// if `:` is not preceded by a potential drive letter, then consider it as a delimiter.
|
||||
array = append(array, raw[left:right])
|
||||
left = right + 1
|
||||
numberOfParts++
|
||||
}
|
||||
}
|
||||
// need to take care of the last part
|
||||
if left < len(raw) {
|
||||
if n >= 0 && numberOfParts >= n {
|
||||
// if the maximum number of parts is reached, just append the rest to the last part
|
||||
// left-1 is at the last `:` that needs to be included since not considered a separator.
|
||||
array[n-1] += raw[left-1:]
|
||||
} else {
|
||||
array = append(array, raw[left:])
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
74
integration/vendor/github.com/docker/docker/runconfig/opts/runtime.go
generated
vendored
Normal file
74
integration/vendor/github.com/docker/docker/runconfig/opts/runtime.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/engine-api/types"
|
||||
)
|
||||
|
||||
// RuntimeOpt defines a map of Runtimes
|
||||
type RuntimeOpt struct {
|
||||
name string
|
||||
stockRuntimeName string
|
||||
values *map[string]types.Runtime
|
||||
}
|
||||
|
||||
// NewNamedRuntimeOpt creates a new RuntimeOpt
|
||||
func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime, stockRuntime string) *RuntimeOpt {
|
||||
if ref == nil {
|
||||
ref = &map[string]types.Runtime{}
|
||||
}
|
||||
return &RuntimeOpt{name: name, values: ref, stockRuntimeName: stockRuntime}
|
||||
}
|
||||
|
||||
// Name returns the name of the NamedListOpts in the configuration.
|
||||
func (o *RuntimeOpt) Name() string {
|
||||
return o.name
|
||||
}
|
||||
|
||||
// Set validates and updates the list of Runtimes
|
||||
func (o *RuntimeOpt) Set(val string) error {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid runtime argument: %s", val)
|
||||
}
|
||||
|
||||
parts[0] = strings.TrimSpace(parts[0])
|
||||
parts[1] = strings.TrimSpace(parts[1])
|
||||
if parts[0] == "" || parts[1] == "" {
|
||||
return fmt.Errorf("invalid runtime argument: %s", val)
|
||||
}
|
||||
|
||||
parts[0] = strings.ToLower(parts[0])
|
||||
if parts[0] == o.stockRuntimeName {
|
||||
return fmt.Errorf("runtime name '%s' is reserved", o.stockRuntimeName)
|
||||
}
|
||||
|
||||
if _, ok := (*o.values)[parts[0]]; ok {
|
||||
return fmt.Errorf("runtime '%s' was already defined", parts[0])
|
||||
}
|
||||
|
||||
(*o.values)[parts[0]] = types.Runtime{Path: parts[1]}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns Runtime values as a string.
|
||||
func (o *RuntimeOpt) String() string {
|
||||
var out []string
|
||||
for k := range *o.values {
|
||||
out = append(out, k)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", out)
|
||||
}
|
||||
|
||||
// GetMap returns a map of Runtimes (name: path)
|
||||
func (o *RuntimeOpt) GetMap() map[string]types.Runtime {
|
||||
if o.values != nil {
|
||||
return *o.values
|
||||
}
|
||||
|
||||
return map[string]types.Runtime{}
|
||||
}
|
113
integration/vendor/github.com/docker/docker/runconfig/opts/throttledevice.go
generated
vendored
Normal file
113
integration/vendor/github.com/docker/docker/runconfig/opts/throttledevice.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/engine-api/types/blkiodev"
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// ValidatorThrottleFctType defines a validator function that returns a validated struct and/or an error.
|
||||
type ValidatorThrottleFctType func(val string) (*blkiodev.ThrottleDevice, error)
|
||||
|
||||
// ValidateThrottleBpsDevice validates that the specified string has a valid device-rate format.
|
||||
func ValidateThrottleBpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
|
||||
split := strings.SplitN(val, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return nil, fmt.Errorf("bad format: %s", val)
|
||||
}
|
||||
if !strings.HasPrefix(split[0], "/dev/") {
|
||||
return nil, fmt.Errorf("bad format for device path: %s", val)
|
||||
}
|
||||
rate, err := units.RAMInBytes(split[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
|
||||
}
|
||||
if rate < 0 {
|
||||
return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
|
||||
}
|
||||
|
||||
return &blkiodev.ThrottleDevice{
|
||||
Path: split[0],
|
||||
Rate: uint64(rate),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ValidateThrottleIOpsDevice validates that the specified string has a valid device-rate format.
|
||||
func ValidateThrottleIOpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
|
||||
split := strings.SplitN(val, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return nil, fmt.Errorf("bad format: %s", val)
|
||||
}
|
||||
if !strings.HasPrefix(split[0], "/dev/") {
|
||||
return nil, fmt.Errorf("bad format for device path: %s", val)
|
||||
}
|
||||
rate, err := strconv.ParseUint(split[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
|
||||
}
|
||||
if rate < 0 {
|
||||
return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
|
||||
}
|
||||
|
||||
return &blkiodev.ThrottleDevice{
|
||||
Path: split[0],
|
||||
Rate: uint64(rate),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ThrottledeviceOpt defines a map of ThrottleDevices
|
||||
type ThrottledeviceOpt struct {
|
||||
values []*blkiodev.ThrottleDevice
|
||||
validator ValidatorThrottleFctType
|
||||
}
|
||||
|
||||
// NewThrottledeviceOpt creates a new ThrottledeviceOpt
|
||||
func NewThrottledeviceOpt(validator ValidatorThrottleFctType) ThrottledeviceOpt {
|
||||
values := []*blkiodev.ThrottleDevice{}
|
||||
return ThrottledeviceOpt{
|
||||
values: values,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
// Set validates a ThrottleDevice and sets its name as a key in ThrottledeviceOpt
|
||||
func (opt *ThrottledeviceOpt) Set(val string) error {
|
||||
var value *blkiodev.ThrottleDevice
|
||||
if opt.validator != nil {
|
||||
v, err := opt.validator(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value = v
|
||||
}
|
||||
(opt.values) = append((opt.values), value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns ThrottledeviceOpt values as a string.
|
||||
func (opt *ThrottledeviceOpt) String() string {
|
||||
var out []string
|
||||
for _, v := range opt.values {
|
||||
out = append(out, v.String())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", out)
|
||||
}
|
||||
|
||||
// GetList returns a slice of pointers to ThrottleDevices.
|
||||
func (opt *ThrottledeviceOpt) GetList() []*blkiodev.ThrottleDevice {
|
||||
var throttledevice []*blkiodev.ThrottleDevice
|
||||
for _, v := range opt.values {
|
||||
throttledevice = append(throttledevice, v)
|
||||
}
|
||||
|
||||
return throttledevice
|
||||
}
|
||||
|
||||
// Type returns the option type
|
||||
func (opt *ThrottledeviceOpt) Type() string {
|
||||
return "throttled-device"
|
||||
}
|
57
integration/vendor/github.com/docker/docker/runconfig/opts/ulimit.go
generated
vendored
Normal file
57
integration/vendor/github.com/docker/docker/runconfig/opts/ulimit.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// UlimitOpt defines a map of Ulimits
|
||||
type UlimitOpt struct {
|
||||
values *map[string]*units.Ulimit
|
||||
}
|
||||
|
||||
// NewUlimitOpt creates a new UlimitOpt
|
||||
func NewUlimitOpt(ref *map[string]*units.Ulimit) *UlimitOpt {
|
||||
if ref == nil {
|
||||
ref = &map[string]*units.Ulimit{}
|
||||
}
|
||||
return &UlimitOpt{ref}
|
||||
}
|
||||
|
||||
// Set validates a Ulimit and sets its name as a key in UlimitOpt
|
||||
func (o *UlimitOpt) Set(val string) error {
|
||||
l, err := units.ParseUlimit(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
(*o.values)[l.Name] = l
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns Ulimit values as a string.
|
||||
func (o *UlimitOpt) String() string {
|
||||
var out []string
|
||||
for _, v := range *o.values {
|
||||
out = append(out, v.String())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", out)
|
||||
}
|
||||
|
||||
// GetList returns a slice of pointers to Ulimits.
|
||||
func (o *UlimitOpt) GetList() []*units.Ulimit {
|
||||
var ulimits []*units.Ulimit
|
||||
for _, v := range *o.values {
|
||||
ulimits = append(ulimits, v)
|
||||
}
|
||||
|
||||
return ulimits
|
||||
}
|
||||
|
||||
// Type returns the option type
|
||||
func (o *UlimitOpt) Type() string {
|
||||
return "ulimit"
|
||||
}
|
89
integration/vendor/github.com/docker/docker/runconfig/opts/weightdevice.go
generated
vendored
Normal file
89
integration/vendor/github.com/docker/docker/runconfig/opts/weightdevice.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
package opts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/engine-api/types/blkiodev"
|
||||
)
|
||||
|
||||
// ValidatorWeightFctType defines a validator function that returns a validated struct and/or an error.
|
||||
type ValidatorWeightFctType func(val string) (*blkiodev.WeightDevice, error)
|
||||
|
||||
// ValidateWeightDevice validates that the specified string has a valid device-weight format.
|
||||
func ValidateWeightDevice(val string) (*blkiodev.WeightDevice, error) {
|
||||
split := strings.SplitN(val, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return nil, fmt.Errorf("bad format: %s", val)
|
||||
}
|
||||
if !strings.HasPrefix(split[0], "/dev/") {
|
||||
return nil, fmt.Errorf("bad format for device path: %s", val)
|
||||
}
|
||||
weight, err := strconv.ParseUint(split[1], 10, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid weight for device: %s", val)
|
||||
}
|
||||
if weight > 0 && (weight < 10 || weight > 1000) {
|
||||
return nil, fmt.Errorf("invalid weight for device: %s", val)
|
||||
}
|
||||
|
||||
return &blkiodev.WeightDevice{
|
||||
Path: split[0],
|
||||
Weight: uint16(weight),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WeightdeviceOpt defines a map of WeightDevices
|
||||
type WeightdeviceOpt struct {
|
||||
values []*blkiodev.WeightDevice
|
||||
validator ValidatorWeightFctType
|
||||
}
|
||||
|
||||
// NewWeightdeviceOpt creates a new WeightdeviceOpt
|
||||
func NewWeightdeviceOpt(validator ValidatorWeightFctType) WeightdeviceOpt {
|
||||
values := []*blkiodev.WeightDevice{}
|
||||
return WeightdeviceOpt{
|
||||
values: values,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
// Set validates a WeightDevice and sets its name as a key in WeightdeviceOpt
|
||||
func (opt *WeightdeviceOpt) Set(val string) error {
|
||||
var value *blkiodev.WeightDevice
|
||||
if opt.validator != nil {
|
||||
v, err := opt.validator(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value = v
|
||||
}
|
||||
(opt.values) = append((opt.values), value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns WeightdeviceOpt values as a string.
|
||||
func (opt *WeightdeviceOpt) String() string {
|
||||
var out []string
|
||||
for _, v := range opt.values {
|
||||
out = append(out, v.String())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", out)
|
||||
}
|
||||
|
||||
// GetList returns a slice of pointers to WeightDevices.
|
||||
func (opt *WeightdeviceOpt) GetList() []*blkiodev.WeightDevice {
|
||||
var weightdevice []*blkiodev.WeightDevice
|
||||
for _, v := range opt.values {
|
||||
weightdevice = append(weightdevice, v)
|
||||
}
|
||||
|
||||
return weightdevice
|
||||
}
|
||||
|
||||
// Type returns the option type
|
||||
func (opt *WeightdeviceOpt) Type() string {
|
||||
return "weighted-device"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue