mirror of
https://github.com/kemko/nomad.git
synced 2026-01-04 01:15:43 +03:00
Merge pull request #5046 from oleksii-shyman/docker_runtimes
Nvidia runtime
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
2
vendor/github.com/docker/docker/LICENSE
generated
vendored
2
vendor/github.com/docker/docker/LICENSE
generated
vendored
@@ -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.
|
||||
|
||||
7
vendor/github.com/docker/docker/api/types/configs.go
generated
vendored
7
vendor/github.com/docker/docker/api/types/configs.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
1
vendor/github.com/docker/docker/api/types/container/host_config.go
generated
vendored
1
vendor/github.com/docker/docker/api/types/container/host_config.go
generated
vendored
@@ -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
|
||||
|
||||
16
vendor/github.com/docker/docker/api/types/filters/parse.go
generated
vendored
16
vendor/github.com/docker/docker/api/types/filters/parse.go
generated
vendored
@@ -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 {
|
||||
|
||||
3
vendor/github.com/docker/docker/api/types/mount/mount.go
generated
vendored
3
vendor/github.com/docker/docker/api/types/mount/mount.go
generated
vendored
@@ -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.
|
||||
|
||||
18
vendor/github.com/docker/docker/api/types/network/network.go
generated
vendored
18
vendor/github.com/docker/docker/api/types/network/network.go
generated
vendored
@@ -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))
|
||||
}
|
||||
|
||||
4
vendor/github.com/docker/docker/api/types/stats.go
generated
vendored
4
vendor/github.com/docker/docker/api/types/stats.go
generated
vendored
@@ -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.
|
||||
|
||||
1
vendor/github.com/docker/docker/api/types/swarm/container.go
generated
vendored
1
vendor/github.com/docker/docker/api/types/swarm/container.go
generated
vendored
@@ -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"`
|
||||
}
|
||||
|
||||
10
vendor/github.com/docker/docker/api/types/swarm/swarm.go
generated
vendored
10
vendor/github.com/docker/docker/api/types/swarm/swarm.go
generated
vendored
@@ -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.
|
||||
|
||||
32
vendor/github.com/docker/docker/api/types/types.go
generated
vendored
32
vendor/github.com/docker/docker/api/types/types.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
85
vendor/github.com/docker/docker/pkg/archive/archive.go
generated
vendored
85
vendor/github.com/docker/docker/pkg/archive/archive.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
10
vendor/github.com/docker/docker/pkg/archive/archive_unix.go
generated
vendored
10
vendor/github.com/docker/docker/pkg/archive/archive_unix.go
generated
vendored
@@ -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
|
||||
|
||||
18
vendor/github.com/docker/docker/pkg/archive/archive_windows.go
generated
vendored
18
vendor/github.com/docker/docker/pkg/archive/archive_windows.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
12
vendor/github.com/docker/docker/pkg/archive/changes.go
generated
vendored
12
vendor/github.com/docker/docker/pkg/archive/changes.go
generated
vendored
@@ -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))
|
||||
}
|
||||
|
||||
8
vendor/github.com/docker/docker/pkg/archive/changes_unix.go
generated
vendored
8
vendor/github.com/docker/docker/pkg/archive/changes_unix.go
generated
vendored
@@ -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
|
||||
|
||||
8
vendor/github.com/docker/docker/pkg/archive/changes_windows.go
generated
vendored
8
vendor/github.com/docker/docker/pkg/archive/changes_windows.go
generated
vendored
@@ -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
|
||||
|
||||
14
vendor/github.com/docker/docker/pkg/archive/diff.go
generated
vendored
14
vendor/github.com/docker/docker/pkg/archive/diff.go
generated
vendored
@@ -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)
|
||||
|
||||
97
vendor/github.com/docker/docker/pkg/archive/example_changes.go
generated
vendored
97
vendor/github.com/docker/docker/pkg/archive/example_changes.go
generated
vendored
@@ -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
|
||||
}
|
||||
2
vendor/github.com/docker/docker/pkg/fileutils/fileutils.go
generated
vendored
2
vendor/github.com/docker/docker/pkg/fileutils/fileutils.go
generated
vendored
@@ -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
|
||||
|
||||
45
vendor/github.com/docker/docker/pkg/idtools/idtools.go
generated
vendored
45
vendor/github.com/docker/docker/pkg/idtools/idtools.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
9
vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go
generated
vendored
9
vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go
generated
vendored
@@ -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
|
||||
|
||||
10
vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go
generated
vendored
10
vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
20
vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go
generated
vendored
20
vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
10
vendor/github.com/docker/docker/pkg/system/path_unix.go
generated
vendored
Normal file
10
vendor/github.com/docker/docker/pkg/system/path_unix.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
24
vendor/github.com/docker/docker/pkg/system/path_windows.go
generated
vendored
Normal file
24
vendor/github.com/docker/docker/pkg/system/path_windows.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
2
vendor/github.com/docker/docker/pkg/system/rm.go
generated
vendored
2
vendor/github.com/docker/docker/pkg/system/rm.go
generated
vendored
@@ -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)
|
||||
|
||||
72
vendor/github.com/docker/docker/pkg/system/syscall_windows.go
generated
vendored
72
vendor/github.com/docker/docker/pkg/system/syscall_windows.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
1
vendor/github.com/docker/docker/pkg/tarsum/tarsum_spec.md
generated
vendored
1
vendor/github.com/docker/docker/pkg/tarsum/tarsum_spec.md
generated
vendored
@@ -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.
|
||||
|
||||
|
||||
7
vendor/github.com/docker/docker/pkg/term/term_windows.go
generated
vendored
7
vendor/github.com/docker/docker/pkg/term/term_windows.go
generated
vendored
@@ -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.
|
||||
|
||||
4
vendor/github.com/docker/docker/registry/service_v2.go
generated
vendored
4
vendor/github.com/docker/docker/registry/service_v2.go
generated
vendored
@@ -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
|
||||
|
||||
14
vendor/github.com/fsouza/go-dockerclient/AUTHORS
generated
vendored
14
vendor/github.com/fsouza/go-dockerclient/AUTHORS
generated
vendored
@@ -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
|
||||
|
||||
12
vendor/github.com/fsouza/go-dockerclient/Gopkg.toml
generated
vendored
12
vendor/github.com/fsouza/go-dockerclient/Gopkg.toml
generated
vendored
@@ -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"
|
||||
|
||||
19
vendor/github.com/fsouza/go-dockerclient/LICENSE
generated
vendored
19
vendor/github.com/fsouza/go-dockerclient/LICENSE
generated
vendored
@@ -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
|
||||
|
||||
18
vendor/github.com/fsouza/go-dockerclient/Makefile
generated
vendored
18
vendor/github.com/fsouza/go-dockerclient/Makefile
generated
vendored
@@ -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 ./...
|
||||
|
||||
4
vendor/github.com/fsouza/go-dockerclient/appveyor.yml
generated
vendored
4
vendor/github.com/fsouza/go-dockerclient/appveyor.yml
generated
vendored
@@ -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
|
||||
|
||||
60
vendor/github.com/fsouza/go-dockerclient/auth.go
generated
vendored
60
vendor/github.com/fsouza/go-dockerclient/auth.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
38
vendor/github.com/fsouza/go-dockerclient/client.go
generated
vendored
38
vendor/github.com/fsouza/go-dockerclient/client.go
generated
vendored
@@ -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 {
|
||||
|
||||
13
vendor/github.com/fsouza/go-dockerclient/client_unix.go
generated
vendored
13
vendor/github.com/fsouza/go-dockerclient/client_unix.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
5
vendor/github.com/fsouza/go-dockerclient/client_windows.go
generated
vendored
5
vendor/github.com/fsouza/go-dockerclient/client_windows.go
generated
vendored
@@ -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)
|
||||
|
||||
30
vendor/github.com/fsouza/go-dockerclient/container.go
generated
vendored
30
vendor/github.com/fsouza/go-dockerclient/container.go
generated
vendored
@@ -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}
|
||||
|
||||
2
vendor/github.com/fsouza/go-dockerclient/env.go
generated
vendored
2
vendor/github.com/fsouza/go-dockerclient/env.go
generated
vendored
@@ -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)
|
||||
|
||||
17
vendor/github.com/fsouza/go-dockerclient/event.go
generated
vendored
17
vendor/github.com/fsouza/go-dockerclient/event.go
generated
vendored
@@ -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()
|
||||
|
||||
7
vendor/github.com/fsouza/go-dockerclient/exec.go
generated
vendored
7
vendor/github.com/fsouza/go-dockerclient/exec.go
generated
vendored
@@ -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 {
|
||||
|
||||
26
vendor/github.com/fsouza/go-dockerclient/go.mod
generated
vendored
Normal file
26
vendor/github.com/fsouza/go-dockerclient/go.mod
generated
vendored
Normal file
@@ -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
|
||||
)
|
||||
54
vendor/github.com/fsouza/go-dockerclient/go.sum
generated
vendored
Normal file
54
vendor/github.com/fsouza/go-dockerclient/go.sum
generated
vendored
Normal file
@@ -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=
|
||||
29
vendor/github.com/fsouza/go-dockerclient/image.go
generated
vendored
29
vendor/github.com/fsouza/go-dockerclient/image.go
generated
vendored
@@ -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
|
||||
|
||||
505
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go
generated
vendored
Normal file
505
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
104
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go
generated
vendored
Normal file
104
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_linux.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
11
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go
generated
vendored
Normal file
11
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_other.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
77
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go
generated
vendored
Normal file
77
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_unix.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
71
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go
generated
vendored
Normal file
71
vendor/github.com/fsouza/go-dockerclient/internal/archive/archive_windows.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
16
vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go
generated
vendored
Normal file
16
vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_unix.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
11
vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go
generated
vendored
Normal file
11
vendor/github.com/fsouza/go-dockerclient/internal/archive/changes_windows.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
29
vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go
generated
vendored
Normal file
29
vendor/github.com/fsouza/go-dockerclient/internal/archive/copy.go
generated
vendored
Normal file
@@ -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) == "."
|
||||
}
|
||||
27
vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go
generated
vendored
Normal file
27
vendor/github.com/fsouza/go-dockerclient/internal/archive/whiteouts.go
generated
vendored
Normal file
@@ -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"
|
||||
402
vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go
generated
vendored
Normal file
402
vendor/github.com/fsouza/go-dockerclient/internal/jsonmessage/jsonmessage.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
13
vendor/github.com/fsouza/go-dockerclient/internal/term/term.go
generated
vendored
Normal file
13
vendor/github.com/fsouza/go-dockerclient/internal/term/term.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
16
vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go
generated
vendored
Normal file
16
vendor/github.com/fsouza/go-dockerclient/internal/term/winsize.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
22
vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go
generated
vendored
Normal file
22
vendor/github.com/fsouza/go-dockerclient/internal/term/winsize_windows.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
17
vendor/github.com/fsouza/go-dockerclient/misc.go
generated
vendored
17
vendor/github.com/fsouza/go-dockerclient/misc.go
generated
vendored
@@ -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
|
||||
|
||||
8
vendor/github.com/fsouza/go-dockerclient/network.go
generated
vendored
8
vendor/github.com/fsouza/go-dockerclient/network.go
generated
vendored
@@ -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
|
||||
|
||||
418
vendor/github.com/fsouza/go-dockerclient/plugin.go
generated
vendored
Normal file
418
vendor/github.com/fsouza/go-dockerclient/plugin.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
10
vendor/github.com/fsouza/go-dockerclient/registry_auth.go
generated
vendored
Normal file
10
vendor/github.com/fsouza/go-dockerclient/registry_auth.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
2
vendor/github.com/fsouza/go-dockerclient/swarm.go
generated
vendored
2
vendor/github.com/fsouza/go-dockerclient/swarm.go
generated
vendored
@@ -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 (
|
||||
|
||||
2
vendor/github.com/fsouza/go-dockerclient/swarm_configs.go
generated
vendored
2
vendor/github.com/fsouza/go-dockerclient/swarm_configs.go
generated
vendored
@@ -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.
|
||||
|
||||
2
vendor/github.com/fsouza/go-dockerclient/swarm_node.go
generated
vendored
2
vendor/github.com/fsouza/go-dockerclient/swarm_node.go
generated
vendored
@@ -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.
|
||||
|
||||
2
vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go
generated
vendored
2
vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go
generated
vendored
@@ -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.
|
||||
|
||||
17
vendor/github.com/fsouza/go-dockerclient/swarm_service.go
generated
vendored
17
vendor/github.com/fsouza/go-dockerclient/swarm_service.go
generated
vendored
@@ -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,
|
||||
|
||||
2
vendor/github.com/fsouza/go-dockerclient/swarm_task.go
generated
vendored
2
vendor/github.com/fsouza/go-dockerclient/swarm_task.go
generated
vendored
@@ -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.
|
||||
|
||||
72
vendor/github.com/fsouza/go-dockerclient/system.go
generated
vendored
Normal file
72
vendor/github.com/fsouza/go-dockerclient/system.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
7
vendor/github.com/fsouza/go-dockerclient/tar.go
generated
vendored
7
vendor/github.com/fsouza/go-dockerclient/tar.go
generated
vendored
@@ -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
|
||||
|
||||
10
vendor/github.com/fsouza/go-dockerclient/tls.go
generated
vendored
10
vendor/github.com/fsouza/go-dockerclient/tls.go
generated
vendored
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
47
vendor/github.com/fsouza/go-dockerclient/volume.go
generated
vendored
47
vendor/github.com/fsouza/go-dockerclient/volume.go
generated
vendored
@@ -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})
|
||||
|
||||
65
vendor/vendor.json
vendored
65
vendor/vendor.json
vendored
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user