Remove unused vendor.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
69
vendor/github.com/docker/docker/pkg/parsers/parsers.go
generated
vendored
69
vendor/github.com/docker/docker/pkg/parsers/parsers.go
generated
vendored
@ -1,69 +0,0 @@
|
||||
// Package parsers provides helper functions to parse and validate different type
|
||||
// of string. It can be hosts, unix addresses, tcp addresses, filters, kernel
|
||||
// operating system versions.
|
||||
package parsers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseKeyValueOpt parses and validates the specified string as a key/value pair (key=value)
|
||||
func ParseKeyValueOpt(opt string) (string, string, error) {
|
||||
parts := strings.SplitN(opt, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", "", fmt.Errorf("Unable to parse key/value option: %s", opt)
|
||||
}
|
||||
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
||||
}
|
||||
|
||||
// ParseUintList parses and validates the specified string as the value
|
||||
// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be
|
||||
// one of the formats below. Note that duplicates are actually allowed in the
|
||||
// input string. It returns a `map[int]bool` with available elements from `val`
|
||||
// set to `true`.
|
||||
// Supported formats:
|
||||
// 7
|
||||
// 1-6
|
||||
// 0,3-4,7,8-10
|
||||
// 0-0,0,1-7
|
||||
// 03,1-3 <- this is gonna get parsed as [1,2,3]
|
||||
// 3,2,1
|
||||
// 0-2,3,1
|
||||
func ParseUintList(val string) (map[int]bool, error) {
|
||||
if val == "" {
|
||||
return map[int]bool{}, nil
|
||||
}
|
||||
|
||||
availableInts := make(map[int]bool)
|
||||
split := strings.Split(val, ",")
|
||||
errInvalidFormat := fmt.Errorf("invalid format: %s", val)
|
||||
|
||||
for _, r := range split {
|
||||
if !strings.Contains(r, "-") {
|
||||
v, err := strconv.Atoi(r)
|
||||
if err != nil {
|
||||
return nil, errInvalidFormat
|
||||
}
|
||||
availableInts[v] = true
|
||||
} else {
|
||||
split := strings.SplitN(r, "-", 2)
|
||||
min, err := strconv.Atoi(split[0])
|
||||
if err != nil {
|
||||
return nil, errInvalidFormat
|
||||
}
|
||||
max, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
return nil, errInvalidFormat
|
||||
}
|
||||
if max < min {
|
||||
return nil, errInvalidFormat
|
||||
}
|
||||
for i := min; i <= max; i++ {
|
||||
availableInts[i] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return availableInts, nil
|
||||
}
|
||||
1
vendor/github.com/docker/docker/pkg/sysinfo/README.md
generated
vendored
1
vendor/github.com/docker/docker/pkg/sysinfo/README.md
generated
vendored
@ -1 +0,0 @@
|
||||
SysInfo stores information about which features a kernel supports.
|
||||
12
vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go
generated
vendored
12
vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
// +build !linux,!windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// NumCPU returns the number of CPUs
|
||||
func NumCPU() int {
|
||||
return runtime.NumCPU()
|
||||
}
|
||||
43
vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go
generated
vendored
43
vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// numCPU queries the system for the count of threads available
|
||||
// for use to this process.
|
||||
//
|
||||
// Issues two syscalls.
|
||||
// Returns 0 on errors. Use |runtime.NumCPU| in that case.
|
||||
func numCPU() int {
|
||||
// Gets the affinity mask for a process: The very one invoking this function.
|
||||
pid, _, _ := syscall.RawSyscall(syscall.SYS_GETPID, 0, 0, 0)
|
||||
|
||||
var mask [1024 / 64]uintptr
|
||||
_, _, err := syscall.RawSyscall(syscall.SYS_SCHED_GETAFFINITY, pid, uintptr(len(mask)*8), uintptr(unsafe.Pointer(&mask[0])))
|
||||
if err != 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// For every available thread a bit is set in the mask.
|
||||
ncpu := 0
|
||||
for _, e := range mask {
|
||||
if e == 0 {
|
||||
continue
|
||||
}
|
||||
ncpu += int(popcnt(uint64(e)))
|
||||
}
|
||||
return ncpu
|
||||
}
|
||||
|
||||
// NumCPU returns the number of CPUs which are currently online
|
||||
func NumCPU() int {
|
||||
if ncpu := numCPU(); ncpu > 0 {
|
||||
return ncpu
|
||||
}
|
||||
return runtime.NumCPU()
|
||||
}
|
||||
37
vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go
generated
vendored
37
vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
getCurrentProcess = kernel32.NewProc("GetCurrentProcess")
|
||||
getProcessAffinityMask = kernel32.NewProc("GetProcessAffinityMask")
|
||||
)
|
||||
|
||||
func numCPU() int {
|
||||
// Gets the affinity mask for a process
|
||||
var mask, sysmask uintptr
|
||||
currentProcess, _, _ := getCurrentProcess.Call()
|
||||
ret, _, _ := getProcessAffinityMask.Call(currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
|
||||
if ret == 0 {
|
||||
return 0
|
||||
}
|
||||
// For every available thread a bit is set in the mask.
|
||||
ncpu := int(popcnt(uint64(mask)))
|
||||
return ncpu
|
||||
}
|
||||
|
||||
// NumCPU returns the number of CPUs which are currently online
|
||||
func NumCPU() int {
|
||||
if ncpu := numCPU(); ncpu > 0 {
|
||||
return ncpu
|
||||
}
|
||||
return runtime.NumCPU()
|
||||
}
|
||||
144
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go
generated
vendored
144
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go
generated
vendored
@ -1,144 +0,0 @@
|
||||
package sysinfo
|
||||
|
||||
import "github.com/docker/docker/pkg/parsers"
|
||||
|
||||
// SysInfo stores information about which features a kernel supports.
|
||||
// TODO Windows: Factor out platform specific capabilities.
|
||||
type SysInfo struct {
|
||||
// Whether the kernel supports AppArmor or not
|
||||
AppArmor bool
|
||||
// Whether the kernel supports Seccomp or not
|
||||
Seccomp bool
|
||||
|
||||
cgroupMemInfo
|
||||
cgroupCPUInfo
|
||||
cgroupBlkioInfo
|
||||
cgroupCpusetInfo
|
||||
cgroupPids
|
||||
|
||||
// Whether IPv4 forwarding is supported or not, if this was disabled, networking will not work
|
||||
IPv4ForwardingDisabled bool
|
||||
|
||||
// Whether bridge-nf-call-iptables is supported or not
|
||||
BridgeNFCallIPTablesDisabled bool
|
||||
|
||||
// Whether bridge-nf-call-ip6tables is supported or not
|
||||
BridgeNFCallIP6TablesDisabled bool
|
||||
|
||||
// Whether the cgroup has the mountpoint of "devices" or not
|
||||
CgroupDevicesEnabled bool
|
||||
}
|
||||
|
||||
type cgroupMemInfo struct {
|
||||
// Whether memory limit is supported or not
|
||||
MemoryLimit bool
|
||||
|
||||
// Whether swap limit is supported or not
|
||||
SwapLimit bool
|
||||
|
||||
// Whether soft limit is supported or not
|
||||
MemoryReservation bool
|
||||
|
||||
// Whether OOM killer disable is supported or not
|
||||
OomKillDisable bool
|
||||
|
||||
// Whether memory swappiness is supported or not
|
||||
MemorySwappiness bool
|
||||
|
||||
// Whether kernel memory limit is supported or not
|
||||
KernelMemory bool
|
||||
}
|
||||
|
||||
type cgroupCPUInfo struct {
|
||||
// Whether CPU shares is supported or not
|
||||
CPUShares bool
|
||||
|
||||
// Whether CPU CFS(Completely Fair Scheduler) period is supported or not
|
||||
CPUCfsPeriod bool
|
||||
|
||||
// Whether CPU CFS(Completely Fair Scheduler) quota is supported or not
|
||||
CPUCfsQuota bool
|
||||
|
||||
// Whether CPU real-time period is supported or not
|
||||
CPURealtimePeriod bool
|
||||
|
||||
// Whether CPU real-time runtime is supported or not
|
||||
CPURealtimeRuntime bool
|
||||
}
|
||||
|
||||
type cgroupBlkioInfo struct {
|
||||
// Whether Block IO weight is supported or not
|
||||
BlkioWeight bool
|
||||
|
||||
// Whether Block IO weight_device is supported or not
|
||||
BlkioWeightDevice bool
|
||||
|
||||
// Whether Block IO read limit in bytes per second is supported or not
|
||||
BlkioReadBpsDevice bool
|
||||
|
||||
// Whether Block IO write limit in bytes per second is supported or not
|
||||
BlkioWriteBpsDevice bool
|
||||
|
||||
// Whether Block IO read limit in IO per second is supported or not
|
||||
BlkioReadIOpsDevice bool
|
||||
|
||||
// Whether Block IO write limit in IO per second is supported or not
|
||||
BlkioWriteIOpsDevice bool
|
||||
}
|
||||
|
||||
type cgroupCpusetInfo struct {
|
||||
// Whether Cpuset is supported or not
|
||||
Cpuset bool
|
||||
|
||||
// Available Cpuset's cpus
|
||||
Cpus string
|
||||
|
||||
// Available Cpuset's memory nodes
|
||||
Mems string
|
||||
}
|
||||
|
||||
type cgroupPids struct {
|
||||
// Whether Pids Limit is supported or not
|
||||
PidsLimit bool
|
||||
}
|
||||
|
||||
// IsCpusetCpusAvailable returns `true` if the provided string set is contained
|
||||
// in cgroup's cpuset.cpus set, `false` otherwise.
|
||||
// If error is not nil a parsing error occurred.
|
||||
func (c cgroupCpusetInfo) IsCpusetCpusAvailable(provided string) (bool, error) {
|
||||
return isCpusetListAvailable(provided, c.Cpus)
|
||||
}
|
||||
|
||||
// IsCpusetMemsAvailable returns `true` if the provided string set is contained
|
||||
// in cgroup's cpuset.mems set, `false` otherwise.
|
||||
// If error is not nil a parsing error occurred.
|
||||
func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) {
|
||||
return isCpusetListAvailable(provided, c.Mems)
|
||||
}
|
||||
|
||||
func isCpusetListAvailable(provided, available string) (bool, error) {
|
||||
parsedProvided, err := parsers.ParseUintList(provided)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
parsedAvailable, err := parsers.ParseUintList(available)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for k := range parsedProvided {
|
||||
if !parsedAvailable[k] {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Returns bit count of 1, used by NumCPU
|
||||
func popcnt(x uint64) (n byte) {
|
||||
x -= (x >> 1) & 0x5555555555555555
|
||||
x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
|
||||
x += x >> 4
|
||||
x &= 0x0f0f0f0f0f0f0f0f
|
||||
x *= 0x0101010101010101
|
||||
return byte(x >> 56)
|
||||
}
|
||||
259
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go
generated
vendored
259
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go
generated
vendored
@ -1,259 +0,0 @@
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
)
|
||||
|
||||
const (
|
||||
// SeccompModeFilter refers to the syscall argument SECCOMP_MODE_FILTER.
|
||||
SeccompModeFilter = uintptr(2)
|
||||
)
|
||||
|
||||
func findCgroupMountpoints() (map[string]string, error) {
|
||||
cgMounts, err := cgroups.GetCgroupMounts(false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse cgroup information: %v", err)
|
||||
}
|
||||
mps := make(map[string]string)
|
||||
for _, m := range cgMounts {
|
||||
for _, ss := range m.Subsystems {
|
||||
mps[ss] = m.Mountpoint
|
||||
}
|
||||
}
|
||||
return mps, nil
|
||||
}
|
||||
|
||||
// New returns a new SysInfo, using the filesystem to detect which features
|
||||
// the kernel supports. If `quiet` is `false` warnings are printed in logs
|
||||
// whenever an error occurs or misconfigurations are present.
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
cgMounts, err := findCgroupMountpoints()
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to parse cgroup information: %v", err)
|
||||
} else {
|
||||
sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet)
|
||||
sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet)
|
||||
sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet)
|
||||
sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet)
|
||||
sysInfo.cgroupPids = checkCgroupPids(quiet)
|
||||
}
|
||||
|
||||
_, ok := cgMounts["devices"]
|
||||
sysInfo.CgroupDevicesEnabled = ok
|
||||
|
||||
sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
|
||||
sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
|
||||
sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
|
||||
|
||||
// Check if AppArmor is supported.
|
||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
|
||||
sysInfo.AppArmor = true
|
||||
}
|
||||
|
||||
// Check if Seccomp is supported, via CONFIG_SECCOMP.
|
||||
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL {
|
||||
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
|
||||
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL {
|
||||
sysInfo.Seccomp = true
|
||||
}
|
||||
}
|
||||
|
||||
return sysInfo
|
||||
}
|
||||
|
||||
// checkCgroupMem reads the memory information from the memory cgroup mount point.
|
||||
func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
|
||||
mountPoint, ok := cgMounts["memory"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Your kernel does not support cgroup memory limit")
|
||||
}
|
||||
return cgroupMemInfo{}
|
||||
}
|
||||
|
||||
swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
|
||||
if !quiet && !swapLimit {
|
||||
logrus.Warn("Your kernel does not support swap memory limit")
|
||||
}
|
||||
memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
|
||||
if !quiet && !memoryReservation {
|
||||
logrus.Warn("Your kernel does not support memory reservation")
|
||||
}
|
||||
oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
|
||||
if !quiet && !oomKillDisable {
|
||||
logrus.Warn("Your kernel does not support oom control")
|
||||
}
|
||||
memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
|
||||
if !quiet && !memorySwappiness {
|
||||
logrus.Warn("Your kernel does not support memory swappiness")
|
||||
}
|
||||
kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
|
||||
if !quiet && !kernelMemory {
|
||||
logrus.Warn("Your kernel does not support kernel memory limit")
|
||||
}
|
||||
|
||||
return cgroupMemInfo{
|
||||
MemoryLimit: true,
|
||||
SwapLimit: swapLimit,
|
||||
MemoryReservation: memoryReservation,
|
||||
OomKillDisable: oomKillDisable,
|
||||
MemorySwappiness: memorySwappiness,
|
||||
KernelMemory: kernelMemory,
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupCPU reads the cpu information from the cpu cgroup mount point.
|
||||
func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
|
||||
mountPoint, ok := cgMounts["cpu"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Unable to find cpu cgroup in mounts")
|
||||
}
|
||||
return cgroupCPUInfo{}
|
||||
}
|
||||
|
||||
cpuShares := cgroupEnabled(mountPoint, "cpu.shares")
|
||||
if !quiet && !cpuShares {
|
||||
logrus.Warn("Your kernel does not support cgroup cpu shares")
|
||||
}
|
||||
|
||||
cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us")
|
||||
if !quiet && !cpuCfsPeriod {
|
||||
logrus.Warn("Your kernel does not support cgroup cfs period")
|
||||
}
|
||||
|
||||
cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
|
||||
if !quiet && !cpuCfsQuota {
|
||||
logrus.Warn("Your kernel does not support cgroup cfs quotas")
|
||||
}
|
||||
|
||||
cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us")
|
||||
if !quiet && !cpuRealtimePeriod {
|
||||
logrus.Warn("Your kernel does not support cgroup rt period")
|
||||
}
|
||||
|
||||
cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
|
||||
if !quiet && !cpuRealtimeRuntime {
|
||||
logrus.Warn("Your kernel does not support cgroup rt runtime")
|
||||
}
|
||||
|
||||
return cgroupCPUInfo{
|
||||
CPUShares: cpuShares,
|
||||
CPUCfsPeriod: cpuCfsPeriod,
|
||||
CPUCfsQuota: cpuCfsQuota,
|
||||
CPURealtimePeriod: cpuRealtimePeriod,
|
||||
CPURealtimeRuntime: cpuRealtimeRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
|
||||
func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
|
||||
mountPoint, ok := cgMounts["blkio"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Unable to find blkio cgroup in mounts")
|
||||
}
|
||||
return cgroupBlkioInfo{}
|
||||
}
|
||||
|
||||
weight := cgroupEnabled(mountPoint, "blkio.weight")
|
||||
if !quiet && !weight {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio weight")
|
||||
}
|
||||
|
||||
weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
|
||||
if !quiet && !weightDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio weight_device")
|
||||
}
|
||||
|
||||
readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
|
||||
if !quiet && !readBpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
|
||||
}
|
||||
|
||||
writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
|
||||
if !quiet && !writeBpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
|
||||
}
|
||||
readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
|
||||
if !quiet && !readIOpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
|
||||
}
|
||||
|
||||
writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
|
||||
if !quiet && !writeIOpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
|
||||
}
|
||||
return cgroupBlkioInfo{
|
||||
BlkioWeight: weight,
|
||||
BlkioWeightDevice: weightDevice,
|
||||
BlkioReadBpsDevice: readBpsDevice,
|
||||
BlkioWriteBpsDevice: writeBpsDevice,
|
||||
BlkioReadIOpsDevice: readIOpsDevice,
|
||||
BlkioWriteIOpsDevice: writeIOpsDevice,
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
|
||||
func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
|
||||
mountPoint, ok := cgMounts["cpuset"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Unable to find cpuset cgroup in mounts")
|
||||
}
|
||||
return cgroupCpusetInfo{}
|
||||
}
|
||||
|
||||
cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
|
||||
if err != nil {
|
||||
return cgroupCpusetInfo{}
|
||||
}
|
||||
|
||||
mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
|
||||
if err != nil {
|
||||
return cgroupCpusetInfo{}
|
||||
}
|
||||
|
||||
return cgroupCpusetInfo{
|
||||
Cpuset: true,
|
||||
Cpus: strings.TrimSpace(string(cpus)),
|
||||
Mems: strings.TrimSpace(string(mems)),
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupPids reads the pids information from the pids cgroup mount point.
|
||||
func checkCgroupPids(quiet bool) cgroupPids {
|
||||
_, err := cgroups.FindCgroupMountpoint("pids")
|
||||
if err != nil {
|
||||
if !quiet {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
return cgroupPids{}
|
||||
}
|
||||
|
||||
return cgroupPids{
|
||||
PidsLimit: true,
|
||||
}
|
||||
}
|
||||
|
||||
func cgroupEnabled(mountPoint, name string) bool {
|
||||
_, err := os.Stat(path.Join(mountPoint, name))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func readProcBool(path string) bool {
|
||||
val, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.TrimSpace(string(val)) == "1"
|
||||
}
|
||||
121
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_solaris.go
generated
vendored
121
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_solaris.go
generated
vendored
@ -1,121 +0,0 @@
|
||||
// +build solaris,cgo
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -llgrp
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/lgrp_user.h>
|
||||
int getLgrpCount() {
|
||||
lgrp_cookie_t lgrpcookie = LGRP_COOKIE_NONE;
|
||||
uint_t nlgrps;
|
||||
|
||||
if ((lgrpcookie = lgrp_init(LGRP_VIEW_OS)) == LGRP_COOKIE_NONE) {
|
||||
return -1;
|
||||
}
|
||||
nlgrps = lgrp_nlgrps(lgrpcookie);
|
||||
return nlgrps;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// IsCPUSharesAvailable returns whether CPUShares setting is supported.
|
||||
// We need FSS to be set as default scheduling class to support CPU Shares
|
||||
func IsCPUSharesAvailable() bool {
|
||||
cmd := exec.Command("/usr/sbin/dispadmin", "-d")
|
||||
outBuf := new(bytes.Buffer)
|
||||
errBuf := new(bytes.Buffer)
|
||||
cmd.Stderr = errBuf
|
||||
cmd.Stdout = outBuf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return (strings.Contains(outBuf.String(), "FSS"))
|
||||
}
|
||||
|
||||
// New returns a new SysInfo, using the filesystem to detect which features
|
||||
// the kernel supports.
|
||||
//NOTE Solaris: If we change the below capabilities be sure
|
||||
// to update verifyPlatformContainerSettings() in daemon_solaris.go
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
sysInfo.cgroupMemInfo = setCgroupMem(quiet)
|
||||
sysInfo.cgroupCPUInfo = setCgroupCPU(quiet)
|
||||
sysInfo.cgroupBlkioInfo = setCgroupBlkioInfo(quiet)
|
||||
sysInfo.cgroupCpusetInfo = setCgroupCPUsetInfo(quiet)
|
||||
|
||||
sysInfo.IPv4ForwardingDisabled = false
|
||||
|
||||
sysInfo.AppArmor = false
|
||||
|
||||
return sysInfo
|
||||
}
|
||||
|
||||
// setCgroupMem reads the memory information for Solaris.
|
||||
func setCgroupMem(quiet bool) cgroupMemInfo {
|
||||
|
||||
return cgroupMemInfo{
|
||||
MemoryLimit: true,
|
||||
SwapLimit: true,
|
||||
MemoryReservation: false,
|
||||
OomKillDisable: false,
|
||||
MemorySwappiness: false,
|
||||
KernelMemory: false,
|
||||
}
|
||||
}
|
||||
|
||||
// setCgroupCPU reads the cpu information for Solaris.
|
||||
func setCgroupCPU(quiet bool) cgroupCPUInfo {
|
||||
|
||||
return cgroupCPUInfo{
|
||||
CPUShares: true,
|
||||
CPUCfsPeriod: false,
|
||||
CPUCfsQuota: true,
|
||||
CPURealtimePeriod: false,
|
||||
CPURealtimeRuntime: false,
|
||||
}
|
||||
}
|
||||
|
||||
// blkio switches are not supported in Solaris.
|
||||
func setCgroupBlkioInfo(quiet bool) cgroupBlkioInfo {
|
||||
|
||||
return cgroupBlkioInfo{
|
||||
BlkioWeight: false,
|
||||
BlkioWeightDevice: false,
|
||||
}
|
||||
}
|
||||
|
||||
// setCgroupCPUsetInfo reads the cpuset information for Solaris.
|
||||
func setCgroupCPUsetInfo(quiet bool) cgroupCpusetInfo {
|
||||
|
||||
return cgroupCpusetInfo{
|
||||
Cpuset: true,
|
||||
Cpus: getCPUCount(),
|
||||
Mems: getLgrpCount(),
|
||||
}
|
||||
}
|
||||
|
||||
func getCPUCount() string {
|
||||
ncpus := C.sysconf(C._SC_NPROCESSORS_ONLN)
|
||||
if ncpus <= 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatInt(int64(ncpus), 16)
|
||||
}
|
||||
|
||||
func getLgrpCount() string {
|
||||
nlgrps := C.getLgrpCount()
|
||||
if nlgrps <= 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatInt(int64(nlgrps), 16)
|
||||
}
|
||||
9
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go
generated
vendored
9
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go
generated
vendored
@ -1,9 +0,0 @@
|
||||
// +build !linux,!solaris,!windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
// New returns an empty SysInfo for non linux nor solaris for now.
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
return sysInfo
|
||||
}
|
||||
9
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go
generated
vendored
9
vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go
generated
vendored
@ -1,9 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
// New returns an empty SysInfo for windows for now.
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
return sysInfo
|
||||
}
|
||||
108
vendor/github.com/docker/docker/runconfig/config.go
generated
vendored
108
vendor/github.com/docker/docker/runconfig/config.go
generated
vendored
@ -1,108 +0,0 @@
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/volume"
|
||||
)
|
||||
|
||||
// ContainerDecoder implements httputils.ContainerDecoder
|
||||
// calling DecodeContainerConfig.
|
||||
type ContainerDecoder struct{}
|
||||
|
||||
// DecodeConfig makes ContainerDecoder to implement httputils.ContainerDecoder
|
||||
func (r ContainerDecoder) DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
|
||||
return DecodeContainerConfig(src)
|
||||
}
|
||||
|
||||
// DecodeHostConfig makes ContainerDecoder to implement httputils.ContainerDecoder
|
||||
func (r ContainerDecoder) DecodeHostConfig(src io.Reader) (*container.HostConfig, error) {
|
||||
return DecodeHostConfig(src)
|
||||
}
|
||||
|
||||
// DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper
|
||||
// struct and returns both a Config and a HostConfig struct
|
||||
// Be aware this function is not checking whether the resulted structs are nil,
|
||||
// it's your business to do so
|
||||
func DecodeContainerConfig(src io.Reader) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
|
||||
var w ContainerConfigWrapper
|
||||
|
||||
decoder := json.NewDecoder(src)
|
||||
if err := decoder.Decode(&w); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
hc := w.getHostConfig()
|
||||
|
||||
// Perform platform-specific processing of Volumes and Binds.
|
||||
if w.Config != nil && hc != nil {
|
||||
|
||||
// Initialize the volumes map if currently nil
|
||||
if w.Config.Volumes == nil {
|
||||
w.Config.Volumes = make(map[string]struct{})
|
||||
}
|
||||
|
||||
// Now validate all the volumes and binds
|
||||
if err := validateMountSettings(w.Config, hc); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Certain parameters need daemon-side validation that cannot be done
|
||||
// on the client, as only the daemon knows what is valid for the platform.
|
||||
if err := validateNetMode(w.Config, hc); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Validate isolation
|
||||
if err := validateIsolation(hc); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Validate QoS
|
||||
if err := validateQoS(hc); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Validate Resources
|
||||
if err := validateResources(hc, sysinfo.New(true)); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Validate Privileged
|
||||
if err := validatePrivileged(hc); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Validate ReadonlyRootfs
|
||||
if err := validateReadonlyRootfs(hc); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return w.Config, hc, w.NetworkingConfig, nil
|
||||
}
|
||||
|
||||
// validateMountSettings validates each of the volumes and bind settings
|
||||
// passed by the caller to ensure they are valid.
|
||||
func validateMountSettings(c *container.Config, hc *container.HostConfig) error {
|
||||
// it is ok to have len(hc.Mounts) > 0 && (len(hc.Binds) > 0 || len (c.Volumes) > 0 || len (hc.Tmpfs) > 0 )
|
||||
|
||||
// Ensure all volumes and binds are valid.
|
||||
for spec := range c.Volumes {
|
||||
if _, err := volume.ParseMountRaw(spec, hc.VolumeDriver); err != nil {
|
||||
return fmt.Errorf("invalid volume spec %q: %v", spec, err)
|
||||
}
|
||||
}
|
||||
for _, spec := range hc.Binds {
|
||||
if _, err := volume.ParseMountRaw(spec, hc.VolumeDriver); err != nil {
|
||||
return fmt.Errorf("invalid bind mount spec %q: %v", spec, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
59
vendor/github.com/docker/docker/runconfig/config_unix.go
generated
vendored
59
vendor/github.com/docker/docker/runconfig/config_unix.go
generated
vendored
@ -1,59 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
)
|
||||
|
||||
// ContainerConfigWrapper is a Config wrapper that holds the container Config (portable)
|
||||
// and the corresponding HostConfig (non-portable).
|
||||
type ContainerConfigWrapper struct {
|
||||
*container.Config
|
||||
InnerHostConfig *container.HostConfig `json:"HostConfig,omitempty"`
|
||||
Cpuset string `json:",omitempty"` // Deprecated. Exported for backwards compatibility.
|
||||
NetworkingConfig *networktypes.NetworkingConfig `json:"NetworkingConfig,omitempty"`
|
||||
*container.HostConfig // Deprecated. Exported to read attributes from json that are not in the inner host config structure.
|
||||
}
|
||||
|
||||
// getHostConfig gets the HostConfig of the Config.
|
||||
// It's mostly there to handle Deprecated fields of the ContainerConfigWrapper
|
||||
func (w *ContainerConfigWrapper) getHostConfig() *container.HostConfig {
|
||||
hc := w.HostConfig
|
||||
|
||||
if hc == nil && w.InnerHostConfig != nil {
|
||||
hc = w.InnerHostConfig
|
||||
} else if w.InnerHostConfig != nil {
|
||||
if hc.Memory != 0 && w.InnerHostConfig.Memory == 0 {
|
||||
w.InnerHostConfig.Memory = hc.Memory
|
||||
}
|
||||
if hc.MemorySwap != 0 && w.InnerHostConfig.MemorySwap == 0 {
|
||||
w.InnerHostConfig.MemorySwap = hc.MemorySwap
|
||||
}
|
||||
if hc.CPUShares != 0 && w.InnerHostConfig.CPUShares == 0 {
|
||||
w.InnerHostConfig.CPUShares = hc.CPUShares
|
||||
}
|
||||
if hc.CpusetCpus != "" && w.InnerHostConfig.CpusetCpus == "" {
|
||||
w.InnerHostConfig.CpusetCpus = hc.CpusetCpus
|
||||
}
|
||||
|
||||
if hc.VolumeDriver != "" && w.InnerHostConfig.VolumeDriver == "" {
|
||||
w.InnerHostConfig.VolumeDriver = hc.VolumeDriver
|
||||
}
|
||||
|
||||
hc = w.InnerHostConfig
|
||||
}
|
||||
|
||||
if hc != nil {
|
||||
if w.Cpuset != "" && hc.CpusetCpus == "" {
|
||||
hc.CpusetCpus = w.Cpuset
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure NetworkMode has an acceptable value. We do this to ensure
|
||||
// backwards compatible API behavior.
|
||||
SetDefaultNetModeIfBlank(hc)
|
||||
|
||||
return hc
|
||||
}
|
||||
19
vendor/github.com/docker/docker/runconfig/config_windows.go
generated
vendored
19
vendor/github.com/docker/docker/runconfig/config_windows.go
generated
vendored
@ -1,19 +0,0 @@
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
)
|
||||
|
||||
// ContainerConfigWrapper is a Config wrapper that holds the container Config (portable)
|
||||
// and the corresponding HostConfig (non-portable).
|
||||
type ContainerConfigWrapper struct {
|
||||
*container.Config
|
||||
HostConfig *container.HostConfig `json:"HostConfig,omitempty"`
|
||||
NetworkingConfig *networktypes.NetworkingConfig `json:"NetworkingConfig,omitempty"`
|
||||
}
|
||||
|
||||
// getHostConfig gets the HostConfig of the Config.
|
||||
func (w *ContainerConfigWrapper) getHostConfig() *container.HostConfig {
|
||||
return w.HostConfig
|
||||
}
|
||||
38
vendor/github.com/docker/docker/runconfig/errors.go
generated
vendored
38
vendor/github.com/docker/docker/runconfig/errors.go
generated
vendored
@ -1,38 +0,0 @@
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrConflictContainerNetworkAndLinks conflict between --net=container and links
|
||||
ErrConflictContainerNetworkAndLinks = fmt.Errorf("conflicting options: container type network can't be used with links. This would result in undefined behavior")
|
||||
// ErrConflictSharedNetwork conflict between private and other networks
|
||||
ErrConflictSharedNetwork = fmt.Errorf("container sharing network namespace with another container or host cannot be connected to any other network")
|
||||
// ErrConflictHostNetwork conflict from being disconnected from host network or connected to host network.
|
||||
ErrConflictHostNetwork = fmt.Errorf("container cannot be disconnected from host network or connected to host network")
|
||||
// ErrConflictNoNetwork conflict between private and other networks
|
||||
ErrConflictNoNetwork = fmt.Errorf("container cannot be connected to multiple networks with one of the networks in private (none) mode")
|
||||
// ErrConflictNetworkAndDNS conflict between --dns and the network mode
|
||||
ErrConflictNetworkAndDNS = fmt.Errorf("conflicting options: dns and the network mode")
|
||||
// ErrConflictNetworkHostname conflict between the hostname and the network mode
|
||||
ErrConflictNetworkHostname = fmt.Errorf("conflicting options: hostname and the network mode")
|
||||
// ErrConflictHostNetworkAndLinks conflict between --net=host and links
|
||||
ErrConflictHostNetworkAndLinks = fmt.Errorf("conflicting options: host type networking can't be used with links. This would result in undefined behavior")
|
||||
// ErrConflictContainerNetworkAndMac conflict between the mac address and the network mode
|
||||
ErrConflictContainerNetworkAndMac = fmt.Errorf("conflicting options: mac-address and the network mode")
|
||||
// ErrConflictNetworkHosts conflict between add-host and the network mode
|
||||
ErrConflictNetworkHosts = fmt.Errorf("conflicting options: custom host-to-IP mapping and the network mode")
|
||||
// ErrConflictNetworkPublishPorts conflict between the publish options and the network mode
|
||||
ErrConflictNetworkPublishPorts = fmt.Errorf("conflicting options: port publishing and the container type network mode")
|
||||
// ErrConflictNetworkExposePorts conflict between the expose option and the network mode
|
||||
ErrConflictNetworkExposePorts = fmt.Errorf("conflicting options: port exposing and the container type network mode")
|
||||
// ErrUnsupportedNetworkAndIP conflict between network mode and requested ip address
|
||||
ErrUnsupportedNetworkAndIP = fmt.Errorf("user specified IP address is supported on user defined networks only")
|
||||
// ErrUnsupportedNetworkNoSubnetAndIP conflict between network with no configured subnet and requested ip address
|
||||
ErrUnsupportedNetworkNoSubnetAndIP = fmt.Errorf("user specified IP address is supported only when connecting to networks with user configured subnets")
|
||||
// ErrUnsupportedNetworkAndAlias conflict between network mode and alias
|
||||
ErrUnsupportedNetworkAndAlias = fmt.Errorf("network-scoped alias is supported only for containers in user defined networks")
|
||||
// ErrConflictUTSHostname conflict between the hostname and the UTS mode
|
||||
ErrConflictUTSHostname = fmt.Errorf("conflicting options: hostname and the UTS mode")
|
||||
)
|
||||
80
vendor/github.com/docker/docker/runconfig/hostconfig.go
generated
vendored
80
vendor/github.com/docker/docker/runconfig/hostconfig.go
generated
vendored
@ -1,80 +0,0 @@
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
)
|
||||
|
||||
// DecodeHostConfig creates a HostConfig based on the specified Reader.
|
||||
// It assumes the content of the reader will be JSON, and decodes it.
|
||||
func DecodeHostConfig(src io.Reader) (*container.HostConfig, error) {
|
||||
decoder := json.NewDecoder(src)
|
||||
|
||||
var w ContainerConfigWrapper
|
||||
if err := decoder.Decode(&w); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hc := w.getHostConfig()
|
||||
return hc, nil
|
||||
}
|
||||
|
||||
// SetDefaultNetModeIfBlank changes the NetworkMode in a HostConfig structure
|
||||
// to default if it is not populated. This ensures backwards compatibility after
|
||||
// the validation of the network mode was moved from the docker CLI to the
|
||||
// docker daemon.
|
||||
func SetDefaultNetModeIfBlank(hc *container.HostConfig) {
|
||||
if hc != nil {
|
||||
if hc.NetworkMode == container.NetworkMode("") {
|
||||
hc.NetworkMode = container.NetworkMode("default")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validateNetContainerMode ensures that the various combinations of requested
|
||||
// network settings wrt container mode are valid.
|
||||
func validateNetContainerMode(c *container.Config, hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
parts := strings.Split(string(hc.NetworkMode), ":")
|
||||
if parts[0] == "container" {
|
||||
if len(parts) < 2 || parts[1] == "" {
|
||||
return fmt.Errorf("Invalid network mode: invalid container format container:<name|id>")
|
||||
}
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsContainer() && c.Hostname != "" {
|
||||
return ErrConflictNetworkHostname
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsContainer() && len(hc.Links) > 0 {
|
||||
return ErrConflictContainerNetworkAndLinks
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsContainer() && len(hc.DNS) > 0 {
|
||||
return ErrConflictNetworkAndDNS
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsContainer() && len(hc.ExtraHosts) > 0 {
|
||||
return ErrConflictNetworkHosts
|
||||
}
|
||||
|
||||
if (hc.NetworkMode.IsContainer() || hc.NetworkMode.IsHost()) && c.MacAddress != "" {
|
||||
return ErrConflictContainerNetworkAndMac
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsContainer() && (len(hc.PortBindings) > 0 || hc.PublishAllPorts == true) {
|
||||
return ErrConflictNetworkPublishPorts
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsContainer() && len(c.ExposedPorts) > 0 {
|
||||
return ErrConflictNetworkExposePorts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
46
vendor/github.com/docker/docker/runconfig/hostconfig_solaris.go
generated
vendored
46
vendor/github.com/docker/docker/runconfig/hostconfig_solaris.go
generated
vendored
@ -1,46 +0,0 @@
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
)
|
||||
|
||||
// DefaultDaemonNetworkMode returns the default network stack the daemon should
|
||||
// use.
|
||||
func DefaultDaemonNetworkMode() container.NetworkMode {
|
||||
return container.NetworkMode("bridge")
|
||||
}
|
||||
|
||||
// IsPreDefinedNetwork indicates if a network is predefined by the daemon
|
||||
func IsPreDefinedNetwork(network string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// validateNetMode ensures that the various combinations of requested
|
||||
// network settings are valid.
|
||||
func validateNetMode(c *container.Config, hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateIsolation performs platform specific validation of the
|
||||
// isolation level in the hostconfig structure.
|
||||
// This setting is currently discarded for Solaris so this is a no-op.
|
||||
func validateIsolation(hc *container.HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateQoS performs platform specific validation of the QoS settings
|
||||
func validateQoS(hc *container.HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateResources performs platform specific validation of the resource settings
|
||||
func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePrivileged performs platform specific validation of the Privileged setting
|
||||
func validatePrivileged(hc *container.HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
110
vendor/github.com/docker/docker/runconfig/hostconfig_unix.go
generated
vendored
110
vendor/github.com/docker/docker/runconfig/hostconfig_unix.go
generated
vendored
@ -1,110 +0,0 @@
|
||||
// +build !windows,!solaris
|
||||
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
)
|
||||
|
||||
// DefaultDaemonNetworkMode returns the default network stack the daemon should
|
||||
// use.
|
||||
func DefaultDaemonNetworkMode() container.NetworkMode {
|
||||
return container.NetworkMode("bridge")
|
||||
}
|
||||
|
||||
// IsPreDefinedNetwork indicates if a network is predefined by the daemon
|
||||
func IsPreDefinedNetwork(network string) bool {
|
||||
n := container.NetworkMode(network)
|
||||
return n.IsBridge() || n.IsHost() || n.IsNone() || n.IsDefault()
|
||||
}
|
||||
|
||||
// validateNetMode ensures that the various combinations of requested
|
||||
// network settings are valid.
|
||||
func validateNetMode(c *container.Config, hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := validateNetContainerMode(c, hc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hc.UTSMode.IsHost() && c.Hostname != "" {
|
||||
return ErrConflictUTSHostname
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsHost() && len(hc.Links) > 0 {
|
||||
return ErrConflictHostNetworkAndLinks
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateIsolation performs platform specific validation of
|
||||
// isolation in the hostconfig structure. Linux only supports "default"
|
||||
// which is LXC container isolation
|
||||
func validateIsolation(hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
if !hc.Isolation.IsValid() {
|
||||
return fmt.Errorf("Invalid isolation: %q - %s only supports 'default'", hc.Isolation, runtime.GOOS)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateQoS performs platform specific validation of the QoS settings
|
||||
func validateQoS(hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if hc.IOMaximumBandwidth != 0 {
|
||||
return fmt.Errorf("Invalid QoS settings: %s does not support configuration of maximum bandwidth", runtime.GOOS)
|
||||
}
|
||||
|
||||
if hc.IOMaximumIOps != 0 {
|
||||
return fmt.Errorf("Invalid QoS settings: %s does not support configuration of maximum IOPs", runtime.GOOS)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateResources performs platform specific validation of the resource settings
|
||||
// cpu-rt-runtime and cpu-rt-period can not be greater than their parent, cpu-rt-runtime requires sys_nice
|
||||
func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if hc.Resources.CPURealtimePeriod > 0 && !si.CPURealtimePeriod {
|
||||
return fmt.Errorf("Your kernel does not support cgroup cpu real-time period")
|
||||
}
|
||||
|
||||
if hc.Resources.CPURealtimeRuntime > 0 && !si.CPURealtimeRuntime {
|
||||
return fmt.Errorf("Your kernel does not support cgroup cpu real-time runtime")
|
||||
}
|
||||
|
||||
if hc.Resources.CPURealtimePeriod != 0 && hc.Resources.CPURealtimeRuntime != 0 && hc.Resources.CPURealtimeRuntime > hc.Resources.CPURealtimePeriod {
|
||||
return fmt.Errorf("cpu real-time runtime cannot be higher than cpu real-time period")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePrivileged performs platform specific validation of the Privileged setting
|
||||
func validatePrivileged(hc *container.HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateReadonlyRootfs performs platform specific validation of the ReadonlyRootfs setting
|
||||
func validateReadonlyRootfs(hc *container.HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
96
vendor/github.com/docker/docker/runconfig/hostconfig_windows.go
generated
vendored
96
vendor/github.com/docker/docker/runconfig/hostconfig_windows.go
generated
vendored
@ -1,96 +0,0 @@
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
)
|
||||
|
||||
// DefaultDaemonNetworkMode returns the default network stack the daemon should
|
||||
// use.
|
||||
func DefaultDaemonNetworkMode() container.NetworkMode {
|
||||
return container.NetworkMode("nat")
|
||||
}
|
||||
|
||||
// IsPreDefinedNetwork indicates if a network is predefined by the daemon
|
||||
func IsPreDefinedNetwork(network string) bool {
|
||||
return !container.NetworkMode(network).IsUserDefined()
|
||||
}
|
||||
|
||||
// validateNetMode ensures that the various combinations of requested
|
||||
// network settings are valid.
|
||||
func validateNetMode(c *container.Config, hc *container.HostConfig) error {
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := validateNetContainerMode(c, hc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hc.NetworkMode.IsContainer() && hc.Isolation.IsHyperV() {
|
||||
return fmt.Errorf("Using the network stack of another container is not supported while using Hyper-V Containers")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateIsolation performs platform specific validation of the
|
||||
// isolation in the hostconfig structure. Windows supports 'default' (or
|
||||
// blank), 'process', or 'hyperv'.
|
||||
func validateIsolation(hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
if !hc.Isolation.IsValid() {
|
||||
return fmt.Errorf("Invalid isolation: %q. Windows supports 'default', 'process', or 'hyperv'", hc.Isolation)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateQoS performs platform specific validation of the Qos settings
|
||||
func validateQoS(hc *container.HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateResources performs platform specific validation of the resource settings
|
||||
func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
if hc.Resources.CPURealtimePeriod != 0 {
|
||||
return fmt.Errorf("Windows does not support CPU real-time period")
|
||||
}
|
||||
if hc.Resources.CPURealtimeRuntime != 0 {
|
||||
return fmt.Errorf("Windows does not support CPU real-time runtime")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePrivileged performs platform specific validation of the Privileged setting
|
||||
func validatePrivileged(hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
if hc.Privileged {
|
||||
return fmt.Errorf("Windows does not support privileged mode")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateReadonlyRootfs performs platform specific validation of the ReadonlyRootfs setting
|
||||
func validateReadonlyRootfs(hc *container.HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
if hc.ReadonlyRootfs {
|
||||
return fmt.Errorf("Windows does not support root filesystem in read-only mode")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
140
vendor/github.com/docker/docker/volume/validate.go
generated
vendored
140
vendor/github.com/docker/docker/volume/validate.go
generated
vendored
@ -1,140 +0,0 @@
|
||||
package volume
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
)
|
||||
|
||||
var errBindNotExist = errors.New("bind source path does not exist")
|
||||
|
||||
type validateOpts struct {
|
||||
skipBindSourceCheck bool
|
||||
skipAbsolutePathCheck bool
|
||||
}
|
||||
|
||||
func validateMountConfig(mnt *mount.Mount, options ...func(*validateOpts)) error {
|
||||
opts := validateOpts{}
|
||||
for _, o := range options {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
if len(mnt.Target) == 0 {
|
||||
return &errMountConfig{mnt, errMissingField("Target")}
|
||||
}
|
||||
|
||||
if err := validateNotRoot(mnt.Target); err != nil {
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
|
||||
if !opts.skipAbsolutePathCheck {
|
||||
if err := validateAbsolute(mnt.Target); err != nil {
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
}
|
||||
|
||||
switch mnt.Type {
|
||||
case mount.TypeBind:
|
||||
if len(mnt.Source) == 0 {
|
||||
return &errMountConfig{mnt, errMissingField("Source")}
|
||||
}
|
||||
// Don't error out just because the propagation mode is not supported on the platform
|
||||
if opts := mnt.BindOptions; opts != nil {
|
||||
if len(opts.Propagation) > 0 && len(propagationModes) > 0 {
|
||||
if _, ok := propagationModes[opts.Propagation]; !ok {
|
||||
return &errMountConfig{mnt, fmt.Errorf("invalid propagation mode: %s", opts.Propagation)}
|
||||
}
|
||||
}
|
||||
}
|
||||
if mnt.VolumeOptions != nil {
|
||||
return &errMountConfig{mnt, errExtraField("VolumeOptions")}
|
||||
}
|
||||
|
||||
if err := validateAbsolute(mnt.Source); err != nil {
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
|
||||
// Do not allow binding to non-existent path
|
||||
if !opts.skipBindSourceCheck {
|
||||
fi, err := os.Stat(mnt.Source)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
return &errMountConfig{mnt, errBindNotExist}
|
||||
}
|
||||
if err := validateStat(fi); err != nil {
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
}
|
||||
case mount.TypeVolume:
|
||||
if mnt.BindOptions != nil {
|
||||
return &errMountConfig{mnt, errExtraField("BindOptions")}
|
||||
}
|
||||
|
||||
if len(mnt.Source) == 0 && mnt.ReadOnly {
|
||||
return &errMountConfig{mnt, fmt.Errorf("must not set ReadOnly mode when using anonymous volumes")}
|
||||
}
|
||||
|
||||
if len(mnt.Source) != 0 {
|
||||
if valid, err := IsVolumeNameValid(mnt.Source); !valid {
|
||||
if err == nil {
|
||||
err = errors.New("invalid volume name")
|
||||
}
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
}
|
||||
case mount.TypeTmpfs:
|
||||
if len(mnt.Source) != 0 {
|
||||
return &errMountConfig{mnt, errExtraField("Source")}
|
||||
}
|
||||
if err := ValidateTmpfsMountDestination(mnt.Target); err != nil {
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
if _, err := ConvertTmpfsOptions(mnt.TmpfsOptions, mnt.ReadOnly); err != nil {
|
||||
return &errMountConfig{mnt, err}
|
||||
}
|
||||
default:
|
||||
return &errMountConfig{mnt, errors.New("mount type unknown")}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type errMountConfig struct {
|
||||
mount *mount.Mount
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *errMountConfig) Error() string {
|
||||
return fmt.Sprintf("invalid mount config for type %q: %v", e.mount.Type, e.err.Error())
|
||||
}
|
||||
|
||||
func errExtraField(name string) error {
|
||||
return fmt.Errorf("field %s must not be specified", name)
|
||||
}
|
||||
func errMissingField(name string) error {
|
||||
return fmt.Errorf("field %s must not be empty", name)
|
||||
}
|
||||
|
||||
func validateAbsolute(p string) error {
|
||||
p = convertSlash(p)
|
||||
if filepath.IsAbs(p) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid mount path: '%s' mount path must be absolute", p)
|
||||
}
|
||||
|
||||
// ValidateTmpfsMountDestination validates the destination of tmpfs mount.
|
||||
// Currently, we have only two obvious rule for validation:
|
||||
// - path must not be "/"
|
||||
// - path must be absolute
|
||||
// We should add more rules carefully (#30166)
|
||||
func ValidateTmpfsMountDestination(dest string) error {
|
||||
if err := validateNotRoot(dest); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateAbsolute(dest)
|
||||
}
|
||||
8
vendor/github.com/docker/docker/volume/validate_test_unix.go
generated
vendored
8
vendor/github.com/docker/docker/volume/validate_test_unix.go
generated
vendored
@ -1,8 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package volume
|
||||
|
||||
var (
|
||||
testDestinationPath = "/foo"
|
||||
testSourcePath = "/foo"
|
||||
)
|
||||
6
vendor/github.com/docker/docker/volume/validate_test_windows.go
generated
vendored
6
vendor/github.com/docker/docker/volume/validate_test_windows.go
generated
vendored
@ -1,6 +0,0 @@
|
||||
package volume
|
||||
|
||||
var (
|
||||
testDestinationPath = `c:\foo`
|
||||
testSourcePath = `c:\foo`
|
||||
)
|
||||
374
vendor/github.com/docker/docker/volume/volume.go
generated
vendored
374
vendor/github.com/docker/docker/volume/volume.go
generated
vendored
@ -1,374 +0,0 @@
|
||||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// DefaultDriverName is the driver name used for the driver
|
||||
// implemented in the local package.
|
||||
const DefaultDriverName = "local"
|
||||
|
||||
// Scopes define if a volume has is cluster-wide (global) or local only.
|
||||
// Scopes are returned by the volume driver when it is queried for capabilities and then set on a volume
|
||||
const (
|
||||
LocalScope = "local"
|
||||
GlobalScope = "global"
|
||||
)
|
||||
|
||||
// Driver is for creating and removing volumes.
|
||||
type Driver interface {
|
||||
// Name returns the name of the volume driver.
|
||||
Name() string
|
||||
// Create makes a new volume with the given name.
|
||||
Create(name string, opts map[string]string) (Volume, error)
|
||||
// Remove deletes the volume.
|
||||
Remove(vol Volume) (err error)
|
||||
// List lists all the volumes the driver has
|
||||
List() ([]Volume, error)
|
||||
// Get retrieves the volume with the requested name
|
||||
Get(name string) (Volume, error)
|
||||
// Scope returns the scope of the driver (e.g. `global` or `local`).
|
||||
// Scope determines how the driver is handled at a cluster level
|
||||
Scope() string
|
||||
}
|
||||
|
||||
// Capability defines a set of capabilities that a driver is able to handle.
|
||||
type Capability struct {
|
||||
// Scope is the scope of the driver, `global` or `local`
|
||||
// A `global` scope indicates that the driver manages volumes across the cluster
|
||||
// A `local` scope indicates that the driver only manages volumes resources local to the host
|
||||
// Scope is declared by the driver
|
||||
Scope string
|
||||
}
|
||||
|
||||
// Volume is a place to store data. It is backed by a specific driver, and can be mounted.
|
||||
type Volume interface {
|
||||
// Name returns the name of the volume
|
||||
Name() string
|
||||
// DriverName returns the name of the driver which owns this volume.
|
||||
DriverName() string
|
||||
// Path returns the absolute path to the volume.
|
||||
Path() string
|
||||
// Mount mounts the volume and returns the absolute path to
|
||||
// where it can be consumed.
|
||||
Mount(id string) (string, error)
|
||||
// Unmount unmounts the volume when it is no longer in use.
|
||||
Unmount(id string) error
|
||||
// CreatedAt returns Volume Creation time
|
||||
CreatedAt() (time.Time, error)
|
||||
// Status returns low-level status information about a volume
|
||||
Status() map[string]interface{}
|
||||
}
|
||||
|
||||
// DetailedVolume wraps a Volume with user-defined labels, options, and cluster scope (e.g., `local` or `global`)
|
||||
type DetailedVolume interface {
|
||||
Labels() map[string]string
|
||||
Options() map[string]string
|
||||
Scope() string
|
||||
Volume
|
||||
}
|
||||
|
||||
// MountPoint is the intersection point between a volume and a container. It
|
||||
// specifies which volume is to be used and where inside a container it should
|
||||
// be mounted.
|
||||
type MountPoint struct {
|
||||
// Source is the source path of the mount.
|
||||
// E.g. `mount --bind /foo /bar`, `/foo` is the `Source`.
|
||||
Source string
|
||||
// Destination is the path relative to the container root (`/`) to the mount point
|
||||
// It is where the `Source` is mounted to
|
||||
Destination string
|
||||
// RW is set to true when the mountpoint should be mounted as read-write
|
||||
RW bool
|
||||
// Name is the name reference to the underlying data defined by `Source`
|
||||
// e.g., the volume name
|
||||
Name string
|
||||
// Driver is the volume driver used to create the volume (if it is a volume)
|
||||
Driver string
|
||||
// Type of mount to use, see `Type<foo>` definitions in github.com/docker/docker/api/types/mount
|
||||
Type mounttypes.Type `json:",omitempty"`
|
||||
// Volume is the volume providing data to this mountpoint.
|
||||
// This is nil unless `Type` is set to `TypeVolume`
|
||||
Volume Volume `json:"-"`
|
||||
|
||||
// Mode is the comma separated list of options supplied by the user when creating
|
||||
// the bind/volume mount.
|
||||
// Note Mode is not used on Windows
|
||||
Mode string `json:"Relabel,omitempty"` // Originally field was `Relabel`"
|
||||
|
||||
// Propagation describes how the mounts are propagated from the host into the
|
||||
// mount point, and vice-versa.
|
||||
// See https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
|
||||
// Note Propagation is not used on Windows
|
||||
Propagation mounttypes.Propagation `json:",omitempty"` // Mount propagation string
|
||||
|
||||
// Specifies if data should be copied from the container before the first mount
|
||||
// Use a pointer here so we can tell if the user set this value explicitly
|
||||
// This allows us to error out when the user explicitly enabled copy but we can't copy due to the volume being populated
|
||||
CopyData bool `json:"-"`
|
||||
// ID is the opaque ID used to pass to the volume driver.
|
||||
// This should be set by calls to `Mount` and unset by calls to `Unmount`
|
||||
ID string `json:",omitempty"`
|
||||
|
||||
// Sepc is a copy of the API request that created this mount.
|
||||
Spec mounttypes.Mount
|
||||
|
||||
// Track usage of this mountpoint
|
||||
// Specifically needed for containers which are running and calls to `docker cp`
|
||||
// because both these actions require mounting the volumes.
|
||||
active int
|
||||
}
|
||||
|
||||
// Cleanup frees resources used by the mountpoint
|
||||
func (m *MountPoint) Cleanup() error {
|
||||
if m.Volume == nil || m.ID == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Volume.Unmount(m.ID); err != nil {
|
||||
return errors.Wrapf(err, "error unmounting volume %s", m.Volume.Name())
|
||||
}
|
||||
|
||||
m.active--
|
||||
if m.active == 0 {
|
||||
m.ID = ""
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup sets up a mount point by either mounting the volume if it is
|
||||
// configured, or creating the source directory if supplied.
|
||||
// The, optional, checkFun parameter allows doing additional checking
|
||||
// before creating the source directory on the host.
|
||||
func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) {
|
||||
defer func() {
|
||||
if err != nil || !label.RelabelNeeded(m.Mode) {
|
||||
return
|
||||
}
|
||||
|
||||
err = label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode))
|
||||
if err == syscall.ENOTSUP {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
path = ""
|
||||
err = errors.Wrapf(err, "error setting label on mount source '%s'", m.Source)
|
||||
}
|
||||
}()
|
||||
|
||||
if m.Volume != nil {
|
||||
id := m.ID
|
||||
if id == "" {
|
||||
id = stringid.GenerateNonCryptoID()
|
||||
}
|
||||
path, err := m.Volume.Mount(id)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error while mounting volume '%s'", m.Source)
|
||||
}
|
||||
|
||||
m.ID = id
|
||||
m.active++
|
||||
return path, nil
|
||||
}
|
||||
|
||||
if len(m.Source) == 0 {
|
||||
return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined")
|
||||
}
|
||||
|
||||
// system.MkdirAll() produces an error if m.Source exists and is a file (not a directory),
|
||||
if m.Type == mounttypes.TypeBind {
|
||||
// Before creating the source directory on the host, invoke checkFun if it's not nil. One of
|
||||
// the use case is to forbid creating the daemon socket as a directory if the daemon is in
|
||||
// the process of shutting down.
|
||||
if checkFun != nil {
|
||||
if err := checkFun(m); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
// idtools.MkdirAllNewAs() produces an error if m.Source exists and is a file (not a directory)
|
||||
// also, makes sure that if the directory is created, the correct remapped rootUID/rootGID will own it
|
||||
if err := idtools.MkdirAllAndChownNew(m.Source, 0755, rootIDs); err != nil {
|
||||
if perr, ok := err.(*os.PathError); ok {
|
||||
if perr.Err != syscall.ENOTDIR {
|
||||
return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return m.Source, nil
|
||||
}
|
||||
|
||||
// Path returns the path of a volume in a mount point.
|
||||
func (m *MountPoint) Path() string {
|
||||
if m.Volume != nil {
|
||||
return m.Volume.Path()
|
||||
}
|
||||
return m.Source
|
||||
}
|
||||
|
||||
// ParseVolumesFrom ensures that the supplied volumes-from is valid.
|
||||
func ParseVolumesFrom(spec string) (string, string, error) {
|
||||
if len(spec) == 0 {
|
||||
return "", "", fmt.Errorf("volumes-from specification cannot be an empty string")
|
||||
}
|
||||
|
||||
specParts := strings.SplitN(spec, ":", 2)
|
||||
id := specParts[0]
|
||||
mode := "rw"
|
||||
|
||||
if len(specParts) == 2 {
|
||||
mode = specParts[1]
|
||||
if !ValidMountMode(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// For now don't allow propagation properties while importing
|
||||
// volumes from data container. These volumes will inherit
|
||||
// the same propagation property as of the original volume
|
||||
// in data container. This probably can be relaxed in future.
|
||||
if HasPropagation(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// Do not allow copy modes on volumes-from
|
||||
if _, isSet := getCopyMode(mode); isSet {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
}
|
||||
return id, mode, nil
|
||||
}
|
||||
|
||||
// ParseMountRaw parses a raw volume spec (e.g. `-v /foo:/bar:shared`) into a
|
||||
// structured spec. Once the raw spec is parsed it relies on `ParseMountSpec` to
|
||||
// validate the spec and create a MountPoint
|
||||
func ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
|
||||
arr, err := splitRawSpec(convertSlash(raw))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var spec mounttypes.Mount
|
||||
var mode string
|
||||
switch len(arr) {
|
||||
case 1:
|
||||
// Just a destination path in the container
|
||||
spec.Target = arr[0]
|
||||
case 2:
|
||||
if ValidMountMode(arr[1]) {
|
||||
// Destination + Mode is not a valid volume - volumes
|
||||
// cannot include a mode. e.g. /foo:rw
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
// Host Source Path or Name + Destination
|
||||
spec.Source = arr[0]
|
||||
spec.Target = arr[1]
|
||||
case 3:
|
||||
// HostSourcePath+DestinationPath+Mode
|
||||
spec.Source = arr[0]
|
||||
spec.Target = arr[1]
|
||||
mode = arr[2]
|
||||
default:
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
|
||||
if !ValidMountMode(mode) {
|
||||
return nil, errInvalidMode(mode)
|
||||
}
|
||||
|
||||
if filepath.IsAbs(spec.Source) {
|
||||
spec.Type = mounttypes.TypeBind
|
||||
} else {
|
||||
spec.Type = mounttypes.TypeVolume
|
||||
}
|
||||
|
||||
spec.ReadOnly = !ReadWrite(mode)
|
||||
|
||||
// cannot assume that if a volume driver is passed in that we should set it
|
||||
if volumeDriver != "" && spec.Type == mounttypes.TypeVolume {
|
||||
spec.VolumeOptions = &mounttypes.VolumeOptions{
|
||||
DriverConfig: &mounttypes.Driver{Name: volumeDriver},
|
||||
}
|
||||
}
|
||||
|
||||
if copyData, isSet := getCopyMode(mode); isSet {
|
||||
if spec.VolumeOptions == nil {
|
||||
spec.VolumeOptions = &mounttypes.VolumeOptions{}
|
||||
}
|
||||
spec.VolumeOptions.NoCopy = !copyData
|
||||
}
|
||||
if HasPropagation(mode) {
|
||||
spec.BindOptions = &mounttypes.BindOptions{
|
||||
Propagation: GetPropagation(mode),
|
||||
}
|
||||
}
|
||||
|
||||
mp, err := ParseMountSpec(spec, platformRawValidationOpts...)
|
||||
if mp != nil {
|
||||
mp.Mode = mode
|
||||
}
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%v: %v", errInvalidSpec(raw), err)
|
||||
}
|
||||
return mp, err
|
||||
}
|
||||
|
||||
// ParseMountSpec reads a mount config, validates it, and configures a mountpoint from it.
|
||||
func ParseMountSpec(cfg mounttypes.Mount, options ...func(*validateOpts)) (*MountPoint, error) {
|
||||
if err := validateMountConfig(&cfg, options...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp := &MountPoint{
|
||||
RW: !cfg.ReadOnly,
|
||||
Destination: clean(convertSlash(cfg.Target)),
|
||||
Type: cfg.Type,
|
||||
Spec: cfg,
|
||||
}
|
||||
|
||||
switch cfg.Type {
|
||||
case mounttypes.TypeVolume:
|
||||
if cfg.Source == "" {
|
||||
mp.Name = stringid.GenerateNonCryptoID()
|
||||
} else {
|
||||
mp.Name = cfg.Source
|
||||
}
|
||||
mp.CopyData = DefaultCopyMode
|
||||
|
||||
if cfg.VolumeOptions != nil {
|
||||
if cfg.VolumeOptions.DriverConfig != nil {
|
||||
mp.Driver = cfg.VolumeOptions.DriverConfig.Name
|
||||
}
|
||||
if cfg.VolumeOptions.NoCopy {
|
||||
mp.CopyData = false
|
||||
}
|
||||
}
|
||||
case mounttypes.TypeBind:
|
||||
mp.Source = clean(convertSlash(cfg.Source))
|
||||
if cfg.BindOptions != nil && len(cfg.BindOptions.Propagation) > 0 {
|
||||
mp.Propagation = cfg.BindOptions.Propagation
|
||||
} else {
|
||||
// If user did not specify a propagation mode, get
|
||||
// default propagation mode.
|
||||
mp.Propagation = DefaultPropagationMode
|
||||
}
|
||||
case mounttypes.TypeTmpfs:
|
||||
// NOP
|
||||
}
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
func errInvalidMode(mode string) error {
|
||||
return fmt.Errorf("invalid mode: %v", mode)
|
||||
}
|
||||
|
||||
func errInvalidSpec(spec string) error {
|
||||
return fmt.Errorf("invalid volume specification: '%s'", spec)
|
||||
}
|
||||
23
vendor/github.com/docker/docker/volume/volume_copy.go
generated
vendored
23
vendor/github.com/docker/docker/volume/volume_copy.go
generated
vendored
@ -1,23 +0,0 @@
|
||||
package volume
|
||||
|
||||
import "strings"
|
||||
|
||||
// {<copy mode>=isEnabled}
|
||||
var copyModes = map[string]bool{
|
||||
"nocopy": false,
|
||||
}
|
||||
|
||||
func copyModeExists(mode string) bool {
|
||||
_, exists := copyModes[mode]
|
||||
return exists
|
||||
}
|
||||
|
||||
// GetCopyMode gets the copy mode from the mode string for mounts
|
||||
func getCopyMode(mode string) (bool, bool) {
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
if isEnabled, exists := copyModes[o]; exists {
|
||||
return isEnabled, true
|
||||
}
|
||||
}
|
||||
return DefaultCopyMode, false
|
||||
}
|
||||
8
vendor/github.com/docker/docker/volume/volume_copy_unix.go
generated
vendored
8
vendor/github.com/docker/docker/volume/volume_copy_unix.go
generated
vendored
@ -1,8 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package volume
|
||||
|
||||
const (
|
||||
// DefaultCopyMode is the copy mode used by default for normal/named volumes
|
||||
DefaultCopyMode = true
|
||||
)
|
||||
6
vendor/github.com/docker/docker/volume/volume_copy_windows.go
generated
vendored
6
vendor/github.com/docker/docker/volume/volume_copy_windows.go
generated
vendored
@ -1,6 +0,0 @@
|
||||
package volume
|
||||
|
||||
const (
|
||||
// DefaultCopyMode is the copy mode used by default for normal/named volumes
|
||||
DefaultCopyMode = false
|
||||
)
|
||||
56
vendor/github.com/docker/docker/volume/volume_linux.go
generated
vendored
56
vendor/github.com/docker/docker/volume/volume_linux.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
)
|
||||
|
||||
// ConvertTmpfsOptions converts *mounttypes.TmpfsOptions to the raw option string
|
||||
// for mount(2).
|
||||
func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) {
|
||||
var rawOpts []string
|
||||
if readOnly {
|
||||
rawOpts = append(rawOpts, "ro")
|
||||
}
|
||||
|
||||
if opt != nil && opt.Mode != 0 {
|
||||
rawOpts = append(rawOpts, fmt.Sprintf("mode=%o", opt.Mode))
|
||||
}
|
||||
|
||||
if opt != nil && opt.SizeBytes != 0 {
|
||||
// calculate suffix here, making this linux specific, but that is
|
||||
// okay, since API is that way anyways.
|
||||
|
||||
// we do this by finding the suffix that divides evenly into the
|
||||
// value, returning the value itself, with no suffix, if it fails.
|
||||
//
|
||||
// For the most part, we don't enforce any semantic to this values.
|
||||
// The operating system will usually align this and enforce minimum
|
||||
// and maximums.
|
||||
var (
|
||||
size = opt.SizeBytes
|
||||
suffix string
|
||||
)
|
||||
for _, r := range []struct {
|
||||
suffix string
|
||||
divisor int64
|
||||
}{
|
||||
{"g", 1 << 30},
|
||||
{"m", 1 << 20},
|
||||
{"k", 1 << 10},
|
||||
} {
|
||||
if size%r.divisor == 0 {
|
||||
size = size / r.divisor
|
||||
suffix = r.suffix
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
rawOpts = append(rawOpts, fmt.Sprintf("size=%d%s", size, suffix))
|
||||
}
|
||||
return strings.Join(rawOpts, ","), nil
|
||||
}
|
||||
47
vendor/github.com/docker/docker/volume/volume_propagation_linux.go
generated
vendored
47
vendor/github.com/docker/docker/volume/volume_propagation_linux.go
generated
vendored
@ -1,47 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package volume
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
)
|
||||
|
||||
// DefaultPropagationMode defines what propagation mode should be used by
|
||||
// default if user has not specified one explicitly.
|
||||
// propagation modes
|
||||
const DefaultPropagationMode = mounttypes.PropagationRPrivate
|
||||
|
||||
var propagationModes = map[mounttypes.Propagation]bool{
|
||||
mounttypes.PropagationPrivate: true,
|
||||
mounttypes.PropagationRPrivate: true,
|
||||
mounttypes.PropagationSlave: true,
|
||||
mounttypes.PropagationRSlave: true,
|
||||
mounttypes.PropagationShared: true,
|
||||
mounttypes.PropagationRShared: true,
|
||||
}
|
||||
|
||||
// GetPropagation extracts and returns the mount propagation mode. If there
|
||||
// are no specifications, then by default it is "private".
|
||||
func GetPropagation(mode string) mounttypes.Propagation {
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
prop := mounttypes.Propagation(o)
|
||||
if propagationModes[prop] {
|
||||
return prop
|
||||
}
|
||||
}
|
||||
return DefaultPropagationMode
|
||||
}
|
||||
|
||||
// HasPropagation checks if there is a valid propagation mode present in
|
||||
// passed string. Returns true if a valid propagation mode specifier is
|
||||
// present, false otherwise.
|
||||
func HasPropagation(mode string) bool {
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
if propagationModes[mounttypes.Propagation(o)] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
24
vendor/github.com/docker/docker/volume/volume_propagation_unsupported.go
generated
vendored
24
vendor/github.com/docker/docker/volume/volume_propagation_unsupported.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package volume
|
||||
|
||||
import mounttypes "github.com/docker/docker/api/types/mount"
|
||||
|
||||
// DefaultPropagationMode is used only in linux. In other cases it returns
|
||||
// empty string.
|
||||
const DefaultPropagationMode mounttypes.Propagation = ""
|
||||
|
||||
// propagation modes not supported on this platform.
|
||||
var propagationModes = map[mounttypes.Propagation]bool{}
|
||||
|
||||
// GetPropagation is not supported. Return empty string.
|
||||
func GetPropagation(mode string) mounttypes.Propagation {
|
||||
return DefaultPropagationMode
|
||||
}
|
||||
|
||||
// HasPropagation checks if there is a valid propagation mode present in
|
||||
// passed string. Returns true if a valid propagation mode specifier is
|
||||
// present, false otherwise.
|
||||
func HasPropagation(mode string) bool {
|
||||
return false
|
||||
}
|
||||
148
vendor/github.com/docker/docker/volume/volume_unix.go
generated
vendored
148
vendor/github.com/docker/docker/volume/volume_unix.go
generated
vendored
@ -1,148 +0,0 @@
|
||||
// +build linux freebsd darwin solaris
|
||||
|
||||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
)
|
||||
|
||||
var platformRawValidationOpts = []func(o *validateOpts){
|
||||
// need to make sure to not error out if the bind source does not exist on unix
|
||||
// this is supported for historical reasons, the path will be automatically
|
||||
// created later.
|
||||
func(o *validateOpts) { o.skipBindSourceCheck = true },
|
||||
}
|
||||
|
||||
// read-write modes
|
||||
var rwModes = map[string]bool{
|
||||
"rw": true,
|
||||
"ro": true,
|
||||
}
|
||||
|
||||
// label modes
|
||||
var labelModes = map[string]bool{
|
||||
"Z": true,
|
||||
"z": true,
|
||||
}
|
||||
|
||||
// consistency modes
|
||||
var consistencyModes = map[mounttypes.Consistency]bool{
|
||||
mounttypes.ConsistencyFull: true,
|
||||
mounttypes.ConsistencyCached: true,
|
||||
mounttypes.ConsistencyDelegated: true,
|
||||
}
|
||||
|
||||
// BackwardsCompatible decides whether this mount point can be
|
||||
// used in old versions of Docker or not.
|
||||
// Only bind mounts and local volumes can be used in old versions of Docker.
|
||||
func (m *MountPoint) BackwardsCompatible() bool {
|
||||
return len(m.Source) > 0 || m.Driver == DefaultDriverName
|
||||
}
|
||||
|
||||
// HasResource checks whether the given absolute path for a container is in
|
||||
// this mount point. If the relative path starts with `../` then the resource
|
||||
// is outside of this mount point, but we can't simply check for this prefix
|
||||
// because it misses `..` which is also outside of the mount, so check both.
|
||||
func (m *MountPoint) HasResource(absolutePath string) bool {
|
||||
relPath, err := filepath.Rel(m.Destination, absolutePath)
|
||||
return err == nil && relPath != ".." && !strings.HasPrefix(relPath, fmt.Sprintf("..%c", filepath.Separator))
|
||||
}
|
||||
|
||||
// IsVolumeNameValid checks a volume name in a platform specific manner.
|
||||
func IsVolumeNameValid(name string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ValidMountMode will make sure the mount mode is valid.
|
||||
// returns if it's a valid mount mode or not.
|
||||
func ValidMountMode(mode string) bool {
|
||||
if mode == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
rwModeCount := 0
|
||||
labelModeCount := 0
|
||||
propagationModeCount := 0
|
||||
copyModeCount := 0
|
||||
consistencyModeCount := 0
|
||||
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
switch {
|
||||
case rwModes[o]:
|
||||
rwModeCount++
|
||||
case labelModes[o]:
|
||||
labelModeCount++
|
||||
case propagationModes[mounttypes.Propagation(o)]:
|
||||
propagationModeCount++
|
||||
case copyModeExists(o):
|
||||
copyModeCount++
|
||||
case consistencyModes[mounttypes.Consistency(o)]:
|
||||
consistencyModeCount++
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Only one string for each mode is allowed.
|
||||
if rwModeCount > 1 || labelModeCount > 1 || propagationModeCount > 1 || copyModeCount > 1 || consistencyModeCount > 1 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadWrite tells you if a mode string is a valid read-write mode or not.
|
||||
// If there are no specifications w.r.t read write mode, then by default
|
||||
// it returns true.
|
||||
func ReadWrite(mode string) bool {
|
||||
if !ValidMountMode(mode) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
if o == "ro" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func validateNotRoot(p string) error {
|
||||
p = filepath.Clean(convertSlash(p))
|
||||
if p == "/" {
|
||||
return fmt.Errorf("invalid specification: destination can't be '/'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateCopyMode(mode bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertSlash(p string) string {
|
||||
return filepath.ToSlash(p)
|
||||
}
|
||||
|
||||
func splitRawSpec(raw string) ([]string, error) {
|
||||
if strings.Count(raw, ":") > 2 {
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
|
||||
arr := strings.SplitN(raw, ":", 3)
|
||||
if arr[0] == "" {
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
func clean(p string) string {
|
||||
return filepath.Clean(p)
|
||||
}
|
||||
|
||||
func validateStat(fi os.FileInfo) error {
|
||||
return nil
|
||||
}
|
||||
16
vendor/github.com/docker/docker/volume/volume_unsupported.go
generated
vendored
16
vendor/github.com/docker/docker/volume/volume_unsupported.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
)
|
||||
|
||||
// ConvertTmpfsOptions converts *mounttypes.TmpfsOptions to the raw option string
|
||||
// for mount(2).
|
||||
func ConvertTmpfsOptions(opt *mounttypes.TmpfsOptions, readOnly bool) (string, error) {
|
||||
return "", fmt.Errorf("%s does not support tmpfs", runtime.GOOS)
|
||||
}
|
||||
201
vendor/github.com/docker/docker/volume/volume_windows.go
generated
vendored
201
vendor/github.com/docker/docker/volume/volume_windows.go
generated
vendored
@ -1,201 +0,0 @@
|
||||
package volume
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// read-write modes
|
||||
var rwModes = map[string]bool{
|
||||
"rw": true,
|
||||
}
|
||||
|
||||
// read-only modes
|
||||
var roModes = map[string]bool{
|
||||
"ro": true,
|
||||
}
|
||||
|
||||
var platformRawValidationOpts = []func(*validateOpts){
|
||||
// filepath.IsAbs is weird on Windows:
|
||||
// `c:` is not considered an absolute path
|
||||
// `c:\` is considered an absolute path
|
||||
// In any case, the regex matching below ensures absolute paths
|
||||
// TODO: consider this a bug with filepath.IsAbs (?)
|
||||
func(o *validateOpts) { o.skipAbsolutePathCheck = true },
|
||||
}
|
||||
|
||||
const (
|
||||
// Spec should be in the format [source:]destination[:mode]
|
||||
//
|
||||
// Examples: c:\foo bar:d:rw
|
||||
// c:\foo:d:\bar
|
||||
// myname:d:
|
||||
// d:\
|
||||
//
|
||||
// Explanation of this regex! Thanks @thaJeztah on IRC and gist for help. See
|
||||
// https://gist.github.com/thaJeztah/6185659e4978789fb2b2. A good place to
|
||||
// test is https://regex-golang.appspot.com/assets/html/index.html
|
||||
//
|
||||
// Useful link for referencing named capturing groups:
|
||||
// http://stackoverflow.com/questions/20750843/using-named-matches-from-go-regex
|
||||
//
|
||||
// There are three match groups: source, destination and mode.
|
||||
//
|
||||
|
||||
// RXHostDir is the first option of a source
|
||||
RXHostDir = `[a-z]:\\(?:[^\\/:*?"<>|\r\n]+\\?)*`
|
||||
// RXName is the second option of a source
|
||||
RXName = `[^\\/:*?"<>|\r\n]+`
|
||||
// RXReservedNames are reserved names not possible on Windows
|
||||
RXReservedNames = `(con)|(prn)|(nul)|(aux)|(com[1-9])|(lpt[1-9])`
|
||||
|
||||
// RXSource is the combined possibilities for a source
|
||||
RXSource = `((?P<source>((` + RXHostDir + `)|(` + RXName + `))):)?`
|
||||
|
||||
// Source. Can be either a host directory, a name, or omitted:
|
||||
// HostDir:
|
||||
// - Essentially using the folder solution from
|
||||
// https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch08s18.html
|
||||
// but adding case insensitivity.
|
||||
// - Must be an absolute path such as c:\path
|
||||
// - Can include spaces such as `c:\program files`
|
||||
// - And then followed by a colon which is not in the capture group
|
||||
// - And can be optional
|
||||
// Name:
|
||||
// - Must not contain invalid NTFS filename characters (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx)
|
||||
// - And then followed by a colon which is not in the capture group
|
||||
// - And can be optional
|
||||
|
||||
// RXDestination is the regex expression for the mount destination
|
||||
RXDestination = `(?P<destination>([a-z]):((?:\\[^\\/:*?"<>\r\n]+)*\\?))`
|
||||
// Destination (aka container path):
|
||||
// - Variation on hostdir but can be a drive followed by colon as well
|
||||
// - If a path, must be absolute. Can include spaces
|
||||
// - Drive cannot be c: (explicitly checked in code, not RegEx)
|
||||
|
||||
// RXMode is the regex expression for the mode of the mount
|
||||
// Mode (optional):
|
||||
// - Hopefully self explanatory in comparison to above regex's.
|
||||
// - Colon is not in the capture group
|
||||
RXMode = `(:(?P<mode>(?i)ro|rw))?`
|
||||
)
|
||||
|
||||
// BackwardsCompatible decides whether this mount point can be
|
||||
// used in old versions of Docker or not.
|
||||
// Windows volumes are never backwards compatible.
|
||||
func (m *MountPoint) BackwardsCompatible() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func splitRawSpec(raw string) ([]string, error) {
|
||||
specExp := regexp.MustCompile(`^` + RXSource + RXDestination + RXMode + `$`)
|
||||
match := specExp.FindStringSubmatch(strings.ToLower(raw))
|
||||
|
||||
// Must have something back
|
||||
if len(match) == 0 {
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
|
||||
var split []string
|
||||
matchgroups := make(map[string]string)
|
||||
// Pull out the sub expressions from the named capture groups
|
||||
for i, name := range specExp.SubexpNames() {
|
||||
matchgroups[name] = strings.ToLower(match[i])
|
||||
}
|
||||
if source, exists := matchgroups["source"]; exists {
|
||||
if source != "" {
|
||||
split = append(split, source)
|
||||
}
|
||||
}
|
||||
if destination, exists := matchgroups["destination"]; exists {
|
||||
if destination != "" {
|
||||
split = append(split, destination)
|
||||
}
|
||||
}
|
||||
if mode, exists := matchgroups["mode"]; exists {
|
||||
if mode != "" {
|
||||
split = append(split, mode)
|
||||
}
|
||||
}
|
||||
// Fix #26329. If the destination appears to be a file, and the source is null,
|
||||
// it may be because we've fallen through the possible naming regex and hit a
|
||||
// situation where the user intention was to map a file into a container through
|
||||
// a local volume, but this is not supported by the platform.
|
||||
if matchgroups["source"] == "" && matchgroups["destination"] != "" {
|
||||
validName, err := IsVolumeNameValid(matchgroups["destination"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !validName {
|
||||
if fi, err := os.Stat(matchgroups["destination"]); err == nil {
|
||||
if !fi.IsDir() {
|
||||
return nil, fmt.Errorf("file '%s' cannot be mapped. Only directories can be mapped on this platform", matchgroups["destination"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return split, nil
|
||||
}
|
||||
|
||||
// IsVolumeNameValid checks a volume name in a platform specific manner.
|
||||
func IsVolumeNameValid(name string) (bool, error) {
|
||||
nameExp := regexp.MustCompile(`^` + RXName + `$`)
|
||||
if !nameExp.MatchString(name) {
|
||||
return false, nil
|
||||
}
|
||||
nameExp = regexp.MustCompile(`^` + RXReservedNames + `$`)
|
||||
if nameExp.MatchString(name) {
|
||||
return false, fmt.Errorf("volume name %q cannot be a reserved word for Windows filenames", name)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ValidMountMode will make sure the mount mode is valid.
|
||||
// returns if it's a valid mount mode or not.
|
||||
func ValidMountMode(mode string) bool {
|
||||
if mode == "" {
|
||||
return true
|
||||
}
|
||||
return roModes[strings.ToLower(mode)] || rwModes[strings.ToLower(mode)]
|
||||
}
|
||||
|
||||
// ReadWrite tells you if a mode string is a valid read-write mode or not.
|
||||
func ReadWrite(mode string) bool {
|
||||
return rwModes[strings.ToLower(mode)] || mode == ""
|
||||
}
|
||||
|
||||
func validateNotRoot(p string) error {
|
||||
p = strings.ToLower(convertSlash(p))
|
||||
if p == "c:" || p == `c:\` {
|
||||
return fmt.Errorf("destination path cannot be `c:` or `c:\\`: %v", p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateCopyMode(mode bool) error {
|
||||
if mode {
|
||||
return fmt.Errorf("Windows does not support copying image path content")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertSlash(p string) string {
|
||||
return filepath.FromSlash(p)
|
||||
}
|
||||
|
||||
func clean(p string) string {
|
||||
if match, _ := regexp.MatchString("^[a-z]:$", p); match {
|
||||
return p
|
||||
}
|
||||
return filepath.Clean(p)
|
||||
}
|
||||
|
||||
func validateStat(fi os.FileInfo) error {
|
||||
if !fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a directory")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user