summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml6
-rw-r--r--cmd/podman/common/netflags.go102
-rw-r--r--contrib/helloimage/Containerfile8
-rw-r--r--contrib/helloimage/README.md55
-rwxr-xr-xcontrib/helloimage/podman_hello_world.bash23
-rw-r--r--docs/source/markdown/podman-stats.1.md6
-rwxr-xr-xhack/bats15
-rw-r--r--pkg/resolvconf/resolvconf.go8
-rw-r--r--pkg/specgenutil/specgen.go8
-rw-r--r--test/e2e/containers_conf_test.go5
-rw-r--r--test/system/500-networking.bats26
-rw-r--r--vendor/github.com/docker/docker/opts/address_pools.go84
-rw-r--r--vendor/github.com/docker/docker/opts/env.go30
-rw-r--r--vendor/github.com/docker/docker/opts/hosts.go183
-rw-r--r--vendor/github.com/docker/docker/opts/hosts_unix.go11
-rw-r--r--vendor/github.com/docker/docker/opts/hosts_windows.go60
-rw-r--r--vendor/github.com/docker/docker/opts/ip.go47
-rw-r--r--vendor/github.com/docker/docker/opts/opts.go348
-rw-r--r--vendor/github.com/docker/docker/opts/quotedstring.go37
-rw-r--r--vendor/github.com/docker/docker/opts/runtime.go79
-rw-r--r--vendor/github.com/docker/docker/opts/ulimit.go81
-rw-r--r--vendor/github.com/docker/libnetwork/ipamutils/utils.go135
-rw-r--r--vendor/modules.txt2
23 files changed, 1294 insertions, 65 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 41e3d8078..1ec825d00 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -811,9 +811,9 @@ release_task:
release_test_task:
name: "Optional Release Test"
alias: release_test
- # Release-PRs are never ever marked with [CI:DOCS] or [CI:BUILD]
- only_if: *not_build
- # Allow running manually as part of release PR preperation
+ # Release-PRs always include "release" or "Bump" in the title
+ only_if: $CIRRUS_CHANGE_TITLE =~ '.*((release)|(bump)).*'
+ # Allow running manually only as part of release-related builds
# see RELEASE_PROCESS.md
trigger_type: manual
depends_on:
diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go
index 255996ac3..9dfe81d62 100644
--- a/cmd/podman/common/netflags.go
+++ b/cmd/podman/common/netflags.go
@@ -103,69 +103,79 @@ func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet) (*enti
opts = &entities.NetOptions{}
}
- opts.AddHosts, err = flags.GetStringSlice("add-host")
- if err != nil {
- return nil, err
- }
- // Verify the additional hosts are in correct format
- for _, host := range opts.AddHosts {
- if _, err := parse.ValidateExtraHost(host); err != nil {
+ if flags.Changed("add-host") {
+ opts.AddHosts, err = flags.GetStringSlice("add-host")
+ if err != nil {
return nil, err
}
+ // Verify the additional hosts are in correct format
+ for _, host := range opts.AddHosts {
+ if _, err := parse.ValidateExtraHost(host); err != nil {
+ return nil, err
+ }
+ }
}
- servers, err := flags.GetStringSlice("dns")
- if err != nil {
- return nil, err
- }
- for _, d := range servers {
- if d == "none" {
- opts.UseImageResolvConf = true
- if len(servers) > 1 {
- return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
- }
- break
+ if flags.Changed("dns") {
+ servers, err := flags.GetStringSlice("dns")
+ if err != nil {
+ return nil, err
}
- dns := net.ParseIP(d)
- if dns == nil {
- return nil, errors.Errorf("%s is not an ip address", d)
+ for _, d := range servers {
+ if d == "none" {
+ opts.UseImageResolvConf = true
+ if len(servers) > 1 {
+ return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
+ }
+ break
+ }
+ dns := net.ParseIP(d)
+ if dns == nil {
+ return nil, errors.Errorf("%s is not an ip address", d)
+ }
+ opts.DNSServers = append(opts.DNSServers, dns)
}
- opts.DNSServers = append(opts.DNSServers, dns)
}
- options, err := flags.GetStringSlice("dns-opt")
- if err != nil {
- return nil, err
+ if flags.Changed("dns-opt") {
+ options, err := flags.GetStringSlice("dns-opt")
+ if err != nil {
+ return nil, err
+ }
+ opts.DNSOptions = options
}
- opts.DNSOptions = options
- dnsSearches, err := flags.GetStringSlice("dns-search")
- if err != nil {
- return nil, err
- }
- // Validate domains are good
- for _, dom := range dnsSearches {
- if dom == "." {
- if len(dnsSearches) > 1 {
- return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
- }
- continue
- }
- if _, err := parse.ValidateDomain(dom); err != nil {
+ if flags.Changed("dns-search") {
+ dnsSearches, err := flags.GetStringSlice("dns-search")
+ if err != nil {
return nil, err
}
+ // Validate domains are good
+ for _, dom := range dnsSearches {
+ if dom == "." {
+ if len(dnsSearches) > 1 {
+ return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
+ }
+ continue
+ }
+ if _, err := parse.ValidateDomain(dom); err != nil {
+ return nil, err
+ }
+ }
+ opts.DNSSearch = dnsSearches
}
- opts.DNSSearch = dnsSearches
- inputPorts, err := flags.GetStringSlice("publish")
- if err != nil {
- return nil, err
- }
- if len(inputPorts) > 0 {
- opts.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
+ if flags.Changed("publish") {
+ inputPorts, err := flags.GetStringSlice("publish")
if err != nil {
return nil, err
}
+ if len(inputPorts) > 0 {
+ opts.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
+ if err != nil {
+ return nil, err
+ }
+ }
}
opts.NoHosts, err = flags.GetBool("no-hosts")
diff --git a/contrib/helloimage/Containerfile b/contrib/helloimage/Containerfile
new file mode 100644
index 000000000..bea71cae0
--- /dev/null
+++ b/contrib/helloimage/Containerfile
@@ -0,0 +1,8 @@
+FROM registry.access.redhat.com/ubi8-micro:latest
+
+LABEL maintainer="Podman Maintainers"
+LABEL artist="Máirín Ní Ḋuḃṫaiġ, Twitter:@mairin"
+WORKDIR /tmp
+
+COPY podman_hello_world.bash .
+ENTRYPOINT ./podman_hello_world.bash
diff --git a/contrib/helloimage/README.md b/contrib/helloimage/README.md
new file mode 100644
index 000000000..93edcc527
--- /dev/null
+++ b/contrib/helloimage/README.md
@@ -0,0 +1,55 @@
+![PODMAN logo](../../logo/podman-logo-source.svg)
+
+# Podman Hello World image
+
+## Overview
+
+This directory contains the Containerfile and bash script necessary to create the
+"hello" podman image housed on quay.io under the Podman account in a public
+repository. The image is public and can be pulled without credentials.
+
+Using this image is helpful to:
+
+ * Prove that basic Podman operations are working on the host.
+ * Shows that the image was pulled from the quay.io container registry.
+ * Container creation was successfuly accomplished. (`podman ps -a`)
+ * The created container was able to stream output to your terminal.
+
+## Directory Contents
+
+The contents of this directory contain:
+ * ./Containerfile
+ * ./podman_hello_world.bash
+
+## Sample Usage
+
+To simply run the image:
+
+```
+podman run quay.io/podman/hello
+
+! ... Hello Podman World ...!
+
+ .--"--.
+ / - - \
+ / (O) (O) \
+ ~~~| -=(,Y,)=- |
+ .---. /` \ |~~
+ ~/ o o \~~~~.----. ~~
+ | =(X)= |~ / (O (O) \
+ ~~~~~~~ ~| =(Y_)=- |
+ ~~~~ ~~~| U |~~
+
+Project: https://github.com/containers/podman
+Website: https://podman.io
+Documents: https://docs.podman.io
+Twitter: @Podman_io
+```
+To build the image yourself, copy the files from this directory into
+a local directory and issue these commands:
+
+```
+chmod 755 ./podman_hello_world.bash
+podman build -t myhello .
+podman run myhello
+```
diff --git a/contrib/helloimage/podman_hello_world.bash b/contrib/helloimage/podman_hello_world.bash
new file mode 100755
index 000000000..c28141174
--- /dev/null
+++ b/contrib/helloimage/podman_hello_world.bash
@@ -0,0 +1,23 @@
+#!/bin/sh
+###
+# ASCII art by the incomparable Máirín Duffy,
+# duffy@redhat.com, Twitter: @mairin
+# January 2022
+###
+echo " "
+echo "! ... Hello Podman World ...!"
+echo " "
+echo " .--\"--. "
+echo " / - - \\ "
+echo " / (O) (O) \\ "
+echo " ~~~| -=(,Y,)=- | "
+echo " .---. /\` \\ |~~ "
+echo " ~/ o o \\~~~~.----. ~~ "
+echo " | =(X)= |~ / (O (O) \\ "
+echo " ~~~~~~~ ~| =(Y_)=- | "
+echo " ~~~~ ~~~| U |~~ "
+echo ""
+echo "Project: https://github.com/containers/podman"
+echo "Website: https://podman.io"
+echo "Documents: https://docs.podman.io"
+echo "Twitter: @Podman_io"
diff --git a/docs/source/markdown/podman-stats.1.md b/docs/source/markdown/podman-stats.1.md
index 765bdabee..a1a156b10 100644
--- a/docs/source/markdown/podman-stats.1.md
+++ b/docs/source/markdown/podman-stats.1.md
@@ -98,8 +98,10 @@ ID NAME MEM USAGE / LIMIT
6eae9e25a564 clever_bassi 3.031MB / 16.7GB
```
-Note: When using a slirp4netns network, the traffic send via the port forwarding will be accounted
-to the `lo` device. Traffic accounted to `lo` is not accounted in the stats output.
+Note: When using a slirp4netns network with the rootlesskit port
+handler, the traffic send via the port forwarding will be accounted to
+the `lo` device. Traffic accounted to `lo` is not accounted in the
+stats output.
## SEE ALSO
diff --git a/hack/bats b/hack/bats
index 0776521f4..ca9835a1f 100755
--- a/hack/bats
+++ b/hack/bats
@@ -6,18 +6,21 @@
###############################################################################
# BEGIN usage message
-usage="Usage: $0 [--root] [--rootless] [--filter=filename[:testname]]
+usage="Usage: $0 [--root] [--rootless] [FILENAME-PATTERN[:TEST-PATTERN]]
$0 is a wrapper for invoking podman system tests.
--root Run only as root
--rootless Run only as user (i.e. you)
- --filter=name Run only test files that match 'test/system/*name*',
- e.g. '500' or 'net' will match 500-networking.bats.
- If ':pattern' is appended, and you have a modern-enough
- version of bats installed, runs with '--filter pattern'
- which runs only subtests that match 'pattern'
+ FILENAME-PATTERN Run only test files that match 'test/system/*name*',
+ e.g. '500' or 'net' will match 500-networking.bats.
+
+ TEST-PATTERN When appended to a filename-pattern, and you have a
+ modern-enough version of bats installed (i.e. Fedora
+ but not RHEL), runs with '--filter TEST-PATTERN' which
+ runs only subtests within FILENAME-PATTERH whose names
+ match that string.
-T Passed on to bats, which will then show timing data
diff --git a/pkg/resolvconf/resolvconf.go b/pkg/resolvconf/resolvconf.go
index f23cd61b0..d7505e049 100644
--- a/pkg/resolvconf/resolvconf.go
+++ b/pkg/resolvconf/resolvconf.go
@@ -221,11 +221,9 @@ func GetOptions(resolvConf []byte) []string {
// dnsSearch, and an "options" entry for every element in dnsOptions.
func Build(path string, dns, dnsSearch, dnsOptions []string) (*File, error) {
content := bytes.NewBuffer(nil)
- if len(dnsSearch) > 0 {
- if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
- if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
- return nil, err
- }
+ for _, search := range dnsSearch {
+ if _, err := content.WriteString("search " + search + "\n"); err != nil {
+ return nil, err
}
}
for _, dns := range dns {
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index 8ca7ce4e6..17699a038 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -19,6 +19,7 @@ import (
"github.com/containers/podman/v4/pkg/specgen"
systemdDefine "github.com/containers/podman/v4/pkg/systemd/define"
"github.com/containers/podman/v4/pkg/util"
+ "github.com/docker/docker/opts"
"github.com/docker/go-units"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@@ -422,11 +423,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
// SHM Size
if c.ShmSize != "" {
- shmSize, err := units.FromHumanSize(c.ShmSize)
- if err != nil {
+ var m opts.MemBytes
+ if err := m.Set(c.ShmSize); err != nil {
return errors.Wrapf(err, "unable to translate --shm-size")
}
- s.ShmSize = &shmSize
+ val := m.Value()
+ s.ShmSize = &val
}
if c.Net != nil {
diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go
index a23983623..bfed01854 100644
--- a/test/e2e/containers_conf_test.go
+++ b/test/e2e/containers_conf_test.go
@@ -84,6 +84,11 @@ var _ = Describe("Verify podman containers.conf usage", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("size=200k"))
+
+ session = podmanTest.Podman([]string{"run", "--shm-size", "1g", ALPINE, "grep", "shm", "/proc/self/mounts"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("size=1048576k"))
})
It("add capabilities", func() {
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index 5a721c965..e54b8d26a 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -589,4 +589,30 @@ load helpers
run_podman network rm -t 0 -f $netname
}
+@test "podman run CONTAINERS_CONF dns options" {
+ skip_if_remote "CONTAINERS_CONF redirect does not work on remote"
+ # Test on the CLI and via containers.conf
+ containersconf=$PODMAN_TMPDIR/containers.conf
+
+ searchIP="100.100.100.100"
+ cat >$containersconf <<EOF
+[containers]
+ dns_searches = [ "example.com", "test1.com"]
+ dns_servers = [
+ "1.1.1.1",
+ "$searchIP",
+ "1.0.0.1",
+ "8.8.8.8",
+]
+EOF
+export searchDNS="search example.com
+search test1.com
+search a.b"
+ CONTAINERS_CONF=$containersconf run_podman run --rm $IMAGE grep "example.com" /etc/resolv.conf
+ CONTAINERS_CONF=$containersconf run_podman run --rm $IMAGE grep $searchIP /etc/resolv.conf
+ is "$output" "nameserver $searchIP" "Should only be one $searchIP not multiple"
+ CONTAINERS_CONF=$containersconf run_podman run --dns-search a.b --rm $IMAGE grep search /etc/resolv.conf
+ is "$output" "$searchDNS" "Searches should be on different lines"
+}
+
# vim: filetype=sh
diff --git a/vendor/github.com/docker/docker/opts/address_pools.go b/vendor/github.com/docker/docker/opts/address_pools.go
new file mode 100644
index 000000000..fa15c24b9
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/address_pools.go
@@ -0,0 +1,84 @@
+package opts
+
+import (
+ "encoding/csv"
+ "encoding/json"
+ "fmt"
+ "strconv"
+ "strings"
+
+ types "github.com/docker/libnetwork/ipamutils"
+)
+
+// PoolsOpt is a Value type for parsing the default address pools definitions
+type PoolsOpt struct {
+ Values []*types.NetworkToSplit
+}
+
+// UnmarshalJSON fills values structure info from JSON input
+func (p *PoolsOpt) UnmarshalJSON(raw []byte) error {
+ return json.Unmarshal(raw, &(p.Values))
+}
+
+// Set predefined pools
+func (p *PoolsOpt) Set(value string) error {
+ csvReader := csv.NewReader(strings.NewReader(value))
+ fields, err := csvReader.Read()
+ if err != nil {
+ return err
+ }
+
+ poolsDef := types.NetworkToSplit{}
+
+ for _, field := range fields {
+ parts := strings.SplitN(field, "=", 2)
+ if len(parts) != 2 {
+ return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
+ }
+
+ key := strings.ToLower(parts[0])
+ value := strings.ToLower(parts[1])
+
+ switch key {
+ case "base":
+ poolsDef.Base = value
+ case "size":
+ size, err := strconv.Atoi(value)
+ if err != nil {
+ return fmt.Errorf("invalid size value: %q (must be integer): %v", value, err)
+ }
+ poolsDef.Size = size
+ default:
+ return fmt.Errorf("unexpected key '%s' in '%s'", key, field)
+ }
+ }
+
+ p.Values = append(p.Values, &poolsDef)
+
+ return nil
+}
+
+// Type returns the type of this option
+func (p *PoolsOpt) Type() string {
+ return "pool-options"
+}
+
+// String returns a string repr of this option
+func (p *PoolsOpt) String() string {
+ var pools []string
+ for _, pool := range p.Values {
+ repr := fmt.Sprintf("%s %d", pool.Base, pool.Size)
+ pools = append(pools, repr)
+ }
+ return strings.Join(pools, ", ")
+}
+
+// Value returns the mounts
+func (p *PoolsOpt) Value() []*types.NetworkToSplit {
+ return p.Values
+}
+
+// Name returns the flag name of this option
+func (p *PoolsOpt) Name() string {
+ return "default-address-pools"
+}
diff --git a/vendor/github.com/docker/docker/opts/env.go b/vendor/github.com/docker/docker/opts/env.go
new file mode 100644
index 000000000..97e1a8c8a
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/env.go
@@ -0,0 +1,30 @@
+package opts // import "github.com/docker/docker/opts"
+
+import (
+ "os"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+// ValidateEnv validates an environment variable and returns it.
+// If no value is specified, it obtains its value from the current environment
+//
+// As on ParseEnvFile and related to #16585, environment variable names
+// are not validate whatsoever, it's up to application inside docker
+// to validate them or not.
+//
+// The only validation here is to check if name is empty, per #25099
+func ValidateEnv(val string) (string, error) {
+ arr := strings.SplitN(val, "=", 2)
+ if arr[0] == "" {
+ return "", errors.New("invalid environment variable: " + val)
+ }
+ if len(arr) > 1 {
+ return val, nil
+ }
+ if envVal, ok := os.LookupEnv(arr[0]); ok {
+ return arr[0] + "=" + envVal, nil
+ }
+ return val, nil
+}
diff --git a/vendor/github.com/docker/docker/opts/hosts.go b/vendor/github.com/docker/docker/opts/hosts.go
new file mode 100644
index 000000000..a3123adef
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/hosts.go
@@ -0,0 +1,183 @@
+package opts // import "github.com/docker/docker/opts"
+
+import (
+ "fmt"
+ "net"
+ "net/url"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/docker/docker/pkg/homedir"
+)
+
+const (
+ // DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. dockerd -H tcp://
+ // These are the IANA registered port numbers for use with Docker
+ // see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
+ DefaultHTTPPort = 2375 // Default HTTP Port
+ // DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
+ DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
+ // DefaultUnixSocket Path for the unix socket.
+ // Docker daemon by default always listens on the default unix socket
+ DefaultUnixSocket = "/var/run/docker.sock"
+ // DefaultTCPHost constant defines the default host string used by docker on Windows
+ DefaultTCPHost = "tcp://" + DefaultHTTPHost + ":2375"
+ // DefaultTLSHost constant defines the default host string used by docker for TLS sockets
+ DefaultTLSHost = "tcp://" + DefaultHTTPHost + ":2376"
+ // DefaultNamedPipe defines the default named pipe used by docker on Windows
+ DefaultNamedPipe = `//./pipe/docker_engine`
+ // HostGatewayName is the string value that can be passed
+ // to the IPAddr section in --add-host that is replaced by
+ // the value of HostGatewayIP daemon config value
+ HostGatewayName = "host-gateway"
+)
+
+// ValidateHost validates that the specified string is a valid host and returns it.
+func ValidateHost(val string) (string, error) {
+ host := strings.TrimSpace(val)
+ // The empty string means default and is not handled by parseDaemonHost
+ if host != "" {
+ _, err := parseDaemonHost(host)
+ if err != nil {
+ return val, err
+ }
+ }
+ // Note: unlike most flag validators, we don't return the mutated value here
+ // we need to know what the user entered later (using ParseHost) to adjust for TLS
+ return val, nil
+}
+
+// ParseHost and set defaults for a Daemon host string.
+// defaultToTLS is preferred over defaultToUnixXDG.
+func ParseHost(defaultToTLS, defaultToUnixXDG bool, val string) (string, error) {
+ host := strings.TrimSpace(val)
+ if host == "" {
+ if defaultToTLS {
+ host = DefaultTLSHost
+ } else if defaultToUnixXDG {
+ runtimeDir, err := homedir.GetRuntimeDir()
+ if err != nil {
+ return "", err
+ }
+ socket := filepath.Join(runtimeDir, "docker.sock")
+ host = "unix://" + socket
+ } else {
+ host = DefaultHost
+ }
+ } else {
+ var err error
+ host, err = parseDaemonHost(host)
+ if err != nil {
+ return val, err
+ }
+ }
+ return host, nil
+}
+
+// parseDaemonHost parses the specified address and returns an address that will be used as the host.
+// Depending of the address specified, this may return one of the global Default* strings defined in hosts.go.
+func parseDaemonHost(addr string) (string, error) {
+ addrParts := strings.SplitN(addr, "://", 2)
+ if len(addrParts) == 1 && addrParts[0] != "" {
+ addrParts = []string{"tcp", addrParts[0]}
+ }
+
+ switch addrParts[0] {
+ case "tcp":
+ return ParseTCPAddr(addrParts[1], DefaultTCPHost)
+ case "unix":
+ return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket)
+ case "npipe":
+ return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe)
+ case "fd":
+ return addr, nil
+ default:
+ return "", fmt.Errorf("Invalid bind address format: %s", addr)
+ }
+}
+
+// parseSimpleProtoAddr parses and validates that the specified address is a valid
+// socket address for simple protocols like unix and npipe. It returns a formatted
+// socket address, either using the address parsed from addr, or the contents of
+// defaultAddr if addr is a blank string.
+func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) {
+ addr = strings.TrimPrefix(addr, proto+"://")
+ if strings.Contains(addr, "://") {
+ return "", fmt.Errorf("Invalid proto, expected %s: %s", proto, addr)
+ }
+ if addr == "" {
+ addr = defaultAddr
+ }
+ return fmt.Sprintf("%s://%s", proto, addr), nil
+}
+
+// ParseTCPAddr parses and validates that the specified address is a valid TCP
+// address. It returns a formatted TCP address, either using the address parsed
+// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.
+// tryAddr is expected to have already been Trim()'d
+// defaultAddr must be in the full `tcp://host:port` form
+func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
+ if tryAddr == "" || tryAddr == "tcp://" {
+ return defaultAddr, nil
+ }
+ addr := strings.TrimPrefix(tryAddr, "tcp://")
+ if strings.Contains(addr, "://") || addr == "" {
+ return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
+ }
+
+ defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://")
+ defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr)
+ if err != nil {
+ return "", err
+ }
+ // url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but
+ // not 1.4. See https://github.com/golang/go/issues/12200 and
+ // https://github.com/golang/go/issues/6530.
+ if strings.HasSuffix(addr, "]:") {
+ addr += defaultPort
+ }
+
+ u, err := url.Parse("tcp://" + addr)
+ if err != nil {
+ return "", err
+ }
+ host, port, err := net.SplitHostPort(u.Host)
+ if err != nil {
+ // try port addition once
+ host, port, err = net.SplitHostPort(net.JoinHostPort(u.Host, defaultPort))
+ }
+ if err != nil {
+ return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
+ }
+
+ if host == "" {
+ host = defaultHost
+ }
+ if port == "" {
+ port = defaultPort
+ }
+ p, err := strconv.Atoi(port)
+ if err != nil && p == 0 {
+ return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
+ }
+
+ return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
+}
+
+// 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)
+ }
+ // Skip IPaddr validation for special "host-gateway" string
+ if arr[1] != HostGatewayName {
+ if _, err := ValidateIPAddress(arr[1]); err != nil {
+ return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
+ }
+ }
+ return val, nil
+}
diff --git a/vendor/github.com/docker/docker/opts/hosts_unix.go b/vendor/github.com/docker/docker/opts/hosts_unix.go
new file mode 100644
index 000000000..29864194a
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/hosts_unix.go
@@ -0,0 +1,11 @@
+// +build !windows
+
+package opts // import "github.com/docker/docker/opts"
+
+const (
+ // DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
+ DefaultHTTPHost = "localhost"
+
+ // DefaultHost constant defines the default host string used by docker on other hosts than Windows
+ DefaultHost = "unix://" + DefaultUnixSocket
+)
diff --git a/vendor/github.com/docker/docker/opts/hosts_windows.go b/vendor/github.com/docker/docker/opts/hosts_windows.go
new file mode 100644
index 000000000..576236ba4
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/hosts_windows.go
@@ -0,0 +1,60 @@
+package opts // import "github.com/docker/docker/opts"
+
+const (
+ // TODO Windows. Identify bug in GOLang 1.5.1+ and/or Windows Server 2016 TP5.
+ //
+ // On Windows, this mitigates a problem with the default options of running
+ // a docker client against a local docker daemon on TP5.
+ //
+ // What was found that if the default host is "localhost", even if the client
+ // (and daemon as this is local) is not physically on a network, and the DNS
+ // cache is flushed (ipconfig /flushdns), then the client will pause for
+ // exactly one second when connecting to the daemon for calls. For example
+ // using docker run windowsservercore cmd, the CLI will send a create followed
+ // by an attach. You see the delay between the attach finishing and the attach
+ // being seen by the daemon.
+ //
+ // Here's some daemon debug logs with additional debug spew put in. The
+ // AfterWriteJSON log is the very last thing the daemon does as part of the
+ // create call. The POST /attach is the second CLI call. Notice the second
+ // time gap.
+ //
+ // time="2015-11-06T13:38:37.259627400-08:00" level=debug msg="After createRootfs"
+ // time="2015-11-06T13:38:37.263626300-08:00" level=debug msg="After setHostConfig"
+ // time="2015-11-06T13:38:37.267631200-08:00" level=debug msg="before createContainerPl...."
+ // time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=ToDiskLocking....
+ // time="2015-11-06T13:38:37.275643200-08:00" level=debug msg="loggin event...."
+ // time="2015-11-06T13:38:37.277627600-08:00" level=debug msg="logged event...."
+ // time="2015-11-06T13:38:37.279631800-08:00" level=debug msg="In defer func"
+ // time="2015-11-06T13:38:37.282628100-08:00" level=debug msg="After daemon.create"
+ // time="2015-11-06T13:38:37.286651700-08:00" level=debug msg="return 2"
+ // time="2015-11-06T13:38:37.289629500-08:00" level=debug msg="Returned from daemon.ContainerCreate"
+ // time="2015-11-06T13:38:37.311629100-08:00" level=debug msg="After WriteJSON"
+ // ... 1 second gap here....
+ // time="2015-11-06T13:38:38.317866200-08:00" level=debug msg="Calling POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach"
+ // time="2015-11-06T13:38:38.326882500-08:00" level=info msg="POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach?stderr=1&stdin=1&stdout=1&stream=1"
+ //
+ // We suspect this is either a bug introduced in GOLang 1.5.1, or that a change
+ // in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows. In theory,
+ // the Windows networking stack is supposed to resolve "localhost" internally,
+ // without hitting DNS, or even reading the hosts file (which is why localhost
+ // is commented out in the hosts file on Windows).
+ //
+ // We have validated that working around this using the actual IPv4 localhost
+ // address does not cause the delay.
+ //
+ // This does not occur with the docker client built with 1.4.3 on the same
+ // Windows build, regardless of whether the daemon is built using 1.5.1
+ // or 1.4.3. It does not occur on Linux. We also verified we see the same thing
+ // on a cross-compiled Windows binary (from Linux).
+ //
+ // Final note: This is a mitigation, not a 'real' fix. It is still susceptible
+ // to the delay if a user were to do 'docker run -H=tcp://localhost:2375...'
+ // explicitly.
+
+ // DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
+ DefaultHTTPHost = "127.0.0.1"
+
+ // DefaultHost constant defines the default host string used by docker on Windows
+ DefaultHost = "npipe://" + DefaultNamedPipe
+)
diff --git a/vendor/github.com/docker/docker/opts/ip.go b/vendor/github.com/docker/docker/opts/ip.go
new file mode 100644
index 000000000..cfbff3a9f
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/ip.go
@@ -0,0 +1,47 @@
+package opts // import "github.com/docker/docker/opts"
+
+import (
+ "fmt"
+ "net"
+)
+
+// IPOpt holds an IP. It is used to store values from CLI flags.
+type IPOpt struct {
+ *net.IP
+}
+
+// NewIPOpt creates a new IPOpt from a reference net.IP and a
+// string representation of an IP. If the string is not a valid
+// IP it will fallback to the specified reference.
+func NewIPOpt(ref *net.IP, defaultVal string) *IPOpt {
+ o := &IPOpt{
+ IP: ref,
+ }
+ o.Set(defaultVal)
+ return o
+}
+
+// Set sets an IPv4 or IPv6 address from a given string. If the given
+// string is not parsable as an IP address it returns an error.
+func (o *IPOpt) Set(val string) error {
+ ip := net.ParseIP(val)
+ if ip == nil {
+ return fmt.Errorf("%s is not an ip address", val)
+ }
+ *o.IP = ip
+ return nil
+}
+
+// String returns the IP address stored in the IPOpt. If stored IP is a
+// nil pointer, it returns an empty string.
+func (o *IPOpt) String() string {
+ if *o.IP == nil {
+ return ""
+ }
+ return o.IP.String()
+}
+
+// Type returns the type of the option
+func (o *IPOpt) Type() string {
+ return "ip"
+}
diff --git a/vendor/github.com/docker/docker/opts/opts.go b/vendor/github.com/docker/docker/opts/opts.go
new file mode 100644
index 000000000..60a093f28
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/opts.go
@@ -0,0 +1,348 @@
+package opts // import "github.com/docker/docker/opts"
+
+import (
+ "fmt"
+ "net"
+ "path"
+ "regexp"
+ "strings"
+
+ units "github.com/docker/go-units"
+)
+
+var (
+ alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
+ domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
+)
+
+// ListOpts holds a list of values and a validation function.
+type ListOpts struct {
+ values *[]string
+ validator ValidatorFctType
+}
+
+// NewListOpts creates a new ListOpts with the specified validator.
+func NewListOpts(validator ValidatorFctType) ListOpts {
+ var values []string
+ return *NewListOptsRef(&values, validator)
+}
+
+// NewListOptsRef creates a new ListOpts with the specified values and validator.
+func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
+ return &ListOpts{
+ values: values,
+ validator: validator,
+ }
+}
+
+func (opts *ListOpts) String() string {
+ if len(*opts.values) == 0 {
+ return ""
+ }
+ return fmt.Sprintf("%v", *opts.values)
+}
+
+// Set validates if needed the input value and adds it to the
+// internal slice.
+func (opts *ListOpts) Set(value string) error {
+ if opts.validator != nil {
+ v, err := opts.validator(value)
+ if err != nil {
+ return err
+ }
+ value = v
+ }
+ *opts.values = append(*opts.values, value)
+ return nil
+}
+
+// Delete removes the specified element from the slice.
+func (opts *ListOpts) Delete(key string) {
+ for i, k := range *opts.values {
+ if k == key {
+ *opts.values = append((*opts.values)[:i], (*opts.values)[i+1:]...)
+ return
+ }
+ }
+}
+
+// GetMap returns the content of values in a map in order to avoid
+// duplicates.
+func (opts *ListOpts) GetMap() map[string]struct{} {
+ ret := make(map[string]struct{})
+ for _, k := range *opts.values {
+ ret[k] = struct{}{}
+ }
+ return ret
+}
+
+// GetAll returns the values of slice.
+func (opts *ListOpts) GetAll() []string {
+ return *opts.values
+}
+
+// GetAllOrEmpty returns the values of the slice
+// or an empty slice when there are no values.
+func (opts *ListOpts) GetAllOrEmpty() []string {
+ v := *opts.values
+ if v == nil {
+ return make([]string, 0)
+ }
+ return v
+}
+
+// Get checks the existence of the specified key.
+func (opts *ListOpts) Get(key string) bool {
+ for _, k := range *opts.values {
+ if k == key {
+ return true
+ }
+ }
+ return false
+}
+
+// Len returns the amount of element in the slice.
+func (opts *ListOpts) Len() int {
+ return len(*opts.values)
+}
+
+// Type returns a string name for this Option type
+func (opts *ListOpts) Type() string {
+ return "list"
+}
+
+// WithValidator returns the ListOpts with validator set.
+func (opts *ListOpts) WithValidator(validator ValidatorFctType) *ListOpts {
+ opts.validator = validator
+ return opts
+}
+
+// NamedOption is an interface that list and map options
+// with names implement.
+type NamedOption interface {
+ Name() string
+}
+
+// NamedListOpts is a ListOpts with a configuration name.
+// This struct is useful to keep reference to the assigned
+// field name in the internal configuration struct.
+type NamedListOpts struct {
+ name string
+ ListOpts
+}
+
+var _ NamedOption = &NamedListOpts{}
+
+// NewNamedListOptsRef creates a reference to a new NamedListOpts struct.
+func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts {
+ return &NamedListOpts{
+ name: name,
+ ListOpts: *NewListOptsRef(values, validator),
+ }
+}
+
+// Name returns the name of the NamedListOpts in the configuration.
+func (o *NamedListOpts) Name() string {
+ return o.name
+}
+
+// MapOpts holds a map of values and a validation function.
+type MapOpts struct {
+ values map[string]string
+ validator ValidatorFctType
+}
+
+// Set validates if needed the input value and add it to the
+// internal map, by splitting on '='.
+func (opts *MapOpts) Set(value string) error {
+ if opts.validator != nil {
+ v, err := opts.validator(value)
+ if err != nil {
+ return err
+ }
+ value = v
+ }
+ vals := strings.SplitN(value, "=", 2)
+ if len(vals) == 1 {
+ (opts.values)[vals[0]] = ""
+ } else {
+ (opts.values)[vals[0]] = vals[1]
+ }
+ return nil
+}
+
+// GetAll returns the values of MapOpts as a map.
+func (opts *MapOpts) GetAll() map[string]string {
+ return opts.values
+}
+
+func (opts *MapOpts) String() string {
+ return fmt.Sprintf("%v", opts.values)
+}
+
+// Type returns a string name for this Option type
+func (opts *MapOpts) Type() string {
+ return "map"
+}
+
+// NewMapOpts creates a new MapOpts with the specified map of values and a validator.
+func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
+ if values == nil {
+ values = make(map[string]string)
+ }
+ return &MapOpts{
+ values: values,
+ validator: validator,
+ }
+}
+
+// NamedMapOpts is a MapOpts struct with a configuration name.
+// This struct is useful to keep reference to the assigned
+// field name in the internal configuration struct.
+type NamedMapOpts struct {
+ name string
+ MapOpts
+}
+
+var _ NamedOption = &NamedMapOpts{}
+
+// NewNamedMapOpts creates a reference to a new NamedMapOpts struct.
+func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts {
+ return &NamedMapOpts{
+ name: name,
+ MapOpts: *NewMapOpts(values, validator),
+ }
+}
+
+// Name returns the name of the NamedMapOpts in the configuration.
+func (o *NamedMapOpts) Name() string {
+ return o.name
+}
+
+// ValidatorFctType defines a validator function that returns a validated string and/or an error.
+type ValidatorFctType func(val string) (string, error)
+
+// ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
+type ValidatorFctListType func(val string) ([]string, error)
+
+// ValidateIPAddress validates an Ip address.
+func ValidateIPAddress(val string) (string, error) {
+ var ip = net.ParseIP(strings.TrimSpace(val))
+ if ip != nil {
+ return ip.String(), nil
+ }
+ return "", fmt.Errorf("%s is not an ip address", val)
+}
+
+// ValidateDNSSearch validates domain for resolvconf search configuration.
+// A zero length domain is represented by a dot (.).
+func ValidateDNSSearch(val string) (string, error) {
+ if val = strings.Trim(val, " "); val == "." {
+ return val, nil
+ }
+ return validateDomain(val)
+}
+
+func validateDomain(val string) (string, error) {
+ if alphaRegexp.FindString(val) == "" {
+ return "", fmt.Errorf("%s is not a valid domain", val)
+ }
+ ns := domainRegexp.FindSubmatch([]byte(val))
+ if len(ns) > 0 && len(ns[1]) < 255 {
+ return string(ns[1]), nil
+ }
+ return "", fmt.Errorf("%s is not a valid domain", val)
+}
+
+// ValidateLabel validates that the specified string is a valid label,
+// it does not use the reserved namespaces com.docker.*, io.docker.*, org.dockerproject.*
+// and returns it.
+// Labels are in the form on key=value.
+func ValidateLabel(val string) (string, error) {
+ if strings.Count(val, "=") < 1 {
+ return "", fmt.Errorf("bad attribute format: %s", val)
+ }
+
+ lowered := strings.ToLower(val)
+ if strings.HasPrefix(lowered, "com.docker.") || strings.HasPrefix(lowered, "io.docker.") ||
+ strings.HasPrefix(lowered, "org.dockerproject.") {
+ return "", fmt.Errorf(
+ "label %s is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
+ val)
+ }
+
+ return val, nil
+}
+
+// ValidateSingleGenericResource validates that a single entry in the
+// generic resource list is valid.
+// i.e 'GPU=UID1' is valid however 'GPU:UID1' or 'UID1' isn't
+func ValidateSingleGenericResource(val string) (string, error) {
+ if strings.Count(val, "=") < 1 {
+ return "", fmt.Errorf("invalid node-generic-resource format `%s` expected `name=value`", val)
+ }
+ return val, 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
+}
+
+// MemBytes is a type for human readable memory bytes (like 128M, 2g, etc)
+type MemBytes int64
+
+// String returns the string format of the human readable memory bytes
+func (m *MemBytes) String() string {
+ // NOTE: In spf13/pflag/flag.go, "0" is considered as "zero value" while "0 B" is not.
+ // We return "0" in case value is 0 here so that the default value is hidden.
+ // (Sometimes "default 0 B" is actually misleading)
+ if m.Value() != 0 {
+ return units.BytesSize(float64(m.Value()))
+ }
+ return "0"
+}
+
+// Set sets the value of the MemBytes by passing a string
+func (m *MemBytes) Set(value string) error {
+ val, err := units.RAMInBytes(value)
+ *m = MemBytes(val)
+ return err
+}
+
+// Type returns the type
+func (m *MemBytes) Type() string {
+ return "bytes"
+}
+
+// Value returns the value in int64
+func (m *MemBytes) Value() int64 {
+ return int64(*m)
+}
+
+// UnmarshalJSON is the customized unmarshaler for MemBytes
+func (m *MemBytes) UnmarshalJSON(s []byte) error {
+ if len(s) <= 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ return fmt.Errorf("invalid size: %q", s)
+ }
+ val, err := units.RAMInBytes(string(s[1 : len(s)-1]))
+ *m = MemBytes(val)
+ return err
+}
diff --git a/vendor/github.com/docker/docker/opts/quotedstring.go b/vendor/github.com/docker/docker/opts/quotedstring.go
new file mode 100644
index 000000000..6c889070e
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/quotedstring.go
@@ -0,0 +1,37 @@
+package opts // import "github.com/docker/docker/opts"
+
+// QuotedString is a string that may have extra quotes around the value. The
+// quotes are stripped from the value.
+type QuotedString struct {
+ value *string
+}
+
+// Set sets a new value
+func (s *QuotedString) Set(val string) error {
+ *s.value = trimQuotes(val)
+ return nil
+}
+
+// Type returns the type of the value
+func (s *QuotedString) Type() string {
+ return "string"
+}
+
+func (s *QuotedString) String() string {
+ return *s.value
+}
+
+func trimQuotes(value string) string {
+ lastIndex := len(value) - 1
+ for _, char := range []byte{'\'', '"'} {
+ if value[0] == char && value[lastIndex] == char {
+ return value[1:lastIndex]
+ }
+ }
+ return value
+}
+
+// NewQuotedString returns a new quoted string option
+func NewQuotedString(value *string) *QuotedString {
+ return &QuotedString{value: value}
+}
diff --git a/vendor/github.com/docker/docker/opts/runtime.go b/vendor/github.com/docker/docker/opts/runtime.go
new file mode 100644
index 000000000..4b9babf0a
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/runtime.go
@@ -0,0 +1,79 @@
+package opts // import "github.com/docker/docker/opts"
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/docker/docker/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{}
+}
+
+// Type returns the type of the option
+func (o *RuntimeOpt) Type() string {
+ return "runtime"
+}
diff --git a/vendor/github.com/docker/docker/opts/ulimit.go b/vendor/github.com/docker/docker/opts/ulimit.go
new file mode 100644
index 000000000..61cc58d4d
--- /dev/null
+++ b/vendor/github.com/docker/docker/opts/ulimit.go
@@ -0,0 +1,81 @@
+package opts // import "github.com/docker/docker/opts"
+
+import (
+ "fmt"
+
+ units "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"
+}
+
+// NamedUlimitOpt defines a named map of Ulimits
+type NamedUlimitOpt struct {
+ name string
+ UlimitOpt
+}
+
+var _ NamedOption = &NamedUlimitOpt{}
+
+// NewNamedUlimitOpt creates a new NamedUlimitOpt
+func NewNamedUlimitOpt(name string, ref *map[string]*units.Ulimit) *NamedUlimitOpt {
+ if ref == nil {
+ ref = &map[string]*units.Ulimit{}
+ }
+ return &NamedUlimitOpt{
+ name: name,
+ UlimitOpt: *NewUlimitOpt(ref),
+ }
+}
+
+// Name returns the option name
+func (o *NamedUlimitOpt) Name() string {
+ return o.name
+}
diff --git a/vendor/github.com/docker/libnetwork/ipamutils/utils.go b/vendor/github.com/docker/libnetwork/ipamutils/utils.go
new file mode 100644
index 000000000..3fd37cd88
--- /dev/null
+++ b/vendor/github.com/docker/libnetwork/ipamutils/utils.go
@@ -0,0 +1,135 @@
+// Package ipamutils provides utility functions for ipam management
+package ipamutils
+
+import (
+ "fmt"
+ "net"
+ "sync"
+)
+
+var (
+ // PredefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
+ // (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGlobalScopeDefaultNetworks`
+ PredefinedLocalScopeDefaultNetworks []*net.IPNet
+ // PredefinedGlobalScopeDefaultNetworks contains a list of 64K IPv4 private networks with host size 8
+ // (10.x.x.x/24) which do not overlap with the networks in `PredefinedLocalScopeDefaultNetworks`
+ PredefinedGlobalScopeDefaultNetworks []*net.IPNet
+ mutex sync.Mutex
+ localScopeDefaultNetworks = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16},
+ {"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16},
+ {"192.168.0.0/16", 20}}
+ globalScopeDefaultNetworks = []*NetworkToSplit{{"10.0.0.0/8", 24}}
+)
+
+// NetworkToSplit represent a network that has to be split in chunks with mask length Size.
+// Each subnet in the set is derived from the Base pool. Base is to be passed
+// in CIDR format.
+// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256
+// 10.10.[0-255].0/24 address pools
+type NetworkToSplit struct {
+ Base string `json:"base"`
+ Size int `json:"size"`
+}
+
+func init() {
+ var err error
+ if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); err != nil {
+ //we are going to panic in case of error as we should never get into this state
+ panic("InitAddressPools failed to initialize the global scope default address pool")
+ }
+
+ if PredefinedLocalScopeDefaultNetworks, err = splitNetworks(localScopeDefaultNetworks); err != nil {
+ //we are going to panic in case of error as we should never get into this state
+ panic("InitAddressPools failed to initialize the local scope default address pool")
+ }
+}
+
+// configDefaultNetworks configures local as well global default pool based on input
+func configDefaultNetworks(defaultAddressPool []*NetworkToSplit, result *[]*net.IPNet) error {
+ mutex.Lock()
+ defer mutex.Unlock()
+ defaultNetworks, err := splitNetworks(defaultAddressPool)
+ if err != nil {
+ return err
+ }
+ *result = defaultNetworks
+ return nil
+}
+
+// GetGlobalScopeDefaultNetworks returns PredefinedGlobalScopeDefaultNetworks
+func GetGlobalScopeDefaultNetworks() []*net.IPNet {
+ mutex.Lock()
+ defer mutex.Unlock()
+ return PredefinedGlobalScopeDefaultNetworks
+}
+
+// GetLocalScopeDefaultNetworks returns PredefinedLocalScopeDefaultNetworks
+func GetLocalScopeDefaultNetworks() []*net.IPNet {
+ mutex.Lock()
+ defer mutex.Unlock()
+ return PredefinedLocalScopeDefaultNetworks
+}
+
+// ConfigGlobalScopeDefaultNetworks configures global default pool.
+// Ideally this will be called from SwarmKit as part of swarm init
+func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
+ if defaultAddressPool == nil {
+ defaultAddressPool = globalScopeDefaultNetworks
+ }
+ return configDefaultNetworks(defaultAddressPool, &PredefinedGlobalScopeDefaultNetworks)
+}
+
+// ConfigLocalScopeDefaultNetworks configures local default pool.
+// Ideally this will be called during libnetwork init
+func ConfigLocalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
+ if defaultAddressPool == nil {
+ return nil
+ }
+ return configDefaultNetworks(defaultAddressPool, &PredefinedLocalScopeDefaultNetworks)
+}
+
+// splitNetworks takes a slice of networks, split them accordingly and returns them
+func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
+ localPools := make([]*net.IPNet, 0, len(list))
+
+ for _, p := range list {
+ _, b, err := net.ParseCIDR(p.Base)
+ if err != nil {
+ return nil, fmt.Errorf("invalid base pool %q: %v", p.Base, err)
+ }
+ ones, _ := b.Mask.Size()
+ if p.Size <= 0 || p.Size < ones {
+ return nil, fmt.Errorf("invalid pools size: %d", p.Size)
+ }
+ localPools = append(localPools, splitNetwork(p.Size, b)...)
+ }
+ return localPools, nil
+}
+
+func splitNetwork(size int, base *net.IPNet) []*net.IPNet {
+ one, bits := base.Mask.Size()
+ mask := net.CIDRMask(size, bits)
+ n := 1 << uint(size-one)
+ s := uint(bits - size)
+ list := make([]*net.IPNet, 0, n)
+
+ for i := 0; i < n; i++ {
+ ip := copyIP(base.IP)
+ addIntToIP(ip, uint(i<<s))
+ list = append(list, &net.IPNet{IP: ip, Mask: mask})
+ }
+ return list
+}
+
+func copyIP(from net.IP) net.IP {
+ ip := make([]byte, len(from))
+ copy(ip, from)
+ return ip
+}
+
+func addIntToIP(array net.IP, ordinal uint) {
+ for i := len(array) - 1; i >= 0; i-- {
+ array[i] |= (byte)(ordinal & 0xff)
+ ordinal >>= 8
+ }
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index aa6fc2753..31c11bd55 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -342,6 +342,7 @@ github.com/docker/docker/api/types/versions
github.com/docker/docker/api/types/volume
github.com/docker/docker/client
github.com/docker/docker/errdefs
+github.com/docker/docker/opts
github.com/docker/docker/pkg/archive
github.com/docker/docker/pkg/fileutils
github.com/docker/docker/pkg/homedir
@@ -372,6 +373,7 @@ github.com/docker/go-plugins-helpers/volume
## explicit
github.com/docker/go-units
# github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316
+github.com/docker/libnetwork/ipamutils
github.com/docker/libnetwork/resolvconf
github.com/docker/libnetwork/resolvconf/dns
github.com/docker/libnetwork/types