diff --git a/devices/gpu/nvidia/device.go b/devices/gpu/nvidia/device.go index 110287681..b288181c0 100644 --- a/devices/gpu/nvidia/device.go +++ b/devices/gpu/nvidia/device.go @@ -31,7 +31,7 @@ const ( const ( // Nvidia-container-runtime environment variable names - nvidiaVisibleDevices = "NVIDIA_VISIBLE_DEVICES" + NvidiaVisibleDevices = "NVIDIA_VISIBLE_DEVICES" ) var ( @@ -181,7 +181,7 @@ func (d *NvidiaDevice) Reserve(deviceIDs []string) (*device.ContainerReservation return &device.ContainerReservation{ Envs: map[string]string{ - nvidiaVisibleDevices: strings.Join(deviceIDs, ","), + NvidiaVisibleDevices: strings.Join(deviceIDs, ","), }, }, nil } diff --git a/devices/gpu/nvidia/device_test.go b/devices/gpu/nvidia/device_test.go index e6daec967..717491f2b 100644 --- a/devices/gpu/nvidia/device_test.go +++ b/devices/gpu/nvidia/device_test.go @@ -73,7 +73,7 @@ func TestReserve(t *testing.T) { Name: "All RequestedIDs are managed by Device", ExpectedReservation: &device.ContainerReservation{ Envs: map[string]string{ - nvidiaVisibleDevices: "UUID1,UUID2,UUID3", + NvidiaVisibleDevices: "UUID1,UUID2,UUID3", }, }, ExpectedError: nil, diff --git a/drivers/docker/config.go b/drivers/docker/config.go index 2c1e5567a..0398137e0 100644 --- a/drivers/docker/config.go +++ b/drivers/docker/config.go @@ -101,6 +101,12 @@ func PluginLoader(opts map[string]string) (map[string]interface{}, error) { if v, err := strconv.ParseBool(opts["docker.privileged.enabled"]); err == nil { conf["allow_privileged"] = v } + + // nvidia_runtime + if v, ok := opts["docker.nvidia_runtime"]; ok { + conf["nvidia_runtime"] = v + } + return conf, nil } @@ -153,6 +159,7 @@ var ( // } // allow_privileged = false // allow_caps = ["CHOWN", "NET_RAW" ... ] + // nvidia_runtime = "nvidia" // } // } configSpec = hclspec.NewObject(map[string]*hclspec.Spec{ @@ -204,6 +211,10 @@ var ( hclspec.NewAttr("allow_caps", "list(string)", false), hclspec.NewLiteral(`["CHOWN","DAC_OVERRIDE","FSETID","FOWNER","MKNOD","NET_RAW","SETGID","SETUID","SETFCAP","SETPCAP","NET_BIND_SERVICE","SYS_CHROOT","KILL","AUDIT_WRITE"]`), ), + "nvidia_runtime": hclspec.NewDefault( + hclspec.NewAttr("nvidia_runtime", "string", false), + hclspec.NewLiteral(`"nvidia"`), + ), }) // taskConfigSpec is the hcl specification for the driver config section of @@ -470,6 +481,7 @@ type DriverConfig struct { Volumes VolumeConfig `codec:"volumes"` AllowPrivileged bool `codec:"allow_privileged"` AllowCaps []string `codec:"allow_caps"` + GPURuntimeName string `codec:"nvidia_runtime"` } type AuthConfig struct { diff --git a/drivers/docker/driver.go b/drivers/docker/driver.go index 7c2cd8b1f..d20de68ad 100644 --- a/drivers/docker/driver.go +++ b/drivers/docker/driver.go @@ -17,6 +17,7 @@ import ( hclog "github.com/hashicorp/go-hclog" multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/nomad/client/taskenv" + "github.com/hashicorp/nomad/devices/gpu/nvidia" "github.com/hashicorp/nomad/drivers/docker/docklog" "github.com/hashicorp/nomad/drivers/shared/eventer" nstructs "github.com/hashicorp/nomad/nomad/structs" @@ -84,6 +85,9 @@ type Driver struct { // logger will log to the Nomad agent logger hclog.Logger + + // gpuRuntime indicates nvidia-docker runtime availability + gpuRuntime bool } // NewDockerDriver returns a docker implementation of a driver plugin @@ -625,6 +629,13 @@ func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *T PidsLimit: driverConfig.PidsLimit, } + if _, ok := task.DeviceEnv[nvidia.NvidiaVisibleDevices]; ok { + if !d.gpuRuntime { + return c, fmt.Errorf("requested docker-runtime %q was not found", d.config.GPURuntimeName) + } + hostConfig.Runtime = d.config.GPURuntimeName + } + // Calculate CPU Quota // cfs_quota_us is the time per core, so we must // multiply the time by the number of cores available diff --git a/drivers/docker/driver_test.go b/drivers/docker/driver_test.go index 9b3124626..e2d681a82 100644 --- a/drivers/docker/driver_test.go +++ b/drivers/docker/driver_test.go @@ -23,6 +23,7 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/taskenv" "github.com/hashicorp/nomad/client/testutil" + "github.com/hashicorp/nomad/devices/gpu/nvidia" "github.com/hashicorp/nomad/helper/testlog" "github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/nomad/structs" @@ -95,8 +96,9 @@ func dockerTask(t *testing.T) (*drivers.TaskConfig, *TaskConfig, []int) { Args: busyboxLongRunningCmd[1:], } task := &drivers.TaskConfig{ - ID: uuid.Generate(), - Name: "redis-demo", + ID: uuid.Generate(), + Name: "redis-demo", + DeviceEnv: make(map[string]string), Resources: &drivers.Resources{ NomadResources: &structs.AllocatedTaskResources{ Memory: structs.AllocatedMemoryResources{ @@ -1136,6 +1138,82 @@ func TestDockerDriver_CreateContainerConfig(t *testing.T) { require.Equal(t, "org/repo:0.1", c.Config.Image) require.EqualValues(t, opt, c.HostConfig.StorageOpt) } + +func TestDockerDriver_CreateContainerConfigWithRuntimes(t *testing.T) { + if !tu.IsTravis() { + t.Parallel() + } + if !testutil.DockerIsConnected(t) { + t.Skip("Docker not connected") + } + if runtime.GOOS != "linux" { + t.Skip("nvidia plugin supports only linux") + } + testCases := []struct { + description string + gpuRuntimeSet bool + expectToReturnError bool + expectedRuntime string + nvidiaDevicesProvided bool + }{ + { + description: "gpu devices are provided, docker driver was able to detect nvidia-runtime 1", + gpuRuntimeSet: true, + expectToReturnError: false, + expectedRuntime: "nvidia", + nvidiaDevicesProvided: true, + }, + { + description: "gpu devices are provided, docker driver was able to detect nvidia-runtime 2", + gpuRuntimeSet: true, + expectToReturnError: false, + expectedRuntime: "nvidia-runtime-modified-name", + nvidiaDevicesProvided: true, + }, + { + description: "no gpu devices provided - no runtime should be set", + gpuRuntimeSet: true, + expectToReturnError: false, + expectedRuntime: "nvidia", + nvidiaDevicesProvided: false, + }, + { + description: "no gpuRuntime supported by docker driver", + gpuRuntimeSet: false, + expectToReturnError: true, + expectedRuntime: "nvidia", + nvidiaDevicesProvided: true, + }, + } + for _, testCase := range testCases { + t.Run(testCase.description, func(t *testing.T) { + task, cfg, _ := dockerTask(t) + + dh := dockerDriverHarness(t, nil) + driver := dh.Impl().(*Driver) + + driver.gpuRuntime = testCase.gpuRuntimeSet + driver.config.GPURuntimeName = testCase.expectedRuntime + if testCase.nvidiaDevicesProvided { + task.DeviceEnv[nvidia.NvidiaVisibleDevices] = "GPU_UUID_1" + } + + c, err := driver.createContainerConfig(task, cfg, "org/repo:0.1") + if testCase.expectToReturnError { + require.NotNil(t, err) + } else { + require.NoError(t, err) + if testCase.nvidiaDevicesProvided { + require.Equal(t, testCase.expectedRuntime, c.HostConfig.Runtime) + } else { + // no nvidia devices provided -> no point to use nvidia runtime + require.Equal(t, "", c.HostConfig.Runtime) + } + } + }) + } +} + func TestDockerDriver_Capabilities(t *testing.T) { if !tu.IsTravis() { t.Parallel() diff --git a/drivers/docker/fingerprint.go b/drivers/docker/fingerprint.go index d20550153..acdad87fc 100644 --- a/drivers/docker/fingerprint.go +++ b/drivers/docker/fingerprint.go @@ -2,6 +2,8 @@ package docker import ( "context" + "sort" + "strings" "time" "github.com/hashicorp/nomad/plugins/drivers" @@ -88,5 +90,23 @@ func (d *Driver) buildFingerprint() *drivers.Fingerprint { } } + if dockerInfo, err := client.Info(); err != nil { + d.logger.Warn("failed to get Docker system info", "error", err) + } else { + runtimeNames := make([]string, 0, len(dockerInfo.Runtimes)) + for name := range dockerInfo.Runtimes { + if d.config.GPURuntimeName == name { + // Nvidia runtime is detected by Docker. + // It makes possible to run GPU workloads using Docker driver on this host. + d.gpuRuntime = true + } + runtimeNames = append(runtimeNames, name) + } + sort.Strings(runtimeNames) + + fp.Attributes["runtimes"] = pstructs.NewStringAttribute( + strings.Join(runtimeNames, ",")) + } + return fp } diff --git a/vendor/github.com/docker/docker/LICENSE b/vendor/github.com/docker/docker/LICENSE index 9c8e20ab8..6d8d58fb6 100644 --- a/vendor/github.com/docker/docker/LICENSE +++ b/vendor/github.com/docker/docker/LICENSE @@ -176,7 +176,7 @@ END OF TERMS AND CONDITIONS - Copyright 2013-2017 Docker, Inc. + Copyright 2013-2018 Docker, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/docker/docker/api/types/configs.go b/vendor/github.com/docker/docker/api/types/configs.go index f6537a27f..178e911a7 100644 --- a/vendor/github.com/docker/docker/api/types/configs.go +++ b/vendor/github.com/docker/docker/api/types/configs.go @@ -55,3 +55,10 @@ type PluginEnableConfig struct { type PluginDisableConfig struct { ForceDisable bool } + +// NetworkListConfig stores the options available for listing networks +type NetworkListConfig struct { + // TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here + Detailed bool + Verbose bool +} diff --git a/vendor/github.com/docker/docker/api/types/container/host_config.go b/vendor/github.com/docker/docker/api/types/container/host_config.go index 4ef26fa6c..44bdfec96 100644 --- a/vendor/github.com/docker/docker/api/types/container/host_config.go +++ b/vendor/github.com/docker/docker/api/types/container/host_config.go @@ -329,6 +329,7 @@ type Resources struct { DeviceCgroupRules []string // List of rule to be added to the device cgroup DiskQuota int64 // Disk limit (in bytes) KernelMemory int64 // Kernel memory limit (in bytes) + KernelMemoryTCP int64 // Hard limit for kernel TCP buffer memory (in bytes) MemoryReservation int64 // Memory soft limit (in bytes) MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap MemorySwappiness *int64 // Tuning container memory swappiness behaviour diff --git a/vendor/github.com/docker/docker/api/types/filters/parse.go b/vendor/github.com/docker/docker/api/types/filters/parse.go index a41e3d8d9..d8f19ae22 100644 --- a/vendor/github.com/docker/docker/api/types/filters/parse.go +++ b/vendor/github.com/docker/docker/api/types/filters/parse.go @@ -323,6 +323,22 @@ func (args Args) WalkValues(field string, op func(value string) error) error { return nil } +// Clone returns a copy of args. +func (args Args) Clone() (newArgs Args) { + newArgs.fields = make(map[string]map[string]bool, len(args.fields)) + for k, m := range args.fields { + var mm map[string]bool + if m != nil { + mm = make(map[string]bool, len(m)) + for kk, v := range m { + mm[kk] = v + } + } + newArgs.fields[k] = mm + } + return newArgs +} + func deprecatedArgs(d map[string][]string) map[string]map[string]bool { m := map[string]map[string]bool{} for k, v := range d { diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go index 3fef974df..ab4446b38 100644 --- a/vendor/github.com/docker/docker/api/types/mount/mount.go +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -79,7 +79,8 @@ const ( // BindOptions defines options specific to mounts of type "bind". type BindOptions struct { - Propagation Propagation `json:",omitempty"` + Propagation Propagation `json:",omitempty"` + NonRecursive bool `json:",omitempty"` } // VolumeOptions represents the options for a mount of type volume. diff --git a/vendor/github.com/docker/docker/api/types/network/network.go b/vendor/github.com/docker/docker/api/types/network/network.go index 761d0b34f..ccb448f23 100644 --- a/vendor/github.com/docker/docker/api/types/network/network.go +++ b/vendor/github.com/docker/docker/api/types/network/network.go @@ -1,4 +1,8 @@ package network // import "github.com/docker/docker/api/types/network" +import ( + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/errdefs" +) // Address represents an IP address type Address struct { @@ -106,3 +110,17 @@ type NetworkingConfig struct { type ConfigReference struct { Network string } + +var acceptedFilters = map[string]bool{ + "driver": true, + "type": true, + "name": true, + "id": true, + "label": true, + "scope": true, +} + +// ValidateFilters validates the list of filter args with the available filters. +func ValidateFilters(filter filters.Args) error { + return errdefs.InvalidParameter(filter.Validate(acceptedFilters)) +} diff --git a/vendor/github.com/docker/docker/api/types/stats.go b/vendor/github.com/docker/docker/api/types/stats.go index 60175c061..20daebed1 100644 --- a/vendor/github.com/docker/docker/api/types/stats.go +++ b/vendor/github.com/docker/docker/api/types/stats.go @@ -120,7 +120,7 @@ type NetworkStats struct { RxBytes uint64 `json:"rx_bytes"` // Packets received. Windows and Linux. RxPackets uint64 `json:"rx_packets"` - // Received errors. Not used on Windows. Note that we dont `omitempty` this + // Received errors. Not used on Windows. Note that we don't `omitempty` this // field as it is expected in the >=v1.21 API stats structure. RxErrors uint64 `json:"rx_errors"` // Incoming packets dropped. Windows and Linux. @@ -129,7 +129,7 @@ type NetworkStats struct { TxBytes uint64 `json:"tx_bytes"` // Packets sent. Windows and Linux. TxPackets uint64 `json:"tx_packets"` - // Sent errors. Not used on Windows. Note that we dont `omitempty` this + // Sent errors. Not used on Windows. Note that we don't `omitempty` this // field as it is expected in the >=v1.21 API stats structure. TxErrors uint64 `json:"tx_errors"` // Outgoing packets dropped. Windows and Linux. diff --git a/vendor/github.com/docker/docker/api/types/swarm/container.go b/vendor/github.com/docker/docker/api/types/swarm/container.go index 151211ff5..e12f09837 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/container.go +++ b/vendor/github.com/docker/docker/api/types/swarm/container.go @@ -71,4 +71,5 @@ type ContainerSpec struct { Secrets []*SecretReference `json:",omitempty"` Configs []*ConfigReference `json:",omitempty"` Isolation container.Isolation `json:",omitempty"` + Sysctls map[string]string `json:",omitempty"` } diff --git a/vendor/github.com/docker/docker/api/types/swarm/swarm.go b/vendor/github.com/docker/docker/api/types/swarm/swarm.go index 1b111d725..484cd0be7 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/swarm.go +++ b/vendor/github.com/docker/docker/api/types/swarm/swarm.go @@ -1,6 +1,8 @@ package swarm // import "github.com/docker/docker/api/types/swarm" -import "time" +import ( + "time" +) // ClusterInfo represents info about the cluster for outputting in "info" // it contains the same information as "Swarm", but without the JoinTokens @@ -10,6 +12,9 @@ type ClusterInfo struct { Spec Spec TLSInfo TLSInfo RootRotationInProgress bool + DefaultAddrPool []string + SubnetSize uint32 + DataPathPort uint32 } // Swarm represents a swarm. @@ -149,10 +154,13 @@ type InitRequest struct { ListenAddr string AdvertiseAddr string DataPathAddr string + DataPathPort uint32 ForceNewCluster bool Spec Spec AutoLockManagers bool Availability NodeAvailability + DefaultAddrPool []string + SubnetSize uint32 } // JoinRequest is the request used to join a swarm. diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go index 06c0ca3a6..2accda9d0 100644 --- a/vendor/github.com/docker/docker/api/types/types.go +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -102,9 +102,10 @@ type ContainerStats struct { // Ping contains response of Engine API: // GET "/_ping" type Ping struct { - APIVersion string - OSType string - Experimental bool + APIVersion string + OSType string + Experimental bool + BuilderVersion BuilderVersion } // ComponentVersion describes the version information for a specific component. @@ -157,6 +158,7 @@ type Info struct { MemoryLimit bool SwapLimit bool KernelMemory bool + KernelMemoryTCP bool CPUCfsPeriod bool `json:"CpuCfsPeriod"` CPUCfsQuota bool `json:"CpuCfsQuota"` CPUShares bool @@ -204,6 +206,8 @@ type Info struct { RuncCommit Commit InitCommit Commit SecurityOptions []string + ProductLicense string `json:",omitempty"` + Warnings []string } // KeyValue holds a key/value pair @@ -540,6 +544,7 @@ type ImagesPruneReport struct { // BuildCachePruneReport contains the response for Engine API: // POST "/build/prune" type BuildCachePruneReport struct { + CachesDeleted []string SpaceReclaimed uint64 } @@ -589,14 +594,21 @@ type BuildResult struct { // BuildCache contains information about a build cache record type BuildCache struct { - ID string - Mutable bool - InUse bool - Size int64 - + ID string + Parent string + Type string + Description string + InUse bool + Shared bool + Size int64 CreatedAt time.Time LastUsedAt *time.Time UsageCount int - Parent string - Description string +} + +// BuildCachePruneOptions hold parameters to prune the build cache +type BuildCachePruneOptions struct { + All bool + KeepStorage int64 + Filters filters.Args } diff --git a/vendor/github.com/docker/docker/pkg/archive/archive.go b/vendor/github.com/docker/docker/pkg/archive/archive.go index daddebded..32132fcfe 100644 --- a/vendor/github.com/docker/docker/pkg/archive/archive.go +++ b/vendor/github.com/docker/docker/pkg/archive/archive.go @@ -52,7 +52,7 @@ type ( NoLchown bool UIDMaps []idtools.IDMap GIDMaps []idtools.IDMap - ChownOpts *idtools.IDPair + ChownOpts *idtools.Identity IncludeSourceDir bool // WhiteoutFormat is the expected on disk format for whiteout files. // This format will be converted to the standard format on pack @@ -72,13 +72,13 @@ type ( // this package with a pluggable Untar function. Also, to facilitate the passing of specific id // mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations. type Archiver struct { - Untar func(io.Reader, string, *TarOptions) error - IDMappingsVar *idtools.IDMappings + Untar func(io.Reader, string, *TarOptions) error + IDMapping *idtools.IdentityMapping } -// NewDefaultArchiver returns a new Archiver without any IDMappings +// NewDefaultArchiver returns a new Archiver without any IdentityMapping func NewDefaultArchiver() *Archiver { - return &Archiver{Untar: Untar, IDMappingsVar: &idtools.IDMappings{}} + return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}} } // breakoutError is used to differentiate errors related to breaking out @@ -367,11 +367,7 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro hdr.AccessTime = time.Time{} hdr.ChangeTime = time.Time{} hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi) - name, err = canonicalTarName(name, fi.IsDir()) - if err != nil { - return nil, fmt.Errorf("tar: cannot canonicalize path: %v", err) - } - hdr.Name = name + hdr.Name = canonicalTarName(name, fi.IsDir()) if err := setHeaderForSpecialDevice(hdr, name, fi.Sys()); err != nil { return nil, err } @@ -424,9 +420,9 @@ type tarAppender struct { Buffer *bufio.Writer // for hardlink mapping - SeenFiles map[uint64]string - IDMappings *idtools.IDMappings - ChownOpts *idtools.IDPair + SeenFiles map[uint64]string + IdentityMapping *idtools.IdentityMapping + ChownOpts *idtools.Identity // For packing and unpacking whiteout files in the // non standard format. The whiteout files defined @@ -435,29 +431,26 @@ type tarAppender struct { WhiteoutConverter tarWhiteoutConverter } -func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender { +func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender { return &tarAppender{ - SeenFiles: make(map[uint64]string), - TarWriter: tar.NewWriter(writer), - Buffer: pools.BufioWriter32KPool.Get(nil), - IDMappings: idMapping, - ChownOpts: chownOpts, + SeenFiles: make(map[uint64]string), + TarWriter: tar.NewWriter(writer), + Buffer: pools.BufioWriter32KPool.Get(nil), + IdentityMapping: idMapping, + ChownOpts: chownOpts, } } // canonicalTarName provides a platform-independent and consistent posix-style //path for files and directories to be archived regardless of the platform. -func canonicalTarName(name string, isDir bool) (string, error) { - name, err := CanonicalTarNameForPath(name) - if err != nil { - return "", err - } +func canonicalTarName(name string, isDir bool) string { + name = CanonicalTarNameForPath(name) // suffix with '/' for directories if isDir && !strings.HasSuffix(name, "/") { name += "/" } - return name, nil + return name } // addTarFile adds to the tar archive a file from `path` as `name` @@ -509,14 +502,12 @@ func (ta *tarAppender) addTarFile(path, name string) error { //handle re-mapping container ID mappings back to host ID mappings before //writing tar headers/files. We skip whiteout files because they were written //by the kernel and already have proper ownership relative to the host - if !isOverlayWhiteout && - !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && - !ta.IDMappings.Empty() { + if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() { fileIDPair, err := getFileUIDGID(fi.Sys()) if err != nil { return err } - hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair) + hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIDPair) if err != nil { return err } @@ -579,7 +570,7 @@ func (ta *tarAppender) addTarFile(path, name string) error { return nil } -func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error { +func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.Identity, inUserns bool) error { // hdr.Mode is in linux format, which we can use for sycalls, // but for os.Foo() calls we need the mode converted to os.FileMode, // so use hdrInfo.Mode() (they differ for e.g. setuid bits) @@ -659,7 +650,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L // Lchown is not supported on Windows. if Lchown && runtime.GOOS != "windows" { if chownOpts == nil { - chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid} + chownOpts = &idtools.Identity{UID: hdr.Uid, GID: hdr.Gid} } if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil { return err @@ -669,11 +660,13 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L var errors []string for key, value := range hdr.Xattrs { if err := system.Lsetxattr(path, key, []byte(value), 0); err != nil { - if err == syscall.ENOTSUP { + if err == syscall.ENOTSUP || err == syscall.EPERM { // We ignore errors here because not all graphdrivers support // xattrs *cough* old versions of AUFS *cough*. However only // ENOTSUP should be emitted in that case, otherwise we still // bail. + // EPERM occurs if modifying xattrs is not allowed. This can + // happen when running in userns with restrictions (ChromeOS). errors = append(errors, err.Error()) continue } @@ -908,8 +901,8 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err defer pools.BufioReader32KPool.Put(trBuf) var dirs []*tar.Header - idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) - rootIDs := idMappings.RootPair() + idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) + rootIDs := idMapping.RootPair() whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat) // Iterate through the files in the archive. @@ -988,7 +981,7 @@ loop: } trBuf.Reset(tr) - if err := remapIDs(idMappings, hdr); err != nil { + if err := remapIDs(idMapping, hdr); err != nil { return err } @@ -1075,8 +1068,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error { } defer archive.Close() options := &TarOptions{ - UIDMaps: archiver.IDMappingsVar.UIDs(), - GIDMaps: archiver.IDMappingsVar.GIDs(), + UIDMaps: archiver.IDMapping.UIDs(), + GIDMaps: archiver.IDMapping.GIDs(), } return archiver.Untar(archive, dst, options) } @@ -1089,8 +1082,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error { } defer archive.Close() options := &TarOptions{ - UIDMaps: archiver.IDMappingsVar.UIDs(), - GIDMaps: archiver.IDMappingsVar.GIDs(), + UIDMaps: archiver.IDMapping.UIDs(), + GIDMaps: archiver.IDMapping.GIDs(), } return archiver.Untar(archive, dst, options) } @@ -1111,7 +1104,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error { // if this Archiver is set up with ID mapping we need to create // the new destination directory with the remapped root UID/GID pair // as owner - rootIDs := archiver.IDMappingsVar.RootPair() + rootIDs := archiver.IDMapping.RootPair() // Create dst, copy src's content into it logrus.Debugf("Creating dest directory: %s", dst) if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil { @@ -1171,7 +1164,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) { hdr.Name = filepath.Base(dst) hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode))) - if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil { + if err := remapIDs(archiver.IDMapping, hdr); err != nil { return err } @@ -1199,13 +1192,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) { return err } -// IDMappings returns the IDMappings of the archiver. -func (archiver *Archiver) IDMappings() *idtools.IDMappings { - return archiver.IDMappingsVar +// IdentityMapping returns the IdentityMapping of the archiver. +func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping { + return archiver.IDMapping } -func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error { - ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}) +func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error { + ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid}) hdr.Uid, hdr.Gid = ids.UID, ids.GID return err } diff --git a/vendor/github.com/docker/docker/pkg/archive/archive_unix.go b/vendor/github.com/docker/docker/pkg/archive/archive_unix.go index e81076c17..1eec912b7 100644 --- a/vendor/github.com/docker/docker/pkg/archive/archive_unix.go +++ b/vendor/github.com/docker/docker/pkg/archive/archive_unix.go @@ -32,8 +32,8 @@ func getWalkRoot(srcPath string, include string) string { // CanonicalTarNameForPath returns platform-specific filepath // to canonical posix-style path for tar archival. p is relative // path. -func CanonicalTarNameForPath(p string) (string, error) { - return p, nil // already unix-style +func CanonicalTarNameForPath(p string) string { + return p // already unix-style } // chmodTarEntry is used to adjust the file permissions used in tar header based @@ -68,13 +68,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) { return } -func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { +func getFileUIDGID(stat interface{}) (idtools.Identity, error) { s, ok := stat.(*syscall.Stat_t) if !ok { - return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t") + return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t") } - return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil + return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil } // handleTarTypeBlockCharFifo is an OS-specific helper function used by diff --git a/vendor/github.com/docker/docker/pkg/archive/archive_windows.go b/vendor/github.com/docker/docker/pkg/archive/archive_windows.go index 69aadd823..ae6b89fd7 100644 --- a/vendor/github.com/docker/docker/pkg/archive/archive_windows.go +++ b/vendor/github.com/docker/docker/pkg/archive/archive_windows.go @@ -2,10 +2,8 @@ package archive // import "github.com/docker/docker/pkg/archive" import ( "archive/tar" - "fmt" "os" "path/filepath" - "strings" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/longpath" @@ -26,16 +24,8 @@ func getWalkRoot(srcPath string, include string) string { // CanonicalTarNameForPath returns platform-specific filepath // to canonical posix-style path for tar archival. p is relative // path. -func CanonicalTarNameForPath(p string) (string, error) { - // windows: convert windows style relative path with backslashes - // into forward slashes. Since windows does not allow '/' or '\' - // in file names, it is mostly safe to replace however we must - // check just in case - if strings.Contains(p, "/") { - return "", fmt.Errorf("Windows path contains forward slash: %s", p) - } - return strings.Replace(p, string(os.PathSeparator), "/", -1), nil - +func CanonicalTarNameForPath(p string) string { + return filepath.ToSlash(p) } // chmodTarEntry is used to adjust the file permissions used in tar header based @@ -71,7 +61,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { return nil } -func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { +func getFileUIDGID(stat interface{}) (idtools.Identity, error) { // no notion of file ownership mapping yet on Windows - return idtools.IDPair{UID: 0, GID: 0}, nil + return idtools.Identity{UID: 0, GID: 0}, nil } diff --git a/vendor/github.com/docker/docker/pkg/archive/changes.go b/vendor/github.com/docker/docker/pkg/archive/changes.go index 43734db5b..aedb91b03 100644 --- a/vendor/github.com/docker/docker/pkg/archive/changes.go +++ b/vendor/github.com/docker/docker/pkg/archive/changes.go @@ -63,12 +63,16 @@ func (c changesByPath) Less(i, j int) bool { return c[i].Path < c[j].Path } func (c changesByPath) Len() int { return len(c) } func (c changesByPath) Swap(i, j int) { c[j], c[i] = c[i], c[j] } -// Gnu tar and the go tar writer don't have sub-second mtime -// precision, which is problematic when we apply changes via tar -// files, we handle this by comparing for exact times, *or* same +// Gnu tar doesn't have sub-second mtime precision. The go tar +// writer (1.10+) does when using PAX format, but we round times to seconds +// to ensure archives have the same hashes for backwards compatibility. +// See https://github.com/moby/moby/pull/35739/commits/fb170206ba12752214630b269a40ac7be6115ed4. +// +// Non-sub-second is problematic when we apply changes via tar +// files. We handle this by comparing for exact times, *or* same // second count and either a or b having exactly 0 nanoseconds func sameFsTime(a, b time.Time) bool { - return a == b || + return a.Equal(b) || (a.Unix() == b.Unix() && (a.Nanosecond() == 0 || b.Nanosecond() == 0)) } diff --git a/vendor/github.com/docker/docker/pkg/archive/changes_unix.go b/vendor/github.com/docker/docker/pkg/archive/changes_unix.go index c06a209d8..06217b716 100644 --- a/vendor/github.com/docker/docker/pkg/archive/changes_unix.go +++ b/vendor/github.com/docker/docker/pkg/archive/changes_unix.go @@ -16,7 +16,13 @@ func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool { oldStat.UID() != newStat.UID() || oldStat.GID() != newStat.GID() || oldStat.Rdev() != newStat.Rdev() || - // Don't look at size for dirs, its not a good measure of change + // Don't look at size or modification time for dirs, its not a good + // measure of change. See https://github.com/moby/moby/issues/9874 + // for a description of the issue with modification time, and + // https://github.com/moby/moby/pull/11422 for the change. + // (Note that in the Windows implementation of this function, + // modification time IS taken as a change). See + // https://github.com/moby/moby/pull/37982 for more information. (oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR && (!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) { return true diff --git a/vendor/github.com/docker/docker/pkg/archive/changes_windows.go b/vendor/github.com/docker/docker/pkg/archive/changes_windows.go index 6555c0136..9906685e4 100644 --- a/vendor/github.com/docker/docker/pkg/archive/changes_windows.go +++ b/vendor/github.com/docker/docker/pkg/archive/changes_windows.go @@ -7,9 +7,13 @@ import ( ) func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool { + // Note there is slight difference between the Linux and Windows + // implementations here. Due to https://github.com/moby/moby/issues/9874, + // and the fix at https://github.com/moby/moby/pull/11422, Linux does not + // consider a change to the directory time as a change. Windows on NTFS + // does. See https://github.com/moby/moby/pull/37982 for more information. - // Don't look at size for dirs, its not a good measure of change - if oldStat.Mtim() != newStat.Mtim() || + if !sameFsTime(oldStat.Mtim(), newStat.Mtim()) || oldStat.Mode() != newStat.Mode() || oldStat.Size() != newStat.Size() && !oldStat.Mode().IsDir() { return true diff --git a/vendor/github.com/docker/docker/pkg/archive/diff.go b/vendor/github.com/docker/docker/pkg/archive/diff.go index fae4b9de0..146e21fe1 100644 --- a/vendor/github.com/docker/docker/pkg/archive/diff.go +++ b/vendor/github.com/docker/docker/pkg/archive/diff.go @@ -33,7 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } - idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) + idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) aufsTempdir := "" aufsHardlinks := make(map[string]*tar.Header) @@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, srcData = tmpFile } - if err := remapIDs(idMappings, srcHdr); err != nil { + if err := remapIDs(idMapping, srcHdr); err != nil { return 0, err } @@ -240,11 +240,13 @@ func applyLayerHandler(dest string, layer io.Reader, options *TarOptions, decomp dest = filepath.Clean(dest) // We need to be able to set any perms - oldmask, err := system.Umask(0) - if err != nil { - return 0, err + if runtime.GOOS != "windows" { + oldmask, err := system.Umask(0) + if err != nil { + return 0, err + } + defer system.Umask(oldmask) } - defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform if decompress { decompLayer, err := DecompressStream(layer) diff --git a/vendor/github.com/docker/docker/pkg/archive/example_changes.go b/vendor/github.com/docker/docker/pkg/archive/example_changes.go deleted file mode 100644 index 495db809e..000000000 --- a/vendor/github.com/docker/docker/pkg/archive/example_changes.go +++ /dev/null @@ -1,97 +0,0 @@ -// +build ignore - -// Simple tool to create an archive stream from an old and new directory -// -// By default it will stream the comparison of two temporary directories with junk files -package main - -import ( - "flag" - "fmt" - "io" - "io/ioutil" - "os" - "path" - - "github.com/docker/docker/pkg/archive" - "github.com/sirupsen/logrus" -) - -var ( - flDebug = flag.Bool("D", false, "debugging output") - flNewDir = flag.String("newdir", "", "") - flOldDir = flag.String("olddir", "", "") - log = logrus.New() -) - -func main() { - flag.Usage = func() { - fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)") - fmt.Printf("%s [OPTIONS]\n", os.Args[0]) - flag.PrintDefaults() - } - flag.Parse() - log.Out = os.Stderr - if (len(os.Getenv("DEBUG")) > 0) || *flDebug { - logrus.SetLevel(logrus.DebugLevel) - } - var newDir, oldDir string - - if len(*flNewDir) == 0 { - var err error - newDir, err = ioutil.TempDir("", "docker-test-newDir") - if err != nil { - log.Fatal(err) - } - defer os.RemoveAll(newDir) - if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil { - log.Fatal(err) - } - } else { - newDir = *flNewDir - } - - if len(*flOldDir) == 0 { - oldDir, err := ioutil.TempDir("", "docker-test-oldDir") - if err != nil { - log.Fatal(err) - } - defer os.RemoveAll(oldDir) - } else { - oldDir = *flOldDir - } - - changes, err := archive.ChangesDirs(newDir, oldDir) - if err != nil { - log.Fatal(err) - } - - a, err := archive.ExportChanges(newDir, changes) - if err != nil { - log.Fatal(err) - } - defer a.Close() - - i, err := io.Copy(os.Stdout, a) - if err != nil && err != io.EOF { - log.Fatal(err) - } - fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i) -} - -func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) { - fileData := []byte("fooo") - for n := 0; n < numberOfFiles; n++ { - fileName := fmt.Sprintf("file-%d", n) - if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil { - return 0, err - } - if makeLinks { - if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil { - return 0, err - } - } - } - totalSize := numberOfFiles * len(fileData) - return totalSize, nil -} diff --git a/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go b/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go index 28cad499a..34f1c726f 100644 --- a/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go +++ b/vendor/github.com/docker/docker/pkg/fileutils/fileutils.go @@ -106,7 +106,7 @@ func (pm *PatternMatcher) Patterns() []*Pattern { return pm.patterns } -// Pattern defines a single regexp used used to filter file paths. +// Pattern defines a single regexp used to filter file paths. type Pattern struct { cleanedPattern string dirs []string diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools.go b/vendor/github.com/docker/docker/pkg/idtools/idtools.go index d1f173a31..230422eac 100644 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools.go +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools.go @@ -37,23 +37,23 @@ const ( // MkdirAllAndChown creates a directory (include any along the path) and then modifies // ownership to the requested uid/gid. If the directory already exists, this // function will still change ownership to the requested uid/gid pair. -func MkdirAllAndChown(path string, mode os.FileMode, owner IDPair) error { - return mkdirAs(path, mode, owner.UID, owner.GID, true, true) +func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error { + return mkdirAs(path, mode, owner, true, true) } // MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid. // If the directory already exists, this function still changes ownership. // Note that unlike os.Mkdir(), this function does not return IsExist error // in case path already exists. -func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error { - return mkdirAs(path, mode, owner.UID, owner.GID, false, true) +func MkdirAndChown(path string, mode os.FileMode, owner Identity) error { + return mkdirAs(path, mode, owner, false, true) } // MkdirAllAndChownNew creates a directory (include any along the path) and then modifies // ownership ONLY of newly created directories to the requested uid/gid. If the // directories along the path exist, no change of ownership will be performed -func MkdirAllAndChownNew(path string, mode os.FileMode, owner IDPair) error { - return mkdirAs(path, mode, owner.UID, owner.GID, true, false) +func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error { + return mkdirAs(path, mode, owner, true, false) } // GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps. @@ -102,22 +102,23 @@ func toHost(contID int, idMap []IDMap) (int, error) { return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID) } -// IDPair is a UID and GID pair -type IDPair struct { +// Identity is either a UID and GID pair or a SID (but not both) +type Identity struct { UID int GID int + SID string } -// IDMappings contains a mappings of UIDs and GIDs -type IDMappings struct { +// IdentityMapping contains a mappings of UIDs and GIDs +type IdentityMapping struct { uids []IDMap gids []IDMap } -// NewIDMappings takes a requested user and group name and +// NewIdentityMapping takes a requested user and group name and // using the data from /etc/sub{uid,gid} ranges, creates the // proper uid and gid remapping ranges for that user/group pair -func NewIDMappings(username, groupname string) (*IDMappings, error) { +func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) { subuidRanges, err := parseSubuid(username) if err != nil { return nil, err @@ -133,7 +134,7 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) { return nil, fmt.Errorf("No subgid ranges found for group %q", groupname) } - return &IDMappings{ + return &IdentityMapping{ uids: createIDMap(subuidRanges), gids: createIDMap(subgidRanges), }, nil @@ -141,21 +142,21 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) { // NewIDMappingsFromMaps creates a new mapping from two slices // Deprecated: this is a temporary shim while transitioning to IDMapping -func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings { - return &IDMappings{uids: uids, gids: gids} +func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping { + return &IdentityMapping{uids: uids, gids: gids} } // RootPair returns a uid and gid pair for the root user. The error is ignored // because a root user always exists, and the defaults are correct when the uid // and gid maps are empty. -func (i *IDMappings) RootPair() IDPair { +func (i *IdentityMapping) RootPair() Identity { uid, gid, _ := GetRootUIDGID(i.uids, i.gids) - return IDPair{UID: uid, GID: gid} + return Identity{UID: uid, GID: gid} } // ToHost returns the host UID and GID for the container uid, gid. // Remapping is only performed if the ids aren't already the remapped root ids -func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) { +func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) { var err error target := i.RootPair() @@ -173,7 +174,7 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) { } // ToContainer returns the container UID and GID for the host uid and gid -func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) { +func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) { uid, err := toContainer(pair.UID, i.uids) if err != nil { return -1, -1, err @@ -183,19 +184,19 @@ func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) { } // Empty returns true if there are no id mappings -func (i *IDMappings) Empty() bool { +func (i *IdentityMapping) Empty() bool { return len(i.uids) == 0 && len(i.gids) == 0 } // UIDs return the UID mapping // TODO: remove this once everything has been refactored to use pairs -func (i *IDMappings) UIDs() []IDMap { +func (i *IdentityMapping) UIDs() []IDMap { return i.uids } // GIDs return the UID mapping // TODO: remove this once everything has been refactored to use pairs -func (i *IDMappings) GIDs() []IDMap { +func (i *IdentityMapping) GIDs() []IDMap { return i.gids } diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go index 1d87ea3bc..fb239743a 100644 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go @@ -21,11 +21,12 @@ var ( getentCmd string ) -func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { +func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error { // make an array containing the original path asked for, plus (for mkAll == true) // all path components leading up to the complete path that don't exist before we MkdirAll // so that we can chown all of them properly at the end. If chownExisting is false, we won't // chown the full directory path if it exists + var paths []string stat, err := system.Stat(path) @@ -38,7 +39,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown } // short-circuit--we were called with an existing directory and chown was requested - return lazyChown(path, ownerUID, ownerGID, stat) + return lazyChown(path, owner.UID, owner.GID, stat) } if os.IsNotExist(err) { @@ -69,7 +70,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown // even if it existed, we will chown the requested path + any subpaths that // didn't exist when we called MkdirAll for _, pathComponent := range paths { - if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil { + if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil { return err } } @@ -78,7 +79,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown // CanAccess takes a valid (existing) directory and a uid, gid pair and determines // if that uid, gid pair has access (execute bit) to the directory -func CanAccess(path string, pair IDPair) bool { +func CanAccess(path string, pair Identity) bool { statInfo, err := system.Stat(path) if err != nil { return false diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go index d72cc2892..4ae38a1b1 100644 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go @@ -6,9 +6,11 @@ import ( "github.com/docker/docker/pkg/system" ) -// Platforms such as Windows do not support the UID/GID concept. So make this -// just a wrapper around system.MkdirAll. -func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { +// This is currently a wrapper around MkdirAll, however, since currently +// permissions aren't set through this path, the identity isn't utilized. +// Ownership is handled elsewhere, but in the future could be support here +// too. +func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error { if err := system.MkdirAll(path, mode, ""); err != nil { return err } @@ -18,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown // CanAccess takes a valid (existing) directory and a uid, gid pair and determines // if that uid, gid pair has access (execute bit) to the directory // Windows does not require/support this function, so always return true -func CanAccess(path string, pair IDPair) bool { +func CanAccess(path string, identity Identity) bool { return true } diff --git a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go index 538f6637a..8a100f0bc 100644 --- a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go +++ b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go @@ -48,18 +48,22 @@ func MakeRUnbindable(mountPoint string) error { return ensureMountedAs(mountPoint, "runbindable") } -func ensureMountedAs(mountPoint, options string) error { - mounted, err := Mounted(mountPoint) +// MakeMount ensures that the file or directory given is a mount point, +// bind mounting it to itself it case it is not. +func MakeMount(mnt string) error { + mounted, err := Mounted(mnt) if err != nil { return err } - - if !mounted { - if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { - return err - } + if mounted { + return nil } - if _, err = Mounted(mountPoint); err != nil { + + return Mount(mnt, mnt, "none", "bind") +} + +func ensureMountedAs(mountPoint, options string) error { + if err := MakeMount(mountPoint); err != nil { return err } diff --git a/vendor/github.com/docker/docker/pkg/system/path_unix.go b/vendor/github.com/docker/docker/pkg/system/path_unix.go new file mode 100644 index 000000000..b0b93196a --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/path_unix.go @@ -0,0 +1,10 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +// GetLongPathName converts Windows short pathnames to full pathnames. +// For example C:\Users\ADMIN~1 --> C:\Users\Administrator. +// It is a no-op on non-Windows platforms +func GetLongPathName(path string) (string, error) { + return path, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/path_windows.go b/vendor/github.com/docker/docker/pkg/system/path_windows.go new file mode 100644 index 000000000..188f2c295 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/path_windows.go @@ -0,0 +1,24 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// GetLongPathName converts Windows short pathnames to full pathnames. +// For example C:\Users\ADMIN~1 --> C:\Users\Administrator. +// It is a no-op on non-Windows platforms +func GetLongPathName(path string) (string, error) { + // See https://groups.google.com/forum/#!topic/golang-dev/1tufzkruoTg + p := syscall.StringToUTF16(path) + b := p // GetLongPathName says we can reuse buffer + n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + if n > uint32(len(b)) { + b = make([]uint16, n) + _, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + } + return syscall.UTF16ToString(b), nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/rm.go b/vendor/github.com/docker/docker/pkg/system/rm.go index 02e4d2622..b31099180 100644 --- a/vendor/github.com/docker/docker/pkg/system/rm.go +++ b/vendor/github.com/docker/docker/pkg/system/rm.go @@ -34,7 +34,7 @@ func EnsureRemoveAll(dir string) error { for { err := os.RemoveAll(dir) if err == nil { - return err + return nil } pe, ok := err.(*os.PathError) diff --git a/vendor/github.com/docker/docker/pkg/system/syscall_windows.go b/vendor/github.com/docker/docker/pkg/system/syscall_windows.go index ee7e0256f..4ae92fa6c 100644 --- a/vendor/github.com/docker/docker/pkg/system/syscall_windows.go +++ b/vendor/github.com/docker/docker/pkg/system/syscall_windows.go @@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system" import ( "fmt" + "syscall" "unsafe" "github.com/sirupsen/logrus" "golang.org/x/sys/windows" ) +const ( + OWNER_SECURITY_INFORMATION = 0x00000001 + GROUP_SECURITY_INFORMATION = 0x00000002 + DACL_SECURITY_INFORMATION = 0x00000004 + SACL_SECURITY_INFORMATION = 0x00000008 + LABEL_SECURITY_INFORMATION = 0x00000010 + ATTRIBUTE_SECURITY_INFORMATION = 0x00000020 + SCOPE_SECURITY_INFORMATION = 0x00000040 + PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080 + ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100 + BACKUP_SECURITY_INFORMATION = 0x00010000 + PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 + PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000 + UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000 + UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 +) + +const ( + SE_UNKNOWN_OBJECT_TYPE = iota + SE_FILE_OBJECT + SE_SERVICE + SE_PRINTER + SE_REGISTRY_KEY + SE_LMSHARE + SE_KERNEL_OBJECT + SE_WINDOW_OBJECT + SE_DS_OBJECT + SE_DS_OBJECT_ALL + SE_PROVIDER_DEFINED_OBJECT + SE_WMIGUID_OBJECT + SE_REGISTRY_WOW64_32KEY +) + +const ( + SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" +) + +const ( + ContainerAdministratorSidString = "S-1-5-93-2-1" + ContainerUserSidString = "S-1-5-93-2-2" +) + var ( - ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") - procGetVersionExW = modkernel32.NewProc("GetVersionExW") - procGetProductInfo = modkernel32.NewProc("GetProductInfo") + ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") + procGetVersionExW = modkernel32.NewProc("GetVersionExW") + procGetProductInfo = modkernel32.NewProc("GetProductInfo") + procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW") + procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl") ) // OSVersion is a wrapper for Windows version information @@ -125,3 +171,23 @@ func HasWin32KSupport() bool { // APIs. return ntuserApiset.Load() == nil } + +func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) { + r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfo.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0) + if r0 != 0 { + result = syscall.Errno(r0) + } + return +} + +func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) { + r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0) + if r1 == 0 { + if e1 != 0 { + result = syscall.Errno(e1) + } else { + result = syscall.EINVAL + } + } + return +} diff --git a/vendor/github.com/docker/docker/pkg/tarsum/tarsum_spec.md b/vendor/github.com/docker/docker/pkg/tarsum/tarsum_spec.md index e7ea2abd0..89b2e49f9 100644 --- a/vendor/github.com/docker/docker/pkg/tarsum/tarsum_spec.md +++ b/vendor/github.com/docker/docker/pkg/tarsum/tarsum_spec.md @@ -227,3 +227,4 @@ with matching paths, and orders the list of file sums accordingly [3]. Joffrey F (shin-) and Guillaume J. Charmes (creack) on the initial work of the TarSum calculation. + diff --git a/vendor/github.com/docker/docker/pkg/term/term_windows.go b/vendor/github.com/docker/docker/pkg/term/term_windows.go index 64ead3c53..a3c3db131 100644 --- a/vendor/github.com/docker/docker/pkg/term/term_windows.go +++ b/vendor/github.com/docker/docker/pkg/term/term_windows.go @@ -62,13 +62,6 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { } } - if os.Getenv("ConEmuANSI") == "ON" || os.Getenv("ConsoleZVersion") != "" { - // The ConEmu and ConsoleZ terminals emulate ANSI on output streams well. - emulateStdin = true - emulateStdout = false - emulateStderr = false - } - // Temporarily use STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and // STD_ERROR_HANDLE from syscall rather than x/sys/windows as long as // go-ansiterm hasn't switch to x/sys/windows. diff --git a/vendor/github.com/docker/docker/registry/service_v2.go b/vendor/github.com/docker/docker/registry/service_v2.go index 3a56dc911..1a4c9e310 100644 --- a/vendor/github.com/docker/docker/registry/service_v2.go +++ b/vendor/github.com/docker/docker/registry/service_v2.go @@ -57,7 +57,7 @@ func (s *DefaultService) lookupV2Endpoints(hostname string) (endpoints []APIEndp Scheme: "https", Host: hostname, }, - Version: APIVersion2, + Version: APIVersion2, AllowNondistributableArtifacts: ana, TrimHostname: true, TLSConfig: tlsConfig, @@ -70,7 +70,7 @@ func (s *DefaultService) lookupV2Endpoints(hostname string) (endpoints []APIEndp Scheme: "http", Host: hostname, }, - Version: APIVersion2, + Version: APIVersion2, AllowNondistributableArtifacts: ana, TrimHostname: true, // used to check if supposed to be secure via InsecureSkipVerify diff --git a/vendor/github.com/fsouza/go-dockerclient/AUTHORS b/vendor/github.com/fsouza/go-dockerclient/AUTHORS index 592163176..4e9f7b8e8 100644 --- a/vendor/github.com/fsouza/go-dockerclient/AUTHORS +++ b/vendor/github.com/fsouza/go-dockerclient/AUTHORS @@ -4,6 +4,7 @@ Abhishek Chanda Adam Bell-Hanssen Adnan Khan Adrien Kohlbecker +Aithal Aldrin Leal Alex Dadgar Alfonso Acosta @@ -23,6 +24,7 @@ Ben Parees Benno van den Berg Bradley Cicenas Brendan Fosberry +Brett Buddin Brian Lalor Brian P. Hamachek Brian Palmer @@ -40,6 +42,7 @@ Chris Bednarski Chris Stavropoulos Christian Stewart Christophe Mourette +Clayton Coleman Clint Armstrong CMGS Colin Hebert @@ -49,12 +52,15 @@ Damon Wang Dan Williams Daniel, Dao Quang Minh Daniel Garcia +Daniel Hess Daniel Hiltgen +Daniel Nephin Daniel Tsui Darren Shepherd Dave Choi David Huie Dawn Chen +Denis Makogon Derek Petersen Dinesh Subhraveti Drew Wells @@ -62,6 +68,7 @@ Ed Elias G. Schneevoigt Erez Horev Eric Anderson +Eric Fode Eric J. Holmes Eric Mountain Erwin van Eyk @@ -69,11 +76,13 @@ Ethan Mosbaugh Ewout Prangsma Fabio Rehm Fatih Arslan +Faye Salwin Felipe Oliveira Flavia Missi Florent Aide Francisco Souza Frank Groeneveld +George MacRorie George Moura Grégoire Delattre Guilherme Rezende @@ -108,6 +117,7 @@ Kevin Xu Kim, Hirokuni Kostas Lekkas Kyle Allan +Yunhee Lee Liron Levin Lior Yankovich Liu Peng @@ -135,6 +145,7 @@ Orivej Desh Paul Bellamy Paul Morie Paul Weil +Peng Yin Peter Edge Peter Jihoon Kim Peter Teich @@ -155,6 +166,7 @@ Sam Rijs Sami Wagiaalla Samuel Archambault Samuel Karp +Sebastian Borza Seth Jennings Shane Xie Silas Sewell @@ -177,10 +189,12 @@ Tonic ttyh061 upccup Victor Marmol +Vijay Krishnan Vincenzo Prignano Vlad Alexandru Ionescu Weitao Zhou Wiliam Souza Ye Yin +Yosuke Otosu Yu, Zou Yuriy Bogdanov diff --git a/vendor/github.com/fsouza/go-dockerclient/Gopkg.toml b/vendor/github.com/fsouza/go-dockerclient/Gopkg.toml index deeb07595..726e898ad 100644 --- a/vendor/github.com/fsouza/go-dockerclient/Gopkg.toml +++ b/vendor/github.com/fsouza/go-dockerclient/Gopkg.toml @@ -3,8 +3,8 @@ version = "v0.4.5" [[constraint]] - name = "github.com/docker/docker" branch = "master" + name = "github.com/docker/docker" [[constraint]] name = "github.com/docker/go-units" @@ -12,17 +12,17 @@ [[constraint]] name = "github.com/google/go-cmp" - branch = "master" + version = "v0.2.0" [[constraint]] name = "github.com/gorilla/mux" version = "v1.5.0" -[[constraint]] - name = "golang.org/x/net" - branch = "master" - [[override]] name = "github.com/Nvveen/Gotty" source = "https://github.com/ijc25/Gotty.git" revision = "a8b993ba6abdb0e0c12b0125c603323a71c7790c" + +[[override]] + name = "github.com/docker/libnetwork" + revision = "19279f0492417475b6bfbd0aa529f73e8f178fb5" diff --git a/vendor/github.com/fsouza/go-dockerclient/LICENSE b/vendor/github.com/fsouza/go-dockerclient/LICENSE index 545174c18..fc7e73f8f 100644 --- a/vendor/github.com/fsouza/go-dockerclient/LICENSE +++ b/vendor/github.com/fsouza/go-dockerclient/LICENSE @@ -1,18 +1,19 @@ -Copyright (c) 2013-2017, go-dockerclient authors +Copyright (c) 2013-2018, go-dockerclient authors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR diff --git a/vendor/github.com/fsouza/go-dockerclient/Makefile b/vendor/github.com/fsouza/go-dockerclient/Makefile index 6ebdcf187..d03f9847f 100644 --- a/vendor/github.com/fsouza/go-dockerclient/Makefile +++ b/vendor/github.com/fsouza/go-dockerclient/Makefile @@ -2,27 +2,22 @@ all \ lint \ vet \ - fmt \ fmtcheck \ pretest \ test \ - integration \ - clean + integration all: test lint: - @ go get -v github.com/golang/lint/golint + @ go get -v golang.org/x/lint/golint [ -z "$$(golint . | grep -v 'type name will be used as docker.DockerInfo' | grep -v 'context.Context should be the first' | tee /dev/stderr)" ] vet: - go vet $$(go list ./... | grep -v vendor) - -fmt: - gofmt -s -w $$(go list ./... | grep -v vendor) + go vet ./... fmtcheck: - [ -z "$$(gofmt -s -d $$(go list ./... | grep -v vendor) | tee /dev/stderr)" ] + if [ -z "$${SKIP_FMT_CHECK}" ]; then [ -z "$$(gofmt -s -d *.go ./testing | tee /dev/stderr)" ]; fi testdeps: go get -u github.com/golang/dep/cmd/dep @@ -31,12 +26,9 @@ testdeps: pretest: testdeps lint vet fmtcheck gotest: - go test -race $$(go list ./... | grep -v vendor) + go test -race ./... test: pretest gotest integration: go test -tags docker_integration -run TestIntegration -v - -clean: - go clean ./... diff --git a/vendor/github.com/fsouza/go-dockerclient/appveyor.yml b/vendor/github.com/fsouza/go-dockerclient/appveyor.yml index 965b83e51..ec778c065 100644 --- a/vendor/github.com/fsouza/go-dockerclient/appveyor.yml +++ b/vendor/github.com/fsouza/go-dockerclient/appveyor.yml @@ -5,8 +5,8 @@ clone_folder: c:\gopath\src\github.com\fsouza\go-dockerclient environment: GOPATH: c:\gopath matrix: - - GOVERSION: 1.8.5 - - GOVERSION: 1.9.2 + - GOVERSION: 1.10.5 + - GOVERSION: 1.11.2 install: - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% - rmdir c:\go /s /q diff --git a/vendor/github.com/fsouza/go-dockerclient/auth.go b/vendor/github.com/fsouza/go-dockerclient/auth.go index 03d192b79..7bdcb6def 100644 --- a/vendor/github.com/fsouza/go-dockerclient/auth.go +++ b/vendor/github.com/fsouza/go-dockerclient/auth.go @@ -27,6 +27,22 @@ type AuthConfiguration struct { Password string `json:"password,omitempty"` Email string `json:"email,omitempty"` ServerAddress string `json:"serveraddress,omitempty"` + + // IdentityToken can be supplied with the identitytoken response of the AuthCheck call + // see https://godoc.org/github.com/docker/docker/api/types#AuthConfig + // It can be used in place of password not in conjunction with it + IdentityToken string `json:"identitytoken,omitempty"` + + // RegistryToken can be supplied with the registrytoken + RegistryToken string `json:"registrytoken,omitempty"` +} + +func (c AuthConfiguration) isEmpty() bool { + return c == AuthConfiguration{} +} + +func (c AuthConfiguration) headerKey() string { + return "X-Registry-Auth" } // AuthConfigurations represents authentication options to use for the @@ -35,15 +51,33 @@ type AuthConfigurations struct { Configs map[string]AuthConfiguration `json:"configs"` } +func (c AuthConfigurations) isEmpty() bool { + return len(c.Configs) == 0 +} + +func (c AuthConfigurations) headerKey() string { + return "X-Registry-Config" +} + // AuthConfigurations119 is used to serialize a set of AuthConfigurations // for Docker API >= 1.19. type AuthConfigurations119 map[string]AuthConfiguration +func (c AuthConfigurations119) isEmpty() bool { + return len(c) == 0 +} + +func (c AuthConfigurations119) headerKey() string { + return "X-Registry-Config" +} + // dockerConfig represents a registry authentation configuration from the // .dockercfg file. type dockerConfig struct { - Auth string `json:"auth"` - Email string `json:"email"` + Auth string `json:"auth"` + Email string `json:"email"` + IdentityToken string `json:"identitytoken"` + RegistryToken string `json:"registrytoken"` } // NewAuthConfigurationsFromFile returns AuthConfigurations from a path containing JSON @@ -128,22 +162,42 @@ func authConfigs(confs map[string]dockerConfig) (*AuthConfigurations, error) { c := &AuthConfigurations{ Configs: make(map[string]AuthConfiguration), } + for reg, conf := range confs { + if conf.Auth == "" { + continue + } data, err := base64.StdEncoding.DecodeString(conf.Auth) if err != nil { return nil, err } + userpass := strings.SplitN(string(data), ":", 2) if len(userpass) != 2 { return nil, ErrCannotParseDockercfg } - c.Configs[reg] = AuthConfiguration{ + + authConfig := AuthConfiguration{ Email: conf.Email, Username: userpass[0], Password: userpass[1], ServerAddress: reg, } + + // if identitytoken provided then zero the password and set it + if conf.IdentityToken != "" { + authConfig.Password = "" + authConfig.IdentityToken = conf.IdentityToken + } + + // if registrytoken provided then zero the password and set it + if conf.RegistryToken != "" { + authConfig.Password = "" + authConfig.RegistryToken = conf.RegistryToken + } + c.Configs[reg] = authConfig } + return c, nil } diff --git a/vendor/github.com/fsouza/go-dockerclient/client.go b/vendor/github.com/fsouza/go-dockerclient/client.go index b404953fc..581e31417 100644 --- a/vendor/github.com/fsouza/go-dockerclient/client.go +++ b/vendor/github.com/fsouza/go-dockerclient/client.go @@ -10,6 +10,7 @@ package docker import ( "bufio" "bytes" + "context" "crypto/tls" "crypto/x509" "encoding/json" @@ -32,10 +33,8 @@ import ( "github.com/docker/docker/opts" "github.com/docker/docker/pkg/homedir" - "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/stdcopy" - "golang.org/x/net/context" - "golang.org/x/net/context/ctxhttp" + "github.com/fsouza/go-dockerclient/internal/jsonmessage" ) const ( @@ -59,6 +58,7 @@ var ( apiVersion119, _ = NewAPIVersion("1.19") apiVersion124, _ = NewAPIVersion("1.24") apiVersion125, _ = NewAPIVersion("1.25") + apiVersion135, _ = NewAPIVersion("1.35") ) // APIVersion is an internal representation of a version of the Remote API. @@ -218,11 +218,19 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro eventMonitor: new(eventMonitoringState), requestedAPIVersion: requestedAPIVersion, } - c.initializeNativeClient() + c.initializeNativeClient(defaultTransport) return c, nil } -// NewVersionnedTLSClient has been DEPRECATED, please use NewVersionedTLSClient. +// WithTransport replaces underlying HTTP client of Docker Client by accepting +// a function that returns pointer to a transport object. +func (c *Client) WithTransport(trFunc func() *http.Transport) { + c.initializeNativeClient(trFunc) +} + +// NewVersionnedTLSClient is like NewVersionedClient, but with ann extra n. +// +// Deprecated: Use NewVersionedTLSClient instead. func NewVersionnedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) { return NewVersionedTLSClient(endpoint, cert, key, ca, apiVersionString) } @@ -339,7 +347,7 @@ func NewVersionedTLSClientFromBytes(endpoint string, certPEMBlock, keyPEMBlock, eventMonitor: new(eventMonitoringState), requestedAPIVersion: requestedAPIVersion, } - c.initializeNativeClient() + c.initializeNativeClient(defaultTransport) return c, nil } @@ -469,7 +477,7 @@ func (c *Client) do(method, path string, doOptions doOptions) (*http.Response, e ctx = context.Background() } - resp, err := ctxhttp.Do(ctx, c.HTTPClient, req) + resp, err := c.HTTPClient.Do(req.WithContext(ctx)) if err != nil { if strings.Contains(err.Error(), "connection refused") { return nil, ErrConnectionRefused @@ -585,7 +593,7 @@ func (c *Client) stream(method, path string, streamOptions streamOptions) error return chooseError(subCtx, err) } } else { - if resp, err = ctxhttp.Do(subCtx, c.HTTPClient, req); err != nil { + if resp, err = c.HTTPClient.Do(req.WithContext(subCtx)); err != nil { if strings.Contains(err.Error(), "connection refused") { return ErrConnectionRefused } @@ -909,6 +917,10 @@ func addQueryStringValue(items url.Values, key string, v reflect.Value) { if v.Int() > 0 { items.Add(key, strconv.FormatInt(v.Int(), 10)) } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if v.Uint() > 0 { + items.Add(key, strconv.FormatUint(v.Uint(), 10)) + } case reflect.Float32, reflect.Float64: if v.Float() > 0 { items.Add(key, strconv.FormatFloat(v.Float(), 'f', -1, 64)) @@ -946,12 +958,20 @@ type Error struct { } func newError(resp *http.Response) *Error { + type ErrMsg struct { + Message string `json:"message"` + } defer resp.Body.Close() data, err := ioutil.ReadAll(resp.Body) if err != nil { return &Error{Status: resp.StatusCode, Message: fmt.Sprintf("cannot read body, err: %v", err)} } - return &Error{Status: resp.StatusCode, Message: string(data)} + var emsg ErrMsg + err = json.Unmarshal(data, &emsg) + if err != nil { + return &Error{Status: resp.StatusCode, Message: string(data)} + } + return &Error{Status: resp.StatusCode, Message: emsg.Message} } func (e *Error) Error() string { diff --git a/vendor/github.com/fsouza/go-dockerclient/client_unix.go b/vendor/github.com/fsouza/go-dockerclient/client_unix.go index ab73cf2b0..57d7904ea 100644 --- a/vendor/github.com/fsouza/go-dockerclient/client_unix.go +++ b/vendor/github.com/fsouza/go-dockerclient/client_unix.go @@ -9,21 +9,24 @@ package docker import ( "context" "net" + "net/http" ) // initializeNativeClient initializes the native Unix domain socket client on // Unix-style operating systems -func (c *Client) initializeNativeClient() { +func (c *Client) initializeNativeClient(trFunc func() *http.Transport) { if c.endpointURL.Scheme != unixProtocol { return } - socketPath := c.endpointURL.Path - tr := defaultTransport() + sockPath := c.endpointURL.Path + + tr := trFunc() + tr.Dial = func(network, addr string) (net.Conn, error) { - return c.Dialer.Dial(unixProtocol, socketPath) + return c.Dialer.Dial(unixProtocol, sockPath) } tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { - return c.Dialer.Dial(unixProtocol, socketPath) + return c.Dialer.Dial(unixProtocol, sockPath) } c.HTTPClient.Transport = tr } diff --git a/vendor/github.com/fsouza/go-dockerclient/client_windows.go b/vendor/github.com/fsouza/go-dockerclient/client_windows.go index c9ecc187d..8e7b457d7 100644 --- a/vendor/github.com/fsouza/go-dockerclient/client_windows.go +++ b/vendor/github.com/fsouza/go-dockerclient/client_windows.go @@ -9,6 +9,7 @@ package docker import ( "context" "net" + "net/http" "time" "github.com/Microsoft/go-winio" @@ -25,7 +26,7 @@ func (p pipeDialer) Dial(network, address string) (net.Conn, error) { } // initializeNativeClient initializes the native Named Pipe client for Windows -func (c *Client) initializeNativeClient() { +func (c *Client) initializeNativeClient(trFunc func() *http.Transport) { if c.endpointURL.Scheme != namedPipeProtocol { return } @@ -34,7 +35,7 @@ func (c *Client) initializeNativeClient() { timeout := namedPipeConnectTimeout return winio.DialPipe(namedPipePath, &timeout) } - tr := defaultTransport() + tr := trFunc() tr.Dial = dialFunc tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { return dialFunc(network, addr) diff --git a/vendor/github.com/fsouza/go-dockerclient/container.go b/vendor/github.com/fsouza/go-dockerclient/container.go index f59bf38b6..b48bc2cf6 100644 --- a/vendor/github.com/fsouza/go-dockerclient/container.go +++ b/vendor/github.com/fsouza/go-dockerclient/container.go @@ -5,6 +5,7 @@ package docker import ( + "context" "encoding/json" "errors" "fmt" @@ -16,7 +17,6 @@ import ( "time" "github.com/docker/go-units" - "golang.org/x/net/context" ) // ErrContainerAlreadyExists is the error returned by CreateContainer when the @@ -303,6 +303,7 @@ type Config struct { StopTimeout int `json:"StopTimeout,omitempty" yaml:"StopTimeout,omitempty" toml:"StopTimeout,omitempty"` Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"` Cmd []string `json:"Cmd" yaml:"Cmd" toml:"Cmd"` + Shell []string `json:"Shell,omitempty" yaml:"Shell,omitempty" toml:"Shell,omitempty"` Healthcheck *HealthConfig `json:"Healthcheck,omitempty" yaml:"Healthcheck,omitempty" toml:"Healthcheck,omitempty"` DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty" toml:"Dns,omitempty"` // For Docker API v1.9 and below only Image string `json:"Image,omitempty" yaml:"Image,omitempty" toml:"Image,omitempty"` @@ -753,7 +754,7 @@ type HostConfig struct { MemoryReservation int64 `json:"MemoryReservation,omitempty" yaml:"MemoryReservation,omitempty" toml:"MemoryReservation,omitempty"` KernelMemory int64 `json:"KernelMemory,omitempty" yaml:"KernelMemory,omitempty" toml:"KernelMemory,omitempty"` MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty" toml:"MemorySwap,omitempty"` - MemorySwappiness int64 `json:"MemorySwappiness" yaml:"MemorySwappiness" toml:"MemorySwappiness"` + MemorySwappiness int64 `json:"MemorySwappiness,omitempty" yaml:"MemorySwappiness,omitempty" toml:"MemorySwappiness,omitempty"` CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty" toml:"CpuShares,omitempty"` CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty" toml:"Cpuset,omitempty"` CPUSetCPUs string `json:"CpusetCpus,omitempty" yaml:"CpusetCpus,omitempty" toml:"CpusetCpus,omitempty"` @@ -787,6 +788,7 @@ type HostConfig struct { IOMaximumIOps int64 `json:"IOMaximumIOps,omitempty" yaml:"IOMaximumIOps,omitempty"` Mounts []HostMount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` Init bool `json:",omitempty" yaml:",omitempty"` + Runtime string `json:"Runtime,omitempty" yaml:"Runtime,omitempty" toml:"Runtime,omitempty"` } // NetworkingConfig represents the container's networking configuration for each of its interfaces @@ -1052,6 +1054,7 @@ type CPUStats struct { UsageInKernelmode uint64 `json:"usage_in_kernelmode,omitempty" yaml:"usage_in_kernelmode,omitempty" toml:"usage_in_kernelmode,omitempty"` } `json:"cpu_usage,omitempty" yaml:"cpu_usage,omitempty" toml:"cpu_usage,omitempty"` SystemCPUUsage uint64 `json:"system_cpu_usage,omitempty" yaml:"system_cpu_usage,omitempty" toml:"system_cpu_usage,omitempty"` + OnlineCPUs uint64 `json:"online_cpus,omitempty" yaml:"online_cpus,omitempty" toml:"online_cpus,omitempty"` ThrottlingData struct { Periods uint64 `json:"periods,omitempty"` ThrottledPeriods uint64 `json:"throttled_periods,omitempty"` @@ -1187,10 +1190,18 @@ func (c *Client) KillContainer(opts KillContainerOptions) error { path := "/containers/" + opts.ID + "/kill" + "?" + queryString(opts) resp, err := c.do("POST", path, doOptions{context: opts.Context}) if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return &NoSuchContainer{ID: opts.ID} + e, ok := err.(*Error) + if !ok { + return err + } + switch e.Status { + case http.StatusNotFound: + return &NoSuchContainer{ID: opts.ID} + case http.StatusConflict: + return &ContainerNotRunning{ID: opts.ID} + default: + return err } - return err } resp.Body.Close() return nil @@ -1278,9 +1289,10 @@ func (c *Client) DownloadFromContainer(id string, opts DownloadFromContainerOpti }) } -// CopyFromContainerOptions has been DEPRECATED, please use DownloadFromContainerOptions along with DownloadFromContainer. +// CopyFromContainerOptions contains the set of options used for copying +// files from a container. // -// See https://goo.gl/nWk2YQ for more details. +// Deprecated: Use DownloadFromContainerOptions and DownloadFromContainer instead. type CopyFromContainerOptions struct { OutputStream io.Writer `json:"-"` Container string `json:"-"` @@ -1288,9 +1300,9 @@ type CopyFromContainerOptions struct { Context context.Context `json:"-"` } -// CopyFromContainer has been DEPRECATED, please use DownloadFromContainerOptions along with DownloadFromContainer. +// CopyFromContainer copies files from a container. // -// See https://goo.gl/nWk2YQ for more details. +// Deprecated: Use DownloadFromContainer and DownloadFromContainer instead. func (c *Client) CopyFromContainer(opts CopyFromContainerOptions) error { if opts.Container == "" { return &NoSuchContainer{ID: opts.Container} diff --git a/vendor/github.com/fsouza/go-dockerclient/env.go b/vendor/github.com/fsouza/go-dockerclient/env.go index 13fedfb17..0f2e72f11 100644 --- a/vendor/github.com/fsouza/go-dockerclient/env.go +++ b/vendor/github.com/fsouza/go-dockerclient/env.go @@ -156,7 +156,7 @@ func (env *Env) SetAuto(key string, value interface{}) { // Map returns the map representation of the env. func (env *Env) Map() map[string]string { - if len(*env) == 0 { + if env == nil || len(*env) == 0 { return nil } m := make(map[string]string) diff --git a/vendor/github.com/fsouza/go-dockerclient/event.go b/vendor/github.com/fsouza/go-dockerclient/event.go index 21c0584f0..18ae5d5a6 100644 --- a/vendor/github.com/fsouza/go-dockerclient/event.go +++ b/vendor/github.com/fsouza/go-dockerclient/event.go @@ -195,10 +195,25 @@ func (eventState *eventMonitoringState) disableEventMonitoring() error { } func (eventState *eventMonitoringState) monitorEvents(c *Client) { + const ( + noListenersTimeout = 5 * time.Second + noListenersInterval = 10 * time.Millisecond + noListenersMaxTries = noListenersTimeout / noListenersInterval + ) + var err error - for eventState.noListeners() { + for i := time.Duration(0); i < noListenersMaxTries && eventState.noListeners(); i++ { time.Sleep(10 * time.Millisecond) } + + if eventState.noListeners() { + // terminate if no listener is available after 5 seconds. + // Prevents goroutine leak when RemoveEventListener is called + // right after AddEventListener. + eventState.disableEventMonitoring() + return + } + if err = eventState.connectWithRetry(c); err != nil { // terminate if connect failed eventState.disableEventMonitoring() diff --git a/vendor/github.com/fsouza/go-dockerclient/exec.go b/vendor/github.com/fsouza/go-dockerclient/exec.go index 004815309..5e7ea87f6 100644 --- a/vendor/github.com/fsouza/go-dockerclient/exec.go +++ b/vendor/github.com/fsouza/go-dockerclient/exec.go @@ -5,6 +5,7 @@ package docker import ( + "context" "encoding/json" "errors" "fmt" @@ -12,8 +13,6 @@ import ( "net/http" "net/url" "strconv" - - "golang.org/x/net/context" ) // Exec is the type representing a `docker exec` instance and containing the @@ -34,6 +33,7 @@ type CreateExecOptions struct { Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty" toml:"Cmd,omitempty"` Container string `json:"Container,omitempty" yaml:"Container,omitempty" toml:"Container,omitempty"` User string `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"` + WorkingDir string `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty" toml:"WorkingDir,omitempty"` Context context.Context `json:"-"` Privileged bool `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"` } @@ -46,6 +46,9 @@ func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) { if len(opts.Env) > 0 && c.serverAPIVersion.LessThan(apiVersion125) { return nil, errors.New("exec configuration Env is only supported in API#1.25 and above") } + if len(opts.WorkingDir) > 0 && c.serverAPIVersion.LessThan(apiVersion135) { + return nil, errors.New("exec configuration WorkingDir is only supported in API#1.35 and above") + } path := fmt.Sprintf("/containers/%s/exec", opts.Container) resp, err := c.do("POST", path, doOptions{data: opts, context: opts.Context}) if err != nil { diff --git a/vendor/github.com/fsouza/go-dockerclient/go.mod b/vendor/github.com/fsouza/go-dockerclient/go.mod new file mode 100644 index 000000000..1da4dcb88 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/go.mod @@ -0,0 +1,26 @@ +module github.com/fsouza/go-dockerclient + +require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 + github.com/Microsoft/go-winio v0.4.11 + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 + github.com/containerd/continuity v0.0.0-20181001140422-bd77b46c8352 // indirect + github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23 + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.3.3 + github.com/docker/libnetwork v0.8.0-dev.2.0.20180608203834-19279f049241 // indirect + github.com/gogo/protobuf v1.1.1 // indirect + github.com/google/go-cmp v0.2.0 + github.com/gorilla/context v1.1.1 // indirect + github.com/gorilla/mux v1.6.2 + github.com/opencontainers/go-digest v1.0.0-rc1 // indirect + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect + github.com/pkg/errors v0.8.0 // indirect + github.com/sirupsen/logrus v1.1.0 + github.com/vishvananda/netlink v1.0.0 // indirect + github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect + golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 // indirect + golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 + gotest.tools v2.1.0+incompatible // indirect +) diff --git a/vendor/github.com/fsouza/go-dockerclient/go.sum b/vendor/github.com/fsouza/go-dockerclient/go.sum new file mode 100644 index 000000000..e12aeef79 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/go.sum @@ -0,0 +1,54 @@ +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/containerd/continuity v0.0.0-20181001140422-bd77b46c8352 h1:CdBoaTKPl60tksFVWYc5QnLWwXBcU+XcLiXx8+NcZ9o= +github.com/containerd/continuity v0.0.0-20181001140422-bd77b46c8352/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23 h1:Zl/9mUfPbYbnv895OXx9WfxPjwqSZHohuZzVcjJ5QPQ= +github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libnetwork v0.8.0-dev.2.0.20180608203834-19279f049241 h1:+ebE/hCU02srkeIg8Vp/vlUp182JapYWtXzV+bCeR2I= +github.com/docker/libnetwork v0.8.0-dev.2.0.20180608203834-19279f049241/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= +github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.1.0 h1:65VZabgUiV9ktjGM5nTq0+YurgTyX+YI2lSSfDjI+qU= +github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM= +github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 h1:Vk3wNqEZwyGyei9yq5ekj7frek2u7HUfffJ1/opblzc= +golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 h1:O33LKL7WyJgjN9CvxfTIomjIClbd/Kq86/iipowHQU0= +golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +gotest.tools v2.1.0+incompatible h1:5USw7CrJBYKqjg9R7QlA6jzqZKEAtvW82aNmsxxGPxw= +gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/vendor/github.com/fsouza/go-dockerclient/image.go b/vendor/github.com/fsouza/go-dockerclient/image.go index 011b2bd59..114ddfb8e 100644 --- a/vendor/github.com/fsouza/go-dockerclient/image.go +++ b/vendor/github.com/fsouza/go-dockerclient/image.go @@ -5,7 +5,7 @@ package docker import ( - "bytes" + "context" "encoding/base64" "encoding/json" "errors" @@ -16,8 +16,6 @@ import ( "os" "strings" "time" - - "golang.org/x/net/context" ) // APIImages represent an image returned in the ListImages call. @@ -474,6 +472,7 @@ type BuildImageOptions struct { InactivityTimeout time.Duration `qs:"-"` CgroupParent string `qs:"cgroupparent"` SecurityOpt []string `qs:"securityopt"` + Target string `gs:"target"` Context context.Context } @@ -558,7 +557,7 @@ func (c *Client) BuildImage(opts BuildImageOptions) error { }) } -func (c *Client) versionedAuthConfigs(authConfigs AuthConfigurations) interface{} { +func (c *Client) versionedAuthConfigs(authConfigs AuthConfigurations) registryAuth { if c.serverAPIVersion == nil { c.checkAPIVersion() } @@ -610,24 +609,18 @@ func isURL(u string) bool { return p.Scheme == "http" || p.Scheme == "https" } -func headersWithAuth(auths ...interface{}) (map[string]string, error) { +func headersWithAuth(auths ...registryAuth) (map[string]string, error) { var headers = make(map[string]string) for _, auth := range auths { - switch auth.(type) { - case AuthConfiguration: - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(auth); err != nil { - return nil, err - } - headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes()) - case AuthConfigurations, AuthConfigurations119: - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(auth); err != nil { - return nil, err - } - headers["X-Registry-Config"] = base64.URLEncoding.EncodeToString(buf.Bytes()) + if auth.isEmpty() { + continue } + data, err := json.Marshal(auth) + if err != nil { + return nil, err + } + headers[auth.headerKey()] = base64.URLEncoding.EncodeToString(data) } return headers, nil diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go new file mode 100644 index 000000000..7d7cf496a --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go @@ -0,0 +1,505 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "archive/tar" + "bufio" + "compress/gzip" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/docker/docker/pkg/fileutils" + "github.com/docker/docker/pkg/idtools" + "github.com/docker/docker/pkg/pools" + "github.com/docker/docker/pkg/system" + "github.com/sirupsen/logrus" +) + +const ( + // Uncompressed represents the uncompressed. + Uncompressed Compression = iota + // Bzip2 is bzip2 compression algorithm. + Bzip2 + // Gzip is gzip compression algorithm. + Gzip + // Xz is xz compression algorithm. + Xz +) + +const ( + modeISDIR = 040000 // Directory + modeISFIFO = 010000 // FIFO + modeISREG = 0100000 // Regular file + modeISLNK = 0120000 // Symbolic link + modeISBLK = 060000 // Block special file + modeISCHR = 020000 // Character special file + modeISSOCK = 0140000 // Socket +) + +// Compression is the state represents if compressed or not. +type Compression int + +// Extension returns the extension of a file that uses the specified compression algorithm. +func (compression *Compression) Extension() string { + switch *compression { + case Uncompressed: + return "tar" + case Bzip2: + return "tar.bz2" + case Gzip: + return "tar.gz" + case Xz: + return "tar.xz" + } + return "" +} + +// WhiteoutFormat is the format of whiteouts unpacked +type WhiteoutFormat int + +// TarOptions wraps the tar options. +type TarOptions struct { + IncludeFiles []string + ExcludePatterns []string + Compression Compression + NoLchown bool + UIDMaps []idtools.IDMap + GIDMaps []idtools.IDMap + ChownOpts *idtools.Identity + IncludeSourceDir bool + // WhiteoutFormat is the expected on disk format for whiteout files. + // This format will be converted to the standard format on pack + // and from the standard format on unpack. + WhiteoutFormat WhiteoutFormat + // When unpacking, specifies whether overwriting a directory with a + // non-directory is allowed and vice versa. + NoOverwriteDirNonDir bool + // For each include when creating an archive, the included name will be + // replaced with the matching name from this map. + RebaseNames map[string]string + InUserNS bool +} + +// TarWithOptions creates an archive from the directory at `path`, only including files whose relative +// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`. +func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) { + + // Fix the source path to work with long path names. This is a no-op + // on platforms other than Windows. + srcPath = fixVolumePathPrefix(srcPath) + + pm, err := fileutils.NewPatternMatcher(options.ExcludePatterns) + if err != nil { + return nil, err + } + + pipeReader, pipeWriter := io.Pipe() + + compressWriter, err := CompressStream(pipeWriter, options.Compression) + if err != nil { + return nil, err + } + + go func() { + ta := newTarAppender( + idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps), + compressWriter, + options.ChownOpts, + ) + ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat) + + defer func() { + // Make sure to check the error on Close. + if err := ta.TarWriter.Close(); err != nil { + logrus.Errorf("Can't close tar writer: %s", err) + } + if err := compressWriter.Close(); err != nil { + logrus.Errorf("Can't close compress writer: %s", err) + } + if err := pipeWriter.Close(); err != nil { + logrus.Errorf("Can't close pipe writer: %s", err) + } + }() + + // this buffer is needed for the duration of this piped stream + defer pools.BufioWriter32KPool.Put(ta.Buffer) + + // In general we log errors here but ignore them because + // during e.g. a diff operation the container can continue + // mutating the filesystem and we can see transient errors + // from this + + stat, err := os.Lstat(srcPath) + if err != nil { + return + } + + if !stat.IsDir() { + // We can't later join a non-dir with any includes because the + // 'walk' will error if "file/." is stat-ed and "file" is not a + // directory. So, we must split the source path and use the + // basename as the include. + if len(options.IncludeFiles) > 0 { + logrus.Warn("Tar: Can't archive a file with includes") + } + + dir, base := SplitPathDirEntry(srcPath) + srcPath = dir + options.IncludeFiles = []string{base} + } + + if len(options.IncludeFiles) == 0 { + options.IncludeFiles = []string{"."} + } + + seen := make(map[string]bool) + + for _, include := range options.IncludeFiles { + rebaseName := options.RebaseNames[include] + + walkRoot := getWalkRoot(srcPath, include) + filepath.Walk(walkRoot, func(filePath string, f os.FileInfo, err error) error { + if err != nil { + logrus.Errorf("Tar: Can't stat file %s to tar: %s", srcPath, err) + return nil + } + + relFilePath, err := filepath.Rel(srcPath, filePath) + if err != nil || (!options.IncludeSourceDir && relFilePath == "." && f.IsDir()) { + // Error getting relative path OR we are looking + // at the source directory path. Skip in both situations. + return nil + } + + if options.IncludeSourceDir && include == "." && relFilePath != "." { + relFilePath = strings.Join([]string{".", relFilePath}, string(filepath.Separator)) + } + + skip := false + + // If "include" is an exact match for the current file + // then even if there's an "excludePatterns" pattern that + // matches it, don't skip it. IOW, assume an explicit 'include' + // is asking for that file no matter what - which is true + // for some files, like .dockerignore and Dockerfile (sometimes) + if include != relFilePath { + skip, err = pm.Matches(relFilePath) + if err != nil { + logrus.Errorf("Error matching %s: %v", relFilePath, err) + return err + } + } + + if skip { + // If we want to skip this file and its a directory + // then we should first check to see if there's an + // excludes pattern (e.g. !dir/file) that starts with this + // dir. If so then we can't skip this dir. + + // Its not a dir then so we can just return/skip. + if !f.IsDir() { + return nil + } + + // No exceptions (!...) in patterns so just skip dir + if !pm.Exclusions() { + return filepath.SkipDir + } + + dirSlash := relFilePath + string(filepath.Separator) + + for _, pat := range pm.Patterns() { + if !pat.Exclusion() { + continue + } + if strings.HasPrefix(pat.String()+string(filepath.Separator), dirSlash) { + // found a match - so can't skip this dir + return nil + } + } + + // No matching exclusion dir so just skip dir + return filepath.SkipDir + } + + if seen[relFilePath] { + return nil + } + seen[relFilePath] = true + + // Rename the base resource. + if rebaseName != "" { + var replacement string + if rebaseName != string(filepath.Separator) { + // Special case the root directory to replace with an + // empty string instead so that we don't end up with + // double slashes in the paths. + replacement = rebaseName + } + + relFilePath = strings.Replace(relFilePath, include, replacement, 1) + } + + if err := ta.addTarFile(filePath, relFilePath); err != nil { + logrus.Errorf("Can't add file %s to tar: %s", filePath, err) + // if pipe is broken, stop writing tar stream to it + if err == io.ErrClosedPipe { + return err + } + } + return nil + }) + } + }() + + return pipeReader, nil +} + +// CompressStream compresses the dest with specified compression algorithm. +func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) { + p := pools.BufioWriter32KPool + buf := p.Get(dest) + switch compression { + case Uncompressed: + writeBufWrapper := p.NewWriteCloserWrapper(buf, buf) + return writeBufWrapper, nil + case Gzip: + gzWriter := gzip.NewWriter(dest) + writeBufWrapper := p.NewWriteCloserWrapper(buf, gzWriter) + return writeBufWrapper, nil + case Bzip2, Xz: + // archive/bzip2 does not support writing, and there is no xz support at all + // However, this is not a problem as docker only currently generates gzipped tars + return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension()) + default: + return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension()) + } +} + +type tarWhiteoutConverter interface { + ConvertWrite(*tar.Header, string, os.FileInfo) (*tar.Header, error) + ConvertRead(*tar.Header, string) (bool, error) +} + +type tarAppender struct { + TarWriter *tar.Writer + Buffer *bufio.Writer + + // for hardlink mapping + SeenFiles map[uint64]string + IdentityMapping *idtools.IdentityMapping + ChownOpts *idtools.Identity + + // For packing and unpacking whiteout files in the + // non standard format. The whiteout files defined + // by the AUFS standard are used as the tar whiteout + // standard. + WhiteoutConverter tarWhiteoutConverter +} + +func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender { + return &tarAppender{ + SeenFiles: make(map[uint64]string), + TarWriter: tar.NewWriter(writer), + Buffer: pools.BufioWriter32KPool.Get(nil), + IdentityMapping: idMapping, + ChownOpts: chownOpts, + } +} + +// addTarFile adds to the tar archive a file from `path` as `name` +func (ta *tarAppender) addTarFile(path, name string) error { + fi, err := os.Lstat(path) + if err != nil { + return err + } + + var link string + if fi.Mode()&os.ModeSymlink != 0 { + var err error + link, err = os.Readlink(path) + if err != nil { + return err + } + } + + hdr, err := FileInfoHeader(name, fi, link) + if err != nil { + return err + } + if err := ReadSecurityXattrToTarHeader(path, hdr); err != nil { + return err + } + + // if it's not a directory and has more than 1 link, + // it's hard linked, so set the type flag accordingly + if !fi.IsDir() && hasHardlinks(fi) { + inode, err := getInodeFromStat(fi.Sys()) + if err != nil { + return err + } + // a link should have a name that it links too + // and that linked name should be first in the tar archive + if oldpath, ok := ta.SeenFiles[inode]; ok { + hdr.Typeflag = tar.TypeLink + hdr.Linkname = oldpath + hdr.Size = 0 // This Must be here for the writer math to add up! + } else { + ta.SeenFiles[inode] = name + } + } + + //check whether the file is overlayfs whiteout + //if yes, skip re-mapping container ID mappings. + isOverlayWhiteout := fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 + + //handle re-mapping container ID mappings back to host ID mappings before + //writing tar headers/files. We skip whiteout files because they were written + //by the kernel and already have proper ownership relative to the host + if !isOverlayWhiteout && + !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && + !ta.IdentityMapping.Empty() { + fileIdentity, err := getFileIdentity(fi.Sys()) + if err != nil { + return err + } + hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIdentity) + if err != nil { + return err + } + } + + // explicitly override with ChownOpts + if ta.ChownOpts != nil { + hdr.Uid = ta.ChownOpts.UID + hdr.Gid = ta.ChownOpts.GID + } + + if ta.WhiteoutConverter != nil { + wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi) + if err != nil { + return err + } + + // If a new whiteout file exists, write original hdr, then + // replace hdr with wo to be written after. Whiteouts should + // always be written after the original. Note the original + // hdr may have been updated to be a whiteout with returning + // a whiteout header + if wo != nil { + if err := ta.TarWriter.WriteHeader(hdr); err != nil { + return err + } + if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 { + return fmt.Errorf("tar: cannot use whiteout for non-empty file") + } + hdr = wo + } + } + + if err := ta.TarWriter.WriteHeader(hdr); err != nil { + return err + } + + if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 { + // We use system.OpenSequential to ensure we use sequential file + // access on Windows to avoid depleting the standby list. + // On Linux, this equates to a regular os.Open. + file, err := system.OpenSequential(path) + if err != nil { + return err + } + + ta.Buffer.Reset(ta.TarWriter) + defer ta.Buffer.Reset(nil) + _, err = io.Copy(ta.Buffer, file) + file.Close() + if err != nil { + return err + } + err = ta.Buffer.Flush() + if err != nil { + return err + } + } + + return nil +} + +// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem +// to a tar header +func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error { + capability, _ := system.Lgetxattr(path, "security.capability") + if capability != nil { + hdr.Xattrs = make(map[string]string) + hdr.Xattrs["security.capability"] = string(capability) + } + return nil +} + +// FileInfoHeader creates a populated Header from fi. +// Compared to archive pkg this function fills in more information. +// Also, regardless of Go version, this function fills file type bits (e.g. hdr.Mode |= modeISDIR), +// which have been deleted since Go 1.9 archive/tar. +func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) { + hdr, err := tar.FileInfoHeader(fi, link) + if err != nil { + return nil, err + } + hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi) + name, err = canonicalTarName(name, fi.IsDir()) + if err != nil { + return nil, fmt.Errorf("tar: cannot canonicalize path: %v", err) + } + hdr.Name = name + if err := setHeaderForSpecialDevice(hdr, name, fi.Sys()); err != nil { + return nil, err + } + return hdr, nil +} + +// fillGo18FileTypeBits fills type bits which have been removed on Go 1.9 archive/tar +// https://github.com/golang/go/commit/66b5a2f +func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 { + fm := fi.Mode() + switch { + case fm.IsRegular(): + mode |= modeISREG + case fi.IsDir(): + mode |= modeISDIR + case fm&os.ModeSymlink != 0: + mode |= modeISLNK + case fm&os.ModeDevice != 0: + if fm&os.ModeCharDevice != 0 { + mode |= modeISCHR + } else { + mode |= modeISBLK + } + case fm&os.ModeNamedPipe != 0: + mode |= modeISFIFO + case fm&os.ModeSocket != 0: + mode |= modeISSOCK + } + return mode +} + +// canonicalTarName provides a platform-independent and consistent posix-style +//path for files and directories to be archived regardless of the platform. +func canonicalTarName(name string, isDir bool) (string, error) { + name, err := CanonicalTarNameForPath(name) + if err != nil { + return "", err + } + + // suffix with '/' for directories + if isDir && !strings.HasSuffix(name, "/") { + name += "/" + } + return name, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go new file mode 100644 index 000000000..9e1f3f2f1 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go @@ -0,0 +1,104 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "archive/tar" + "os" + "path/filepath" + "strings" + + "github.com/docker/docker/pkg/system" + "golang.org/x/sys/unix" +) + +const ( + // AUFSWhiteoutFormat is the default format for whiteouts + AUFSWhiteoutFormat WhiteoutFormat = iota + // OverlayWhiteoutFormat formats whiteout according to the overlay + // standard. + OverlayWhiteoutFormat +) + +func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter { + if format == OverlayWhiteoutFormat { + return overlayWhiteoutConverter{} + } + return nil +} + +type overlayWhiteoutConverter struct{} + +func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) { + // convert whiteouts to AUFS format + if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 { + // we just rename the file and make it normal + dir, filename := filepath.Split(hdr.Name) + hdr.Name = filepath.Join(dir, WhiteoutPrefix+filename) + hdr.Mode = 0600 + hdr.Typeflag = tar.TypeReg + hdr.Size = 0 + } + + if fi.Mode()&os.ModeDir != 0 { + // convert opaque dirs to AUFS format by writing an empty file with the prefix + opaque, err := system.Lgetxattr(path, "trusted.overlay.opaque") + if err != nil { + return nil, err + } + if len(opaque) == 1 && opaque[0] == 'y' { + if hdr.Xattrs != nil { + delete(hdr.Xattrs, "trusted.overlay.opaque") + } + + // create a header for the whiteout file + // it should inherit some properties from the parent, but be a regular file + wo = &tar.Header{ + Typeflag: tar.TypeReg, + Mode: hdr.Mode & int64(os.ModePerm), + Name: filepath.Join(hdr.Name, WhiteoutOpaqueDir), + Size: 0, + Uid: hdr.Uid, + Uname: hdr.Uname, + Gid: hdr.Gid, + Gname: hdr.Gname, + AccessTime: hdr.AccessTime, + ChangeTime: hdr.ChangeTime, + } + } + } + + return +} + +func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) { + base := filepath.Base(path) + dir := filepath.Dir(path) + + // if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay + if base == WhiteoutOpaqueDir { + err := unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0) + // don't write the file itself + return false, err + } + + // if a file was deleted and we are using overlay, we need to create a character device + if strings.HasPrefix(base, WhiteoutPrefix) { + originalBase := base[len(WhiteoutPrefix):] + originalPath := filepath.Join(dir, originalBase) + + if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil { + return false, err + } + if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil { + return false, err + } + + // don't write the file itself + return false, nil + } + + return true, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go new file mode 100644 index 000000000..72822c857 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go @@ -0,0 +1,11 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !linux + +package archive + +func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter { + return nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go new file mode 100644 index 000000000..80199d513 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go @@ -0,0 +1,77 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !windows + +package archive + +import ( + "archive/tar" + "errors" + "os" + "path/filepath" + "syscall" + + "github.com/docker/docker/pkg/idtools" + "golang.org/x/sys/unix" +) + +// CanonicalTarNameForPath returns platform-specific filepath +// to canonical posix-style path for tar archival. p is relative +// path. +func CanonicalTarNameForPath(p string) (string, error) { + return p, nil // already unix-style +} + +// fixVolumePathPrefix does platform specific processing to ensure that if +// the path being passed in is not in a volume path format, convert it to one. +func fixVolumePathPrefix(srcPath string) string { + return srcPath +} + +// getWalkRoot calculates the root path when performing a TarWithOptions. +// We use a separate function as this is platform specific. On Linux, we +// can't use filepath.Join(srcPath,include) because this will clean away +// a trailing "." or "/" which may be important. +func getWalkRoot(srcPath string, include string) string { + return srcPath + string(filepath.Separator) + include +} + +func getInodeFromStat(stat interface{}) (inode uint64, err error) { + s, ok := stat.(*syscall.Stat_t) + + if ok { + inode = uint64(s.Ino) + } + + return +} + +func getFileIdentity(stat interface{}) (idtools.Identity, error) { + s, ok := stat.(*syscall.Stat_t) + + if !ok { + return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t") + } + return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil +} + +func chmodTarEntry(perm os.FileMode) os.FileMode { + return perm // noop for unix as golang APIs provide perm bits correctly +} + +func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) { + s, ok := stat.(*syscall.Stat_t) + + if ok { + // Currently go does not fill in the major/minors + if s.Mode&unix.S_IFBLK != 0 || + s.Mode&unix.S_IFCHR != 0 { + hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) // nolint: unconvert + hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) // nolint: unconvert + } + } + + return +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go new file mode 100644 index 000000000..c47768e68 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go @@ -0,0 +1,71 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "archive/tar" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/docker/docker/pkg/idtools" + "github.com/docker/docker/pkg/longpath" +) + +// CanonicalTarNameForPath returns platform-specific filepath +// to canonical posix-style path for tar archival. p is relative +// path. +func CanonicalTarNameForPath(p string) (string, error) { + // windows: convert windows style relative path with backslashes + // into forward slashes. Since windows does not allow '/' or '\' + // in file names, it is mostly safe to replace however we must + // check just in case + if strings.Contains(p, "/") { + return "", fmt.Errorf("Windows path contains forward slash: %s", p) + } + return strings.Replace(p, string(os.PathSeparator), "/", -1), nil + +} + +// fixVolumePathPrefix does platform specific processing to ensure that if +// the path being passed in is not in a volume path format, convert it to one. +func fixVolumePathPrefix(srcPath string) string { + return longpath.AddPrefix(srcPath) +} + +// getWalkRoot calculates the root path when performing a TarWithOptions. +// We use a separate function as this is platform specific. +func getWalkRoot(srcPath string, include string) string { + return filepath.Join(srcPath, include) +} + +func getInodeFromStat(stat interface{}) (inode uint64, err error) { + // do nothing. no notion of Inode in stat on Windows + return +} + +func getFileIdentity(stat interface{}) (idtools.Identity, error) { + // no notion of file ownership mapping yet on Windows + return idtools.Identity{}, nil +} + +// chmodTarEntry is used to adjust the file permissions used in tar header based +// on the platform the archival is done. +func chmodTarEntry(perm os.FileMode) os.FileMode { + //perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.) + permPart := perm & os.ModePerm + noPermPart := perm &^ os.ModePerm + // Add the x bit: make everything +x from windows + permPart |= 0111 + permPart &= 0755 + + return noPermPart | permPart +} + +func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) { + // do nothing. no notion of Rdev, Nlink in stat on Windows + return +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go new file mode 100644 index 000000000..39ea287bf --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go @@ -0,0 +1,16 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !windows + +package archive + +import ( + "os" + "syscall" +) + +func hasHardlinks(fi os.FileInfo) bool { + return fi.Sys().(*syscall.Stat_t).Nlink > 1 +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go new file mode 100644 index 000000000..a93130474 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go @@ -0,0 +1,11 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import "os" + +func hasHardlinks(fi os.FileInfo) bool { + return false +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go new file mode 100644 index 000000000..45d45f20e --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go @@ -0,0 +1,29 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +import ( + "os" + "path/filepath" +) + +// SplitPathDirEntry splits the given path between its directory name and its +// basename by first cleaning the path but preserves a trailing "." if the +// original path specified the current directory. +func SplitPathDirEntry(path string) (dir, base string) { + cleanedPath := filepath.Clean(filepath.FromSlash(path)) + + if specifiesCurrentDir(path) { + cleanedPath += string(os.PathSeparator) + "." + } + + return filepath.Dir(cleanedPath), filepath.Base(cleanedPath) +} + +// specifiesCurrentDir returns whether the given path specifies +// a "current directory", i.e., the last path segment is `.`. +func specifiesCurrentDir(path string) bool { + return filepath.Base(path) == "." +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go b/vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go new file mode 100644 index 000000000..a61c22a08 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go @@ -0,0 +1,27 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package archive + +// Whiteouts are files with a special meaning for the layered filesystem. +// Docker uses AUFS whiteout files inside exported archives. In other +// filesystems these files are generated/handled on tar creation/extraction. + +// WhiteoutPrefix prefix means file is a whiteout. If this is followed by a +// filename this means that file has been removed from the base layer. +const WhiteoutPrefix = ".wh." + +// WhiteoutMetaPrefix prefix means whiteout has a special meaning and is not +// for removing an actual file. Normally these files are excluded from exported +// archives. +const WhiteoutMetaPrefix = WhiteoutPrefix + WhiteoutPrefix + +// WhiteoutLinkDir is a directory AUFS uses for storing hardlink links to other +// layers. Normally these should not go into exported archives and all changed +// hardlinks should be copied to the top layer. +const WhiteoutLinkDir = WhiteoutMetaPrefix + "plnk" + +// WhiteoutOpaqueDir file means directory has been made opaque - meaning +// readdir calls to this directory do not follow to lower layers. +const WhiteoutOpaqueDir = WhiteoutMetaPrefix + ".opq" diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go b/vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go new file mode 100644 index 000000000..5d8ee6df8 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go @@ -0,0 +1,402 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package jsonmessage + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/Nvveen/Gotty" + "github.com/docker/go-units" + "github.com/fsouza/go-dockerclient/internal/term" +) + +// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to +// ensure the formatted time isalways the same number of characters. +const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00" + +// JSONError wraps a concrete Code and Message, `Code` is +// is an integer error code, `Message` is the error message. +type JSONError struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` +} + +func (e *JSONError) Error() string { + return e.Message +} + +// JSONProgress describes a Progress. terminalFd is the fd of the current terminal, +// Start is the initial value for the operation. Current is the current status and +// value of the progress made towards Total. Total is the end value describing when +// we made 100% progress for an operation. +type JSONProgress struct { + terminalFd uintptr + Current int64 `json:"current,omitempty"` + Total int64 `json:"total,omitempty"` + Start int64 `json:"start,omitempty"` + // If true, don't show xB/yB + HideCounts bool `json:"hidecounts,omitempty"` + Units string `json:"units,omitempty"` + nowFunc func() time.Time + winSize int +} + +func (p *JSONProgress) String() string { + var ( + width = p.width() + pbBox string + numbersBox string + timeLeftBox string + ) + if p.Current <= 0 && p.Total <= 0 { + return "" + } + if p.Total <= 0 { + switch p.Units { + case "": + current := units.HumanSize(float64(p.Current)) + return fmt.Sprintf("%8v", current) + default: + return fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + percentage := int(float64(p.Current)/float64(p.Total)*100) / 2 + if percentage > 50 { + percentage = 50 + } + if width > 110 { + // this number can't be negative gh#7136 + numSpaces := 0 + if 50-percentage > 0 { + numSpaces = 50 - percentage + } + pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces)) + } + + switch { + case p.HideCounts: + case p.Units == "": // no units, use bytes + current := units.HumanSize(float64(p.Current)) + total := units.HumanSize(float64(p.Total)) + + numbersBox = fmt.Sprintf("%8v/%v", current, total) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%8v", current) + } + default: + numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + if p.Current > 0 && p.Start > 0 && percentage < 50 { + fromStart := p.now().Sub(time.Unix(p.Start, 0)) + perEntry := fromStart / time.Duration(p.Current) + left := time.Duration(p.Total-p.Current) * perEntry + left = (left / time.Second) * time.Second + + if width > 50 { + timeLeftBox = " " + left.String() + } + } + return pbBox + numbersBox + timeLeftBox +} + +// shim for testing +func (p *JSONProgress) now() time.Time { + if p.nowFunc == nil { + p.nowFunc = func() time.Time { + return time.Now().UTC() + } + } + return p.nowFunc() +} + +// shim for testing +func (p *JSONProgress) width() int { + if p.winSize != 0 { + return p.winSize + } + ws, err := term.GetWinsize(p.terminalFd) + if err == nil { + return int(ws.Width) + } + return 200 +} + +// JSONMessage defines a message struct. It describes +// the created time, where it from, status, ID of the +// message. It's used for docker events. +type JSONMessage struct { + Stream string `json:"stream,omitempty"` + Status string `json:"status,omitempty"` + Progress *JSONProgress `json:"progressDetail,omitempty"` + ProgressMessage string `json:"progress,omitempty"` //deprecated + ID string `json:"id,omitempty"` + From string `json:"from,omitempty"` + Time int64 `json:"time,omitempty"` + TimeNano int64 `json:"timeNano,omitempty"` + Error *JSONError `json:"errorDetail,omitempty"` + ErrorMessage string `json:"error,omitempty"` //deprecated + // Aux contains out-of-band data, such as digests for push signing and image id after building. + Aux *json.RawMessage `json:"aux,omitempty"` +} + +/* Satisfied by gotty.TermInfo as well as noTermInfo from below */ +type termInfo interface { + Parse(attr string, params ...interface{}) (string, error) +} + +type noTermInfo struct{} // canary used when no terminfo. + +func (ti *noTermInfo) Parse(attr string, params ...interface{}) (string, error) { + return "", fmt.Errorf("noTermInfo") +} + +func clearLine(out io.Writer, ti termInfo) error { + // el2 (clear whole line) is not exposed by terminfo. + + // First clear line from beginning to cursor + if attr, err := ti.Parse("el1"); err == nil { + _, err = fmt.Fprintf(out, "%s", attr) + if err != nil { + return err + } + } else { + _, err := fmt.Fprintf(out, "\x1b[1K") + if err != nil { + return err + } + } + // Then clear line from cursor to end + if attr, err := ti.Parse("el"); err == nil { + _, err = fmt.Fprintf(out, "%s", attr) + if err != nil { + return err + } + } else { + _, err := fmt.Fprintf(out, "\x1b[K") + if err != nil { + return err + } + } + + return nil +} + +func cursorUp(out io.Writer, ti termInfo, l int) error { + if l == 0 { // Should never be the case, but be tolerant + return nil + } + if attr, err := ti.Parse("cuu", l); err == nil { + _, err = fmt.Fprintf(out, "%s", attr) + if err != nil { + return err + } + } else { + _, err := fmt.Fprintf(out, "\x1b[%dA", l) + if err != nil { + return err + } + } + return nil +} + +func cursorDown(out io.Writer, ti termInfo, l int) error { + if l == 0 { // Should never be the case, but be tolerant + return nil + } + if attr, err := ti.Parse("cud", l); err == nil { + _, err = fmt.Fprintf(out, "%s", attr) + if err != nil { + return err + } + } else { + _, err := fmt.Fprintf(out, "\x1b[%dB", l) + if err != nil { + return err + } + } + + return nil +} + +// Display displays the JSONMessage to `out`. `termInfo` is non-nil if `out` +// is a terminal. If this is the case, it will erase the entire current line +// when displaying the progressbar. +func (jm *JSONMessage) Display(out io.Writer, termInfo termInfo) error { + if jm.Error != nil { + if jm.Error.Code == 401 { + return fmt.Errorf("authentication is required") + } + return jm.Error + } + var endl string + if termInfo != nil && jm.Stream == "" && jm.Progress != nil { + clearLine(out, termInfo) + endl = "\r" + _, err := fmt.Fprintf(out, endl) + if err != nil { + return err + } + } else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal + return nil + } + if jm.TimeNano != 0 { + _, err := fmt.Fprintf(out, "%s ", time.Unix(0, jm.TimeNano).Format(RFC3339NanoFixed)) + if err != nil { + return err + } + } else if jm.Time != 0 { + _, err := fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(RFC3339NanoFixed)) + if err != nil { + return err + } + } + if jm.ID != "" { + _, err := fmt.Fprintf(out, "%s: ", jm.ID) + if err != nil { + return err + } + } + if jm.From != "" { + _, err := fmt.Fprintf(out, "(from %s) ", jm.From) + if err != nil { + return err + } + } + if jm.Progress != nil && termInfo != nil { + _, err := fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl) + if err != nil { + return err + } + } else if jm.ProgressMessage != "" { //deprecated + _, err := fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl) + if err != nil { + return err + } + } else if jm.Stream != "" { + _, err := fmt.Fprintf(out, "%s%s", jm.Stream, endl) + if err != nil { + return err + } + } else { + _, err := fmt.Fprintf(out, "%s%s\n", jm.Status, endl) + if err != nil { + return err + } + } + return nil +} + +// DisplayJSONMessagesStream displays a json message stream from `in` to `out`, `isTerminal` +// describes if `out` is a terminal. If this is the case, it will print `\n` at the end of +// each line and move the cursor while displaying. +func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(JSONMessage)) error { + var ( + dec = json.NewDecoder(in) + ids = make(map[string]int) + ) + + var termInfo termInfo + + if isTerminal { + term := os.Getenv("TERM") + if term == "" { + term = "vt102" + } + + var err error + if termInfo, err = gotty.OpenTermInfo(term); err != nil { + termInfo = &noTermInfo{} + } + } + + for { + diff := 0 + var jm JSONMessage + if err := dec.Decode(&jm); err != nil { + if err == io.EOF { + break + } + return err + } + + if jm.Aux != nil { + if auxCallback != nil { + auxCallback(jm) + } + continue + } + + if jm.Progress != nil { + jm.Progress.terminalFd = terminalFd + } + if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") { + line, ok := ids[jm.ID] + if !ok { + // NOTE: This approach of using len(id) to + // figure out the number of lines of history + // only works as long as we clear the history + // when we output something that's not + // accounted for in the map, such as a line + // with no ID. + line = len(ids) + ids[jm.ID] = line + if termInfo != nil { + _, err := fmt.Fprintf(out, "\n") + if err != nil { + return err + } + } + } + diff = len(ids) - line + if termInfo != nil { + if err := cursorUp(out, termInfo, diff); err != nil { + return err + } + } + } else { + // When outputting something that isn't progress + // output, clear the history of previous lines. We + // don't want progress entries from some previous + // operation to be updated (for example, pull -a + // with multiple tags). + ids = make(map[string]int) + } + err := jm.Display(out, termInfo) + if jm.ID != "" && termInfo != nil { + if err := cursorDown(out, termInfo, diff); err != nil { + return err + } + } + if err != nil { + return err + } + } + return nil +} + +type stream interface { + io.Writer + FD() uintptr + IsTerminal() bool +} + +// DisplayJSONMessagesToStream prints json messages to the output stream +func DisplayJSONMessagesToStream(in io.Reader, stream stream, auxCallback func(JSONMessage)) error { + return DisplayJSONMessagesStream(in, stream, stream.FD(), stream.IsTerminal(), auxCallback) +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/term/term.go b/vendor/github.com/fsouza/go-dockerclient/internal/term/term.go new file mode 100644 index 000000000..af06911d8 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/term/term.go @@ -0,0 +1,13 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package term + +// Winsize represents the size of the terminal window. +type Winsize struct { + Height uint16 + Width uint16 + x uint16 + y uint16 +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go new file mode 100644 index 000000000..2a9964a0d --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go @@ -0,0 +1,16 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +// +build !windows + +package term + +import "golang.org/x/sys/unix" + +// GetWinsize returns the window size based on the specified file descriptor. +func GetWinsize(fd uintptr) (*Winsize, error) { + uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) + ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel} + return ws, err +} diff --git a/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go new file mode 100644 index 000000000..4a07a5d19 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go @@ -0,0 +1,22 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package term + +import "github.com/Azure/go-ansiterm/winterm" + +// GetWinsize returns the window size based on the specified file descriptor. +func GetWinsize(fd uintptr) (*Winsize, error) { + info, err := winterm.GetConsoleScreenBufferInfo(fd) + if err != nil { + return nil, err + } + + winsize := &Winsize{ + Width: uint16(info.Window.Right - info.Window.Left + 1), + Height: uint16(info.Window.Bottom - info.Window.Top + 1), + } + + return winsize, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/misc.go b/vendor/github.com/fsouza/go-dockerclient/misc.go index 1b5cb2491..f095c44c7 100644 --- a/vendor/github.com/fsouza/go-dockerclient/misc.go +++ b/vendor/github.com/fsouza/go-dockerclient/misc.go @@ -5,6 +5,7 @@ package docker import ( + "context" "encoding/json" "net" "strings" @@ -16,7 +17,12 @@ import ( // // See https://goo.gl/mU7yje for more details. func (c *Client) Version() (*Env, error) { - resp, err := c.do("GET", "/version", doOptions{}) + return c.VersionWithContext(nil) +} + +// VersionWithContext returns version information about the docker server. +func (c *Client) VersionWithContext(ctx context.Context) (*Env, error) { + resp, err := c.do("GET", "/version", doOptions{context: ctx}) if err != nil { return nil, err } @@ -79,6 +85,7 @@ type DockerInfo struct { Labels []string ServerVersion string ClusterStore string + Runtimes map[string]Runtime ClusterAdvertise string Isolation string InitBinary string @@ -87,6 +94,14 @@ type DockerInfo struct { Swarm swarm.Info } +// Runtime describes an OCI runtime +// +// for more information, see: https://dockr.ly/2NKM8qq +type Runtime struct { + Path string + Args []string `json:"runtimeArgs"` +} + // PluginsInfo is a struct with the plugins registered with the docker daemon // // for more information, see: https://goo.gl/bHUoz9 diff --git a/vendor/github.com/fsouza/go-dockerclient/network.go b/vendor/github.com/fsouza/go-dockerclient/network.go index 155c52c78..8c03b9ae6 100644 --- a/vendor/github.com/fsouza/go-dockerclient/network.go +++ b/vendor/github.com/fsouza/go-dockerclient/network.go @@ -5,12 +5,12 @@ package docker import ( + "context" "encoding/json" "errors" "fmt" "net/http" - - "golang.org/x/net/context" + "net/url" ) // ErrNetworkAlreadyExists is the error returned by CreateNetwork when the @@ -72,7 +72,9 @@ func (c *Client) FilteredListNetworks(opts NetworkFilterOpts) ([]Network, error) if err != nil { return nil, err } - path := "/networks?filters=" + string(params) + qs := make(url.Values) + qs.Add("filters", string(params)) + path := "/networks?" + qs.Encode() resp, err := c.do("GET", path, doOptions{}) if err != nil { return nil, err diff --git a/vendor/github.com/fsouza/go-dockerclient/plugin.go b/vendor/github.com/fsouza/go-dockerclient/plugin.go new file mode 100644 index 000000000..957015907 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/plugin.go @@ -0,0 +1,418 @@ +// Copyright 2018 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/http" +) + +// PluginPrivilege represents a privilege for a plugin. +type PluginPrivilege struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// InstallPluginOptions specify parameters to the InstallPlugins function. +// +// See https://goo.gl/C4t7Tz for more details. +type InstallPluginOptions struct { + Remote string + Name string + Plugins []PluginPrivilege `qs:"-"` + + Auth AuthConfiguration + + Context context.Context +} + +// InstallPlugins installs a plugin or returns an error in case of failure. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) InstallPlugins(opts InstallPluginOptions) error { + path := "/plugins/pull?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + data: opts.Plugins, + context: opts.Context, + }) + defer resp.Body.Close() + if err != nil { + return err + } + return nil +} + +// PluginSettings stores plugin settings. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginSettings struct { + Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"` + Args []string `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"` + Devices []string `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"` +} + +// PluginInterface stores plugin interface. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginInterface struct { + Types []string `json:"Types,omitempty" yaml:"Types,omitempty" toml:"Types,omitempty"` + Socket string `json:"Socket,omitempty" yaml:"Socket,omitempty" toml:"Socket,omitempty"` +} + +// PluginNetwork stores plugin network type. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginNetwork struct { + Type string `json:"Type,omitempty" yaml:"Type,omitempty" toml:"Type,omitempty"` +} + +// PluginLinux stores plugin linux setting. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginLinux struct { + Capabilities []string `json:"Capabilities,omitempty" yaml:"Capabilities,omitempty" toml:"Capabilities,omitempty"` + AllowAllDevices bool `json:"AllowAllDevices,omitempty" yaml:"AllowAllDevices,omitempty" toml:"AllowAllDevices,omitempty"` + Devices []PluginLinuxDevices `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"` +} + +// PluginLinuxDevices stores plugin linux device setting. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginLinuxDevices struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Documentation,omitempty" yaml:"Documentation,omitempty" toml:"Documentation,omitempty"` + Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"` + Path string `json:"Path,omitempty" yaml:"Path,omitempty" toml:"Path,omitempty"` +} + +// PluginEnv stores plugin environment. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginEnv struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"` + Value string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// PluginArgs stores plugin arguments. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginArgs struct { + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Settable []string `json:"Settable,omitempty" yaml:"Settable,omitempty" toml:"Settable,omitempty"` + Value []string `json:"Value,omitempty" yaml:"Value,omitempty" toml:"Value,omitempty"` +} + +// PluginUser stores plugin user. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginUser struct { + UID int32 `json:"UID,omitempty" yaml:"UID,omitempty" toml:"UID,omitempty"` + GID int32 `json:"GID,omitempty" yaml:"GID,omitempty" toml:"GID,omitempty"` +} + +// PluginConfig stores plugin config. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginConfig struct { + Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"` + Documentation string + Interface PluginInterface `json:"Interface,omitempty" yaml:"Interface,omitempty" toml:"Interface,omitempty"` + Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty" toml:"Entrypoint,omitempty"` + WorkDir string `json:"WorkDir,omitempty" yaml:"WorkDir,omitempty" toml:"WorkDir,omitempty"` + User PluginUser `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"` + Network PluginNetwork `json:"Network,omitempty" yaml:"Network,omitempty" toml:"Network,omitempty"` + Linux PluginLinux `json:"Linux,omitempty" yaml:"Linux,omitempty" toml:"Linux,omitempty"` + PropagatedMount string `json:"PropagatedMount,omitempty" yaml:"PropagatedMount,omitempty" toml:"PropagatedMount,omitempty"` + Mounts []Mount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` + Env []PluginEnv `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"` + Args PluginArgs `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"` +} + +// PluginDetail specify results from the ListPlugins function. +// +// See https://goo.gl/C4t7Tz for more details. +type PluginDetail struct { + ID string `json:"Id,omitempty" yaml:"Id,omitempty" toml:"Id,omitempty"` + Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"` + Tag string `json:"Tag,omitempty" yaml:"Tag,omitempty" toml:"Tag,omitempty"` + Active bool `json:"Enabled,omitempty" yaml:"Active,omitempty" toml:"Active,omitempty"` + Settings PluginSettings `json:"Settings,omitempty" yaml:"Settings,omitempty" toml:"Settings,omitempty"` + Config PluginConfig `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"` +} + +// ListPlugins returns pluginDetails or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) ListPlugins(ctx context.Context) ([]PluginDetail, error) { + resp, err := c.do("GET", "/plugins", doOptions{ + context: ctx, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + pluginDetails := make([]PluginDetail, 0) + if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil { + return nil, err + } + return pluginDetails, nil +} + +// ListFilteredPluginsOptions specify parameters to the ListFilteredPlugins function. +// +// See https://goo.gl/C4t7Tz for more details. +type ListFilteredPluginsOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListFilteredPlugins returns pluginDetails or an error. +// +// See https://goo.gl/rmdmWg for more details. +func (c *Client) ListFilteredPlugins(opts ListFilteredPluginsOptions) ([]PluginDetail, error) { + path := "/plugins/json?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{ + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + pluginDetails := make([]PluginDetail, 0) + if err := json.NewDecoder(resp.Body).Decode(&pluginDetails); err != nil { + return nil, err + } + return pluginDetails, nil +} + +// GetPluginPrivileges returns pulginPrivileges or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) GetPluginPrivileges(name string, ctx context.Context) ([]PluginPrivilege, error) { + resp, err := c.do("GET", "/plugins/privileges?remote="+name, doOptions{ + context: ctx, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var pluginPrivileges []PluginPrivilege + if err := json.NewDecoder(resp.Body).Decode(&pluginPrivileges); err != nil { + return nil, err + } + return pluginPrivileges, nil +} + +// InspectPlugins returns a pluginDetail or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) InspectPlugins(name string, ctx context.Context) (*PluginDetail, error) { + resp, err := c.do("GET", "/plugins/"+name+"/json", doOptions{ + context: ctx, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchPlugin{ID: name} + } + return nil, err + } + resp.Body.Close() + var pluginDetail PluginDetail + if err := json.NewDecoder(resp.Body).Decode(&pluginDetail); err != nil { + return nil, err + } + return &pluginDetail, nil +} + +// RemovePluginOptions specify parameters to the RemovePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type RemovePluginOptions struct { + // The Name of the plugin. + Name string `qs:"-"` + + Force bool `qs:"force"` + Context context.Context +} + +// RemovePlugin returns a PluginDetail or an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) RemovePlugin(opts RemovePluginOptions) (*PluginDetail, error) { + path := "/plugins/" + opts.Name + "?" + queryString(opts) + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchPlugin{ID: opts.Name} + } + return nil, err + } + resp.Body.Close() + var pluginDetail PluginDetail + if err := json.NewDecoder(resp.Body).Decode(&pluginDetail); err != nil { + return nil, err + } + return &pluginDetail, nil +} + +// EnablePluginOptions specify parameters to the EnablePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type EnablePluginOptions struct { + // The Name of the plugin. + Name string `qs:"-"` + Timeout int64 `qs:"timeout"` + + Context context.Context +} + +// EnablePlugin enables plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) EnablePlugin(opts EnablePluginOptions) error { + path := "/plugins/" + opts.Name + "/enable?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// DisablePluginOptions specify parameters to the DisablePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type DisablePluginOptions struct { + // The Name of the plugin. + Name string `qs:"-"` + + Context context.Context +} + +// DisablePlugin disables plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) DisablePlugin(opts DisablePluginOptions) error { + path := "/plugins/" + opts.Name + "/disable" + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return err + } + resp.Body.Close() + return nil +} + +// CreatePluginOptions specify parameters to the CreatePlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type CreatePluginOptions struct { + // The Name of the plugin. + Name string `qs:"name"` + // Path to tar containing plugin + Path string `qs:"-"` + + Context context.Context +} + +// CreatePlugin creates plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) CreatePlugin(opts CreatePluginOptions) (string, error) { + path := "/plugins/create?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + data: opts.Path, + context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return "", err + } + containerNameBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(containerNameBytes), nil +} + +// PushPluginOptions specify parameters to PushPlugin function. +// +// See https://goo.gl/C4t7Tz for more details. +type PushPluginOptions struct { + // The Name of the plugin. + Name string + + Context context.Context +} + +// PushPlugin pushes plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) PushPlugin(opts PushPluginOptions) error { + path := "/plugins/" + opts.Name + "/push" + resp, err := c.do("POST", path, doOptions{context: opts.Context}) + defer resp.Body.Close() + if err != nil { + return err + } + return nil +} + +// ConfigurePluginOptions specify parameters to the ConfigurePlugin +// +// See https://goo.gl/C4t7Tz for more details. +type ConfigurePluginOptions struct { + // The Name of the plugin. + Name string `qs:"name"` + Envs []string + + Context context.Context +} + +// ConfigurePlugin configures plugin that opts point or returns an error. +// +// See https://goo.gl/C4t7Tz for more details. +func (c *Client) ConfigurePlugin(opts ConfigurePluginOptions) error { + path := "/plugins/" + opts.Name + "/set" + resp, err := c.do("POST", path, doOptions{ + data: opts.Envs, + context: opts.Context, + }) + defer resp.Body.Close() + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchPlugin{ID: opts.Name} + } + return err + } + return nil +} + +// NoSuchPlugin is the error returned when a given plugin does not exist. +type NoSuchPlugin struct { + ID string + Err error +} + +func (err *NoSuchPlugin) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such plugin: " + err.ID +} diff --git a/vendor/github.com/fsouza/go-dockerclient/registry_auth.go b/vendor/github.com/fsouza/go-dockerclient/registry_auth.go new file mode 100644 index 000000000..1f60d1e8f --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/registry_auth.go @@ -0,0 +1,10 @@ +// Copyright 2013 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +type registryAuth interface { + isEmpty() bool + headerKey() string +} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm.go b/vendor/github.com/fsouza/go-dockerclient/swarm.go index 6d9086a55..a257758fc 100644 --- a/vendor/github.com/fsouza/go-dockerclient/swarm.go +++ b/vendor/github.com/fsouza/go-dockerclient/swarm.go @@ -5,6 +5,7 @@ package docker import ( + "context" "encoding/json" "errors" "net/http" @@ -12,7 +13,6 @@ import ( "strconv" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) var ( diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go b/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go index 7701484da..fb73ab2ef 100644 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go @@ -5,13 +5,13 @@ package docker import ( + "context" "encoding/json" "net/http" "net/url" "strconv" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) // NoSuchConfig is the error returned when a given config does not exist. diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_node.go b/vendor/github.com/fsouza/go-dockerclient/swarm_node.go index 843402541..095653cd9 100644 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_node.go +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_node.go @@ -5,13 +5,13 @@ package docker import ( + "context" "encoding/json" "net/http" "net/url" "strconv" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) // NoSuchNode is the error returned when a given node does not exist. diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go b/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go index eb4881e0d..5a3b82ca5 100644 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go @@ -5,13 +5,13 @@ package docker import ( + "context" "encoding/json" "net/http" "net/url" "strconv" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) // NoSuchSecret is the error returned when a given secret does not exist. diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_service.go b/vendor/github.com/fsouza/go-dockerclient/swarm_service.go index 33af547c6..ca7e23725 100644 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_service.go +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_service.go @@ -5,15 +5,13 @@ package docker import ( + "context" "encoding/json" "io" "net/http" - "net/url" - "strconv" "time" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) // NoSuchService is the error returned when a given service does not exist. @@ -93,10 +91,11 @@ func (c *Client) RemoveService(opts RemoveServiceOptions) error { // // See https://goo.gl/wu3MmS for more details. type UpdateServiceOptions struct { - Auth AuthConfiguration `qs:"-"` - swarm.ServiceSpec - Context context.Context - Version uint64 + Auth AuthConfiguration `qs:"-"` + swarm.ServiceSpec `qs:"-"` + Context context.Context + Version uint64 + Rollback string } // UpdateService updates the service at ID with the options @@ -107,9 +106,7 @@ func (c *Client) UpdateService(id string, opts UpdateServiceOptions) error { if err != nil { return err } - params := make(url.Values) - params.Set("version", strconv.FormatUint(opts.Version, 10)) - resp, err := c.do("POST", "/services/"+id+"/update?"+params.Encode(), doOptions{ + resp, err := c.do("POST", "/services/"+id+"/update?"+queryString(opts), doOptions{ headers: headers, data: opts.ServiceSpec, forceJSON: true, diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_task.go b/vendor/github.com/fsouza/go-dockerclient/swarm_task.go index b1dad4b23..3b1161ab9 100644 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_task.go +++ b/vendor/github.com/fsouza/go-dockerclient/swarm_task.go @@ -5,11 +5,11 @@ package docker import ( + "context" "encoding/json" "net/http" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) // NoSuchTask is the error returned when a given task does not exist. diff --git a/vendor/github.com/fsouza/go-dockerclient/system.go b/vendor/github.com/fsouza/go-dockerclient/system.go new file mode 100644 index 000000000..a43dfb5a2 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/system.go @@ -0,0 +1,72 @@ +package docker + +import ( + "context" + "encoding/json" +) + +// VolumeUsageData represents usage data from the docker system api +// More Info Here https://dockr.ly/2PNzQyO +type VolumeUsageData struct { + + // The number of containers referencing this volume. This field + // is set to `-1` if the reference-count is not available. + // + // Required: true + RefCount int64 `json:"RefCount"` + + // Amount of disk space used by the volume (in bytes). This information + // is only available for volumes created with the `"local"` volume + // driver. For volumes created with other volume drivers, this field + // is set to `-1` ("not available") + // + // Required: true + Size int64 `json:"Size"` +} + +// ImageSummary represents data about what images are +// currently known to docker +// More Info Here https://dockr.ly/2PNzQyO +type ImageSummary struct { + Containers int64 `json:"Containers"` + Created int64 `json:"Created"` + ID string `json:"Id"` + Labels map[string]string `json:"Labels"` + ParentID string `json:"ParentId"` + RepoDigests []string `json:"RepoDigests"` + RepoTags []string `json:"RepoTags"` + SharedSize int64 `json:"SharedSize"` + Size int64 `json:"Size"` + VirtualSize int64 `json:"VirtualSize"` +} + +// DiskUsage holds information about what docker is using disk space on. +// More Info Here https://dockr.ly/2PNzQyO +type DiskUsage struct { + LayersSize int64 + Images []*ImageSummary + Containers []*APIContainers + Volumes []*Volume +} + +// DiskUsageOptions only contains a context for canceling. +type DiskUsageOptions struct { + Context context.Context +} + +// DiskUsage returns a *DiskUsage describing what docker is using disk on. +// +// More Info Here https://dockr.ly/2PNzQyO +func (c *Client) DiskUsage(opts DiskUsageOptions) (*DiskUsage, error) { + path := "/system/df" + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var du *DiskUsage + if err := json.NewDecoder(resp.Body).Decode(&du); err != nil { + return nil, err + } + return du, nil +} diff --git a/vendor/github.com/fsouza/go-dockerclient/tar.go b/vendor/github.com/fsouza/go-dockerclient/tar.go index be4dfa573..611da8c9e 100644 --- a/vendor/github.com/fsouza/go-dockerclient/tar.go +++ b/vendor/github.com/fsouza/go-dockerclient/tar.go @@ -13,11 +13,16 @@ import ( "path/filepath" "strings" - "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/fileutils" + "github.com/fsouza/go-dockerclient/internal/archive" ) func createTarStream(srcPath, dockerfilePath string) (io.ReadCloser, error) { + srcPath, err := filepath.Abs(srcPath) + if err != nil { + return nil, err + } + excludes, err := parseDockerignore(srcPath) if err != nil { return nil, err diff --git a/vendor/github.com/fsouza/go-dockerclient/tls.go b/vendor/github.com/fsouza/go-dockerclient/tls.go index bb5790b5f..5f0e2e31e 100644 --- a/vendor/github.com/fsouza/go-dockerclient/tls.go +++ b/vendor/github.com/fsouza/go-dockerclient/tls.go @@ -109,10 +109,10 @@ func copyTLSConfig(cfg *tls.Config) *tls.Config { NameToCertificate: cfg.NameToCertificate, NextProtos: cfg.NextProtos, PreferServerCipherSuites: cfg.PreferServerCipherSuites, - Rand: cfg.Rand, - RootCAs: cfg.RootCAs, - ServerName: cfg.ServerName, - SessionTicketKey: cfg.SessionTicketKey, - SessionTicketsDisabled: cfg.SessionTicketsDisabled, + Rand: cfg.Rand, + RootCAs: cfg.RootCAs, + ServerName: cfg.ServerName, + SessionTicketKey: cfg.SessionTicketKey, + SessionTicketsDisabled: cfg.SessionTicketsDisabled, } } diff --git a/vendor/github.com/fsouza/go-dockerclient/volume.go b/vendor/github.com/fsouza/go-dockerclient/volume.go index 1118a7817..c8f50469e 100644 --- a/vendor/github.com/fsouza/go-dockerclient/volume.go +++ b/vendor/github.com/fsouza/go-dockerclient/volume.go @@ -5,11 +5,11 @@ package docker import ( + "context" "encoding/json" "errors" "net/http" - - "golang.org/x/net/context" + "time" ) var ( @@ -22,17 +22,19 @@ var ( // Volume represents a volume. // -// See https://goo.gl/FZA4BK for more details. +// See https://goo.gl/3wgTsd for more details. type Volume struct { Name string `json:"Name" yaml:"Name" toml:"Name"` Driver string `json:"Driver,omitempty" yaml:"Driver,omitempty" toml:"Driver,omitempty"` Mountpoint string `json:"Mountpoint,omitempty" yaml:"Mountpoint,omitempty" toml:"Mountpoint,omitempty"` Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"` + Options map[string]string `json:"Options,omitempty" yaml:"Options,omitempty" toml:"Options,omitempty"` + CreatedAt time.Time `json:"CreatedAt,omitempty" yaml:"CreatedAt,omitempty" toml:"CreatedAt,omitempty"` } // ListVolumesOptions specify parameters to the ListVolumes function. // -// See https://goo.gl/FZA4BK for more details. +// See https://goo.gl/3wgTsd for more details. type ListVolumesOptions struct { Filters map[string][]string Context context.Context @@ -40,7 +42,7 @@ type ListVolumesOptions struct { // ListVolumes returns a list of available volumes in the server. // -// See https://goo.gl/FZA4BK for more details. +// See https://goo.gl/3wgTsd for more details. func (c *Client) ListVolumes(opts ListVolumesOptions) ([]Volume, error) { resp, err := c.do("GET", "/volumes?"+queryString(opts), doOptions{ context: opts.Context, @@ -70,7 +72,7 @@ func (c *Client) ListVolumes(opts ListVolumesOptions) ([]Volume, error) { // CreateVolumeOptions specify parameters to the CreateVolume function. // -// See https://goo.gl/pBUbZ9 for more details. +// See https://goo.gl/qEhmEC for more details. type CreateVolumeOptions struct { Name string Driver string @@ -81,7 +83,7 @@ type CreateVolumeOptions struct { // CreateVolume creates a volume on the server. // -// See https://goo.gl/pBUbZ9 for more details. +// See https://goo.gl/qEhmEC for more details. func (c *Client) CreateVolume(opts CreateVolumeOptions) (*Volume, error) { resp, err := c.do("POST", "/volumes/create", doOptions{ data: opts, @@ -100,7 +102,7 @@ func (c *Client) CreateVolume(opts CreateVolumeOptions) (*Volume, error) { // InspectVolume returns a volume by its name. // -// See https://goo.gl/0g9A6i for more details. +// See https://goo.gl/GMjsMc for more details. func (c *Client) InspectVolume(name string) (*Volume, error) { resp, err := c.do("GET", "/volumes/"+name, doOptions{}) if err != nil { @@ -119,9 +121,28 @@ func (c *Client) InspectVolume(name string) (*Volume, error) { // RemoveVolume removes a volume by its name. // -// See https://goo.gl/79GNQz for more details. +// Deprecated: Use RemoveVolumeWithOptions instead. func (c *Client) RemoveVolume(name string) error { - resp, err := c.do("DELETE", "/volumes/"+name, doOptions{}) + return c.RemoveVolumeWithOptions(RemoveVolumeOptions{Name: name}) +} + +// RemoveVolumeOptions specify parameters to the RemoveVolumeWithOptions +// function. +// +// See https://goo.gl/nvd6qj for more details. +type RemoveVolumeOptions struct { + Context context.Context + Name string `qs:"-"` + Force bool +} + +// RemoveVolumeWithOptions removes a volume by its name and takes extra +// parameters. +// +// See https://goo.gl/nvd6qj for more details. +func (c *Client) RemoveVolumeWithOptions(opts RemoveVolumeOptions) error { + path := "/volumes/" + opts.Name + resp, err := c.do("DELETE", path+"?"+queryString(opts), doOptions{context: opts.Context}) if err != nil { if e, ok := err.(*Error); ok { if e.Status == http.StatusNotFound { @@ -139,7 +160,7 @@ func (c *Client) RemoveVolume(name string) error { // PruneVolumesOptions specify parameters to the PruneVolumes function. // -// See https://goo.gl/pFN1Hj for more details. +// See https://goo.gl/f9XDem for more details. type PruneVolumesOptions struct { Filters map[string][]string Context context.Context @@ -147,7 +168,7 @@ type PruneVolumesOptions struct { // PruneVolumesResults specify results from the PruneVolumes function. // -// See https://goo.gl/pFN1Hj for more details. +// See https://goo.gl/f9XDem for more details. type PruneVolumesResults struct { VolumesDeleted []string SpaceReclaimed int64 @@ -155,7 +176,7 @@ type PruneVolumesResults struct { // PruneVolumes deletes volumes which are unused. // -// See https://goo.gl/pFN1Hj for more details. +// See https://goo.gl/f9XDem for more details. func (c *Client) PruneVolumes(opts PruneVolumesOptions) (*PruneVolumesResults, error) { path := "/volumes/prune?" + queryString(opts) resp, err := c.do("POST", path, doOptions{context: opts.Context}) diff --git a/vendor/vendor.json b/vendor/vendor.json index e217677f8..acec6ddcf 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -86,36 +86,36 @@ {"path":"github.com/docker/distribution/registry/storage/cache/memory","checksumSHA1":"T8G3A63WALmJ3JT/A0r01LG4KI0=","revision":"b12bd4004afc203f1cbd2072317c8fda30b89710","revisionTime":"2018-08-28T23:03:05Z"}, {"path":"github.com/docker/docker-credential-helpers/client","checksumSHA1":"zcDmNPSzI1wVokOiHis5+JSg2Rk=","revision":"73e5f5dbfea31ee3b81111ebbf189785fa69731c","revisionTime":"2018-07-19T07:47:51Z"}, {"path":"github.com/docker/docker-credential-helpers/credentials","checksumSHA1":"4u6EMQqD1zIqOHp76zQFLVH5V8U=","revision":"73e5f5dbfea31ee3b81111ebbf189785fa69731c","revisionTime":"2018-07-19T07:47:51Z"}, - {"path":"github.com/docker/docker/api/types","checksumSHA1":"hh2frMl2OiLNAzAdz48xzzzyGlw=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/blkiodev","checksumSHA1":"/jF0HVFiLzUUuywSjp4F/piM7BM=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/container","checksumSHA1":"lsxFU6qegOtXClSTthOvfPtly5I=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/filters","checksumSHA1":"y9EA6+kZQLx6kCM277CFHTm4eiw=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/mount","checksumSHA1":"k9CaJVvYL7SxcIP72ng/YcOuF9k=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/network","checksumSHA1":"IggTTG/yCDaV9SjtQz5SSarqUtc=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/registry","checksumSHA1":"m4Jg5WnW75I65nvkEno8PElSXik=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/strslice","checksumSHA1":"OQEUS/2J2xVHpfvcsxcXzYqBSeY=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/swarm","checksumSHA1":"qlMl0DqET1NC5GFyTSM5b305DL4=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/swarm/runtime","checksumSHA1":"txs5EKTbKgVyKmKKSnaH3fr+odA=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/api/types/versions","checksumSHA1":"MZsgRjJJ0D/gAsXfKiEys+op6dE=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/errdefs","checksumSHA1":"dF9WiXuwISBPd8bQfqpuoWtB3jk=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/opts","checksumSHA1":"u6EOrZRfhdjr4up14b2JJ7MMMaY=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/archive","checksumSHA1":"6jrp+51MWrqN07RIEXQfkwDzjbU=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/fileutils","checksumSHA1":"CYkS5Yh4GZ80KS+n/o+c5d0ktsA=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/homedir","checksumSHA1":"y37I+5AS96wQSiAxOayiMgnZawA=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/idtools","checksumSHA1":"10t/hGlBdat1QuSmLJ59ynG62BM=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/ioutils","checksumSHA1":"Ybq78CnAoQWVBk+lkh3zykmcSjs=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/jsonmessage","checksumSHA1":"KQflv+x9hoJywgvxMwWcJqrmdkQ=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/longpath","checksumSHA1":"EXiIm2xIL7Ds+YsQUx8Z3eUYPtI=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/mount","checksumSHA1":"IaLUlgL27e2W5LVWvncHgPWKffg=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/pools","checksumSHA1":"dj8atalGWftfM9vdzCsh9YF1Seg=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/stdcopy","checksumSHA1":"w0waeTRJ1sFygI0dZXH6l9E1c60=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/stringid","checksumSHA1":"gAUCA6R7F9kObegRGGNX5PzJahE=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/system","checksumSHA1":"W2vhTmDvG1eY4axzQjCjBVzo5Ms=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/tarsum","checksumSHA1":"I6mTgOFa7NeZpYw2S5342eenRLY=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/term","checksumSHA1":"WjvsjU1rtFjD3S0MmzKi5M08zjc=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/pkg/term/windows","checksumSHA1":"TeOtxuBbbZtp6wDK/t4DdaGGSC0=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/registry","checksumSHA1":"7YhsfoA07O7/TLou5q72Y/2sUsw=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, - {"path":"github.com/docker/docker/registry/resumable","checksumSHA1":"jH7uQnDehFQygPP3zLC/mLSqgOk=","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, + {"path":"github.com/docker/docker/api/types","checksumSHA1":"PM15F2b73fvtlDsjFyXSMd9LJqU=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/blkiodev","checksumSHA1":"/jF0HVFiLzUUuywSjp4F/piM7BM=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/container","checksumSHA1":"+jeShxohzdtOkwAzy9e0X/fq6n4=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/filters","checksumSHA1":"RMZg2+TAla7E2KiiyF5yupWn0lY=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/mount","checksumSHA1":"9OClWW7OCikgz4QCS/sAVcvqcWk=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/network","checksumSHA1":"qZNE4g8YWfV6ryZp8kN9BwWYCeM=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/registry","checksumSHA1":"m4Jg5WnW75I65nvkEno8PElSXik=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/strslice","checksumSHA1":"OQEUS/2J2xVHpfvcsxcXzYqBSeY=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/swarm","checksumSHA1":"NT/DoroAQOev6keoJO0zKQZmjbE=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/swarm/runtime","checksumSHA1":"txs5EKTbKgVyKmKKSnaH3fr+odA=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/api/types/versions","checksumSHA1":"MZsgRjJJ0D/gAsXfKiEys+op6dE=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/errdefs","checksumSHA1":"dF9WiXuwISBPd8bQfqpuoWtB3jk=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/opts","checksumSHA1":"u6EOrZRfhdjr4up14b2JJ7MMMaY=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/archive","checksumSHA1":"wZ8yvJiuW5sK2VmoEniu1yjVlBQ=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/fileutils","checksumSHA1":"eMoRb/diYeuYLojU7ChN5DaETHc=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/homedir","checksumSHA1":"y37I+5AS96wQSiAxOayiMgnZawA=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/idtools","checksumSHA1":"+Ir5nXNDvy3cwbTlBh06lR7zUrI=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/ioutils","checksumSHA1":"Ybq78CnAoQWVBk+lkh3zykmcSjs=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/jsonmessage","checksumSHA1":"KQflv+x9hoJywgvxMwWcJqrmdkQ=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/longpath","checksumSHA1":"EXiIm2xIL7Ds+YsQUx8Z3eUYPtI=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/mount","checksumSHA1":"hx613GafM5hLibNt86ijinN89Ro=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/pools","checksumSHA1":"dj8atalGWftfM9vdzCsh9YF1Seg=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/stdcopy","checksumSHA1":"w0waeTRJ1sFygI0dZXH6l9E1c60=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/stringid","checksumSHA1":"gAUCA6R7F9kObegRGGNX5PzJahE=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/system","checksumSHA1":"RreuHCnt9a8brZsc2Q4f5T8wd+E=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/tarsum","checksumSHA1":"I6mTgOFa7NeZpYw2S5342eenRLY=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/term","checksumSHA1":"GFsDxJkQz407/2nUBmWuafG+uF8=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/pkg/term/windows","checksumSHA1":"TeOtxuBbbZtp6wDK/t4DdaGGSC0=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/registry","checksumSHA1":"0ZOQ9gYPwnxxjSIytDpwvsN5Rl0=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, + {"path":"github.com/docker/docker/registry/resumable","checksumSHA1":"jH7uQnDehFQygPP3zLC/mLSqgOk=","revision":"baab736a364959f10a5ef86f0cd8a8e44bdcc576","revisionTime":"2018-11-29T15:58:16Z"}, {"path":"github.com/docker/go-connections/nat","checksumSHA1":"JbiWTzH699Sqz25XmDlsARpMN9w=","revision":"7da10c8c50cad14494ec818dcdfb6506265c0086","revisionTime":"2017-02-03T23:56:24Z"}, {"path":"github.com/docker/go-connections/sockets","checksumSHA1":"jUfDG3VQsA2UZHvvIXncgiddpYA=","origin":"github.com/docker/docker/vendor/github.com/docker/go-connections/sockets","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, {"path":"github.com/docker/go-connections/tlsconfig","checksumSHA1":"zUG/J7nb6PWxfSXOoET6NePfyc0=","origin":"github.com/docker/docker/vendor/github.com/docker/go-connections/tlsconfig","revision":"320063a2ad06a1d8ada61c94c29dbe44e2d87473","revisionTime":"2018-08-16T08:14:46Z"}, @@ -126,7 +126,10 @@ {"path":"github.com/elazarl/go-bindata-assetfs","checksumSHA1":"7DxViusFRJ7UPH0jZqYatwDrOkY=","revision":"30f82fa23fd844bd5bb1e5f216db87fd77b5eb43","revisionTime":"2017-02-27T21:27:28Z"}, {"path":"github.com/fatih/color","checksumSHA1":"VsE3zx2d8kpwj97TWhYddzAwBrY=","revision":"507f6050b8568533fb3f5504de8e5205fa62a114","revisionTime":"2018-02-13T13:34:03Z"}, {"path":"github.com/fatih/structs","checksumSHA1":"QBkOnLnM6zZ158NJSVLqoE4V6fI=","revision":"14f46232cd7bc732dc67313a9e4d3d210e082587","revisionTime":"2016-07-19T20:45:16Z"}, - {"path":"github.com/fsouza/go-dockerclient","checksumSHA1":"E+wmSQrc/BXzgITrbNAbUzljoiM=","revision":"5ffdfff51ec0eba739b1039e65ba3625ef25f7c0","revisionTime":"2017-11-23T03:37:03Z"}, + {"path":"github.com/fsouza/go-dockerclient","checksumSHA1":"fvbo1J+cFWDrPDs0Yudwv+POIb4=","revision":"01c3e9bd8551d675a60382c0303ef51f5849ea99","revisionTime":"2018-11-29T02:57:25Z"}, + {"path":"github.com/fsouza/go-dockerclient/internal/archive","checksumSHA1":"YJ7WR4AVtD2ykYJr+1mTtazkma0=","revision":"01c3e9bd8551d675a60382c0303ef51f5849ea99","revisionTime":"2018-11-29T02:57:25Z"}, + {"path":"github.com/fsouza/go-dockerclient/internal/jsonmessage","checksumSHA1":"lnUC8fZCqakWnfuMLUrZD2g+reY=","revision":"01c3e9bd8551d675a60382c0303ef51f5849ea99","revisionTime":"2018-11-29T02:57:25Z"}, + {"path":"github.com/fsouza/go-dockerclient/internal/term","checksumSHA1":"vdjeVhnepWyw3H4g9pVTVACDfV0=","revision":"01c3e9bd8551d675a60382c0303ef51f5849ea99","revisionTime":"2018-11-29T02:57:25Z"}, {"path":"github.com/go-ini/ini","checksumSHA1":"U4k9IYSBQcW5DW5QDc44n5dddxs=","comment":"v1.8.5-2-g6ec4abd","revision":"6ec4abd8f8d587536da56f730858f0e27aeb4126"}, {"path":"github.com/go-ole/go-ole","checksumSHA1":"IvHj/4iR2nYa/S3cB2GXoyDG/xQ=","comment":"v1.2.0-4-g5005588","revision":"085abb85892dc1949567b726dff00fa226c60c45","revisionTime":"2017-07-12T17:44:59Z"}, {"path":"github.com/go-ole/go-ole/oleutil","checksumSHA1":"qLYVTQDhgrVIeZ2KI9eZV51mmug=","comment":"v1.2.0-4-g5005588","revision":"50055884d646dd9434f16bbb5c9801749b9bafe4"}, diff --git a/website/source/docs/drivers/docker.html.md b/website/source/docs/drivers/docker.html.md index 0a69f6801..a9c6f7a0c 100644 --- a/website/source/docs/drivers/docker.html.md +++ b/website/source/docs/drivers/docker.html.md @@ -688,6 +688,8 @@ options](/docs/configuration/client.html#options): disable Nomad from removing a container when the task exits. Under a name conflict, Nomad may still remove the dead container. +* `docker.nvidia_runtime`: Defaults to `nvidia`. This option allows operators to select the runtime that should be used in order to expose Nvidia GPUs to the container. + Note: When testing or using the `-dev` flag you can use `DOCKER_HOST`, `DOCKER_TLS_VERIFY`, and `DOCKER_CERT_PATH` to customize Nomad's behavior. If `docker.endpoint` is set Nomad will **only** read client configuration from the