summaryrefslogtreecommitdiff
path: root/pkg/specgen
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/specgen')
-rw-r--r--pkg/specgen/generate/config_linux.go141
-rw-r--r--pkg/specgen/generate/container.go19
-rw-r--r--pkg/specgen/generate/container_create.go32
-rw-r--r--pkg/specgen/generate/namespaces.go32
-rw-r--r--pkg/specgen/generate/oci.go35
-rw-r--r--pkg/specgen/generate/pod_create.go90
-rw-r--r--pkg/specgen/podspecgen.go4
-rw-r--r--pkg/specgen/volumes.go30
8 files changed, 195 insertions, 188 deletions
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index ed2e5408d..60d87a8fd 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -3,7 +3,6 @@ package generate
import (
"fmt"
"io/fs"
- "io/ioutil"
"os"
"path"
"path/filepath"
@@ -11,6 +10,7 @@ import (
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/rootless"
+ "github.com/containers/podman/v4/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
@@ -18,56 +18,6 @@ import (
"golang.org/x/sys/unix"
)
-var (
- errNotADevice = errors.New("not a device node")
-)
-
-func addPrivilegedDevices(g *generate.Generator) error {
- hostDevices, err := getDevices("/dev")
- if err != nil {
- return err
- }
- g.ClearLinuxDevices()
-
- if rootless.IsRootless() {
- mounts := make(map[string]interface{})
- for _, m := range g.Mounts() {
- mounts[m.Destination] = true
- }
- newMounts := []spec.Mount{}
- for _, d := range hostDevices {
- devMnt := spec.Mount{
- Destination: d.Path,
- Type: define.TypeBind,
- Source: d.Path,
- Options: []string{"slave", "nosuid", "noexec", "rw", "rbind"},
- }
- if d.Path == "/dev/ptmx" || strings.HasPrefix(d.Path, "/dev/tty") {
- continue
- }
- if _, found := mounts[d.Path]; found {
- continue
- }
- newMounts = append(newMounts, devMnt)
- }
- g.Config.Mounts = append(newMounts, g.Config.Mounts...)
- if g.Config.Linux.Resources != nil {
- g.Config.Linux.Resources.Devices = nil
- }
- } else {
- for _, d := range hostDevices {
- g.AddDevice(d)
- }
- // Add resources device - need to clear the existing one first.
- if g.Config.Linux.Resources != nil {
- g.Config.Linux.Resources.Devices = nil
- }
- g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm")
- }
-
- return nil
-}
-
// DevicesFromPath computes a list of devices
func DevicesFromPath(g *generate.Generator, devicePath string) error {
devs := strings.Split(devicePath, ":")
@@ -174,60 +124,12 @@ func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, mask, unmask
}
}
-// based on getDevices from runc (libcontainer/devices/devices.go)
-func getDevices(path string) ([]spec.LinuxDevice, error) {
- files, err := ioutil.ReadDir(path)
- if err != nil {
- if rootless.IsRootless() && os.IsPermission(err) {
- return nil, nil
- }
- return nil, err
- }
- out := []spec.LinuxDevice{}
- for _, f := range files {
- switch {
- case f.IsDir():
- switch f.Name() {
- // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
- case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
- continue
- default:
- sub, err := getDevices(filepath.Join(path, f.Name()))
- if err != nil {
- return nil, err
- }
- if sub != nil {
- out = append(out, sub...)
- }
- continue
- }
- case f.Name() == "console":
- continue
- case f.Mode()&os.ModeSymlink != 0:
- continue
- }
-
- device, err := deviceFromPath(filepath.Join(path, f.Name()))
- if err != nil {
- if err == errNotADevice {
- continue
- }
- if os.IsNotExist(err) {
- continue
- }
- return nil, err
- }
- out = append(out, *device)
- }
- return out, nil
-}
-
func addDevice(g *generate.Generator, device string) error {
src, dst, permissions, err := ParseDevice(device)
if err != nil {
return err
}
- dev, err := deviceFromPath(src)
+ dev, err := util.DeviceFromPath(src)
if err != nil {
return errors.Wrapf(err, "%s is not a valid device", src)
}
@@ -262,7 +164,7 @@ func addDevice(g *generate.Generator, device string) error {
}
// ParseDevice parses device mapping string to a src, dest & permissions string
-func ParseDevice(device string) (string, string, string, error) { //nolint
+func ParseDevice(device string) (string, string, string, error) {
var src string
var dst string
permissions := "rwm"
@@ -316,43 +218,6 @@ func IsValidDeviceMode(mode string) bool {
return true
}
-// Copied from github.com/opencontainers/runc/libcontainer/devices
-// Given the path to a device look up the information about a linux device
-func deviceFromPath(path string) (*spec.LinuxDevice, error) {
- var stat unix.Stat_t
- err := unix.Lstat(path, &stat)
- if err != nil {
- return nil, err
- }
- var (
- devType string
- mode = stat.Mode
- devNumber = uint64(stat.Rdev) // nolint: unconvert
- m = os.FileMode(mode)
- )
-
- switch {
- case mode&unix.S_IFBLK == unix.S_IFBLK:
- devType = "b"
- case mode&unix.S_IFCHR == unix.S_IFCHR:
- devType = "c"
- case mode&unix.S_IFIFO == unix.S_IFIFO:
- devType = "p"
- default:
- return nil, errNotADevice
- }
-
- return &spec.LinuxDevice{
- Type: devType,
- Path: path,
- FileMode: &m,
- UID: &stat.Uid,
- GID: &stat.Gid,
- Major: int64(unix.Major(devNumber)),
- Minor: int64(unix.Minor(devNumber)),
- }, nil
-}
-
func supportAmbientCapabilities() bool {
err := unix.Prctl(unix.PR_CAP_AMBIENT, unix.PR_CAP_AMBIENT_IS_SET, 0, 0, 0)
return err == nil
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index cc376125f..30c759495 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -303,8 +303,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
if s.ResourceLimits.BlockIO == nil {
s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO)
}
@@ -317,8 +317,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v)
}
}
@@ -328,8 +328,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
}
}
@@ -339,8 +339,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v)
}
}
@@ -450,7 +450,7 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s
specg.IpcNS = specgen.Namespace{NSMode: specgen.Default} // default
}
case "uts":
- specg.UtsNS = specgen.Namespace{NSMode: specgen.Default} // default
+ specg.UtsNS = specgen.Namespace{NSMode: specgen.Private} // default
case "user":
if conf.AddCurrentUserPasswdEntry {
specg.UserNS = specgen.Namespace{NSMode: specgen.KeepID}
@@ -506,6 +506,7 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s
specg.Mounts = mounts
specg.HostDeviceList = conf.DeviceHostSrc
specg.Networks = conf.Networks
+ specg.ShmSize = &conf.ShmSize
mapSecurityConfig(conf, specg)
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 04e24d625..6b2e90b22 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -180,10 +180,23 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
if err != nil {
return nil, nil, nil, err
}
+ resources := runtimeSpec.Linux.Resources
+
+ // resources get overwrritten similarly to pod inheritance, manually assign here if there is a new value
+ marshalRes, err := json.Marshal(resources)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
err = json.Unmarshal(out, runtimeSpec.Linux)
if err != nil {
return nil, nil, nil, err
}
+
+ err = json.Unmarshal(marshalRes, runtimeSpec.Linux.Resources)
+ if err != nil {
+ return nil, nil, nil, err
+ }
}
if s.ResourceLimits != nil {
switch {
@@ -278,6 +291,10 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
options = append(options, libpod.WithPasswdEntry(s.PasswdEntry))
}
+ if s.Privileged {
+ options = append(options, libpod.WithMountAllDevices())
+ }
+
useSystemd := false
switch s.Systemd {
case "always":
@@ -542,6 +559,16 @@ func Inherit(infra libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtim
infraConf := infra.Config()
infraSpec := infraConf.Spec
+ // need to set compatOptions to the currently filled specgenOptions so we do not overwrite
+ compatibleOptions.CapAdd = append(compatibleOptions.CapAdd, s.CapAdd...)
+ compatibleOptions.CapDrop = append(compatibleOptions.CapDrop, s.CapDrop...)
+ compatibleOptions.HostDeviceList = append(compatibleOptions.HostDeviceList, s.HostDeviceList...)
+ compatibleOptions.ImageVolumes = append(compatibleOptions.ImageVolumes, s.ImageVolumes...)
+ compatibleOptions.Mounts = append(compatibleOptions.Mounts, s.Mounts...)
+ compatibleOptions.OverlayVolumes = append(compatibleOptions.OverlayVolumes, s.OverlayVolumes...)
+ compatibleOptions.SelinuxOpts = append(compatibleOptions.SelinuxOpts, s.SelinuxOpts...)
+ compatibleOptions.Volumes = append(compatibleOptions.Volumes, s.Volumes...)
+
compatByte, err := json.Marshal(compatibleOptions)
if err != nil {
return nil, nil, nil, err
@@ -550,5 +577,10 @@ func Inherit(infra libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtim
if err != nil {
return nil, nil, nil, err
}
+
+ // this causes errors when shmSize is the default value, it will still get passed down unless we manually override.
+ if s.IpcNS.NSMode == specgen.Host && (compatibleOptions.ShmSize != nil && compatibleOptions.IsDefaultShmSize()) {
+ s.ShmSize = nil
+ }
return options, infraSpec, compatibleOptions, nil
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 4735111c8..4224d16ce 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -19,6 +19,8 @@ import (
"github.com/sirupsen/logrus"
)
+const host = "host"
+
// Get the default namespace mode for any given namespace type.
func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod) (specgen.Namespace, error) {
// The default for most is private
@@ -33,19 +35,38 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
podMode := false
switch {
case nsType == "pid" && pod.SharesPID():
+ if pod.NamespaceMode(spec.PIDNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
case nsType == "ipc" && pod.SharesIPC():
+ if pod.NamespaceMode(spec.IPCNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
case nsType == "uts" && pod.SharesUTS():
+ if pod.NamespaceMode(spec.UTSNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
case nsType == "user" && pod.SharesUser():
+ // user does not need a special check for host, this is already validated on pod creation
+ // if --userns=host then pod.SharesUser == false
podMode = true
case nsType == "net" && pod.SharesNet():
+ if pod.NetworkMode() == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
- case nsType == "net" && pod.NetworkMode() == "host":
- toReturn.NSMode = specgen.Host
- return toReturn, nil
case nsType == "cgroup" && pod.SharesCgroup():
+ if pod.NamespaceMode(spec.CgroupNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
}
if podMode {
@@ -491,10 +512,7 @@ func GetNamespaceOptions(ns []string, netnsIsHost bool) ([]libpod.PodCreateOptio
case "cgroup":
options = append(options, libpod.WithPodCgroup())
case "net":
- // share the netns setting with other containers in the pod only when it is not set to host
- if !netnsIsHost {
- options = append(options, libpod.WithPodNet())
- }
+ options = append(options, libpod.WithPodNet())
case "mnt":
return erroredOptions, errors.Errorf("Mount sharing functionality not supported on pod level")
case "pid":
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index dda2de6e4..1044854f4 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -298,8 +298,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
g.AddAnnotation(key, val)
}
- switch {
- case compatibleOptions.InfraResources == nil && s.ResourceLimits != nil:
+ if s.ResourceLimits != nil {
out, err := json.Marshal(s.ResourceLimits)
if err != nil {
return nil, err
@@ -308,43 +307,17 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
if err != nil {
return nil, err
}
- case s.ResourceLimits != nil: // if we have predefined resource limits we need to make sure we keep the infra and container limits
- originalResources, err := json.Marshal(s.ResourceLimits)
- if err != nil {
- return nil, err
- }
- infraResources, err := json.Marshal(compatibleOptions.InfraResources)
- if err != nil {
- return nil, err
- }
- err = json.Unmarshal(infraResources, s.ResourceLimits) // put infra's resource limits in the container
- if err != nil {
- return nil, err
- }
- err = json.Unmarshal(originalResources, s.ResourceLimits) // make sure we did not override anything
- if err != nil {
- return nil, err
- }
g.Config.Linux.Resources = s.ResourceLimits
- default:
- g.Config.Linux.Resources = compatibleOptions.InfraResources
}
// Devices
-
// set the default rule at the beginning of device configuration
if !inUserNS && !s.Privileged {
g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
}
var userDevices []spec.LinuxDevice
- if s.Privileged {
- // If privileged, we need to add all the host devices to the
- // spec. We do not add the user provided ones because we are
- // already adding them all.
- if err := addPrivilegedDevices(&g); err != nil {
- return nil, err
- }
- } else {
+
+ if !s.Privileged {
// add default devices from containers.conf
for _, device := range rtc.Containers.Devices {
if err = DevicesFromPath(&g, device); err != nil {
@@ -377,7 +350,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
if err := unix.Stat(k, &statT); err != nil {
return nil, errors.Wrapf(err, "failed to inspect '%s' in --blkio-weight-device", k)
}
- g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) // nolint: unconvert
+ g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) //nolint: unconvert
}
BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g)
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index d4f281a11..4ac8a0aa2 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -2,12 +2,17 @@ package generate
import (
"context"
+ "fmt"
"net"
+ "os"
+ "strconv"
+ "strings"
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/specgen"
+ "github.com/containers/podman/v4/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -210,3 +215,88 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
p.InfraContainerSpec.Image = p.InfraImage
return p.InfraContainerSpec, nil
}
+
+func PodConfigToSpec(rt *libpod.Runtime, spec *specgen.PodSpecGenerator, infraOptions *entities.ContainerCreateOptions, id string) (p *libpod.Pod, err error) {
+ pod, err := rt.LookupPod(id)
+ if err != nil {
+ return nil, err
+ }
+
+ infraSpec := &specgen.SpecGenerator{}
+ if pod.HasInfraContainer() {
+ infraID, err := pod.InfraContainerID()
+ if err != nil {
+ return nil, err
+ }
+ _, _, err = ConfigToSpec(rt, infraSpec, infraID)
+ if err != nil {
+ return nil, err
+ }
+
+ infraSpec.Hostname = ""
+ infraSpec.CgroupParent = ""
+ infraSpec.Pod = "" // remove old pod...
+ infraOptions.IsClone = true
+ infraOptions.IsInfra = true
+
+ n := infraSpec.Name
+ _, err = rt.LookupContainer(n + "-clone")
+ if err == nil { // if we found a ctr with this name, set it so the below switch can tell
+ n += "-clone"
+ }
+
+ switch {
+ case strings.Contains(n, "-clone"):
+ ind := strings.Index(n, "-clone") + 6
+ num, err := strconv.Atoi(n[ind:])
+ if num == 0 && err != nil { // clone1 is hard to get with this logic, just check for it here.
+ _, err = rt.LookupContainer(n + "1")
+ if err != nil {
+ infraSpec.Name = n + "1"
+ break
+ }
+ } else {
+ n = n[0:ind]
+ }
+ err = nil
+ count := num
+ for err == nil {
+ count++
+ tempN := n + strconv.Itoa(count)
+ _, err = rt.LookupContainer(tempN)
+ }
+ n += strconv.Itoa(count)
+ infraSpec.Name = n
+ default:
+ infraSpec.Name = n + "-clone"
+ }
+
+ err = specgenutil.FillOutSpecGen(infraSpec, infraOptions, []string{})
+ if err != nil {
+ return nil, err
+ }
+
+ out, err := CompleteSpec(context.Background(), rt, infraSpec)
+ if err != nil {
+ return nil, err
+ }
+
+ // Print warnings
+ if len(out) > 0 {
+ for _, w := range out {
+ fmt.Println("Could not properly complete the spec as expected:")
+ fmt.Fprintf(os.Stderr, "%s\n", w)
+ }
+ }
+
+ spec.InfraContainerSpec = infraSpec
+ }
+
+ // need to reset hostname, name etc of both pod and infra
+ spec.Hostname = ""
+
+ if len(spec.InfraContainerSpec.Image) > 0 {
+ spec.InfraImage = spec.InfraContainerSpec.Image
+ }
+ return pod, nil
+}
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 777097ac5..02ba06be1 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -183,6 +183,10 @@ type PodStorageConfig struct {
// comma-separated options. Valid options are 'ro', 'rw', and 'z'.
// Options will be used for all volumes sourced from the container.
VolumesFrom []string `json:"volumes_from,omitempty"`
+ // ShmSize is the size of the tmpfs to mount in at /dev/shm, in bytes.
+ // Conflicts with ShmSize if IpcNS is not private.
+ // Optional.
+ ShmSize *int64 `json:"shm_size,omitempty"`
}
// PodCgroupConfig contains configuration options about a pod's cgroups.
diff --git a/pkg/specgen/volumes.go b/pkg/specgen/volumes.go
index b26666df3..f272a5c11 100644
--- a/pkg/specgen/volumes.go
+++ b/pkg/specgen/volumes.go
@@ -1,6 +1,7 @@
package specgen
import (
+ "path/filepath"
"strings"
"github.com/containers/common/pkg/parse"
@@ -56,7 +57,6 @@ func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*Na
overlayVolumes := make(map[string]*OverlayVolume)
volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]")
-
for _, vol := range volumeFlag {
var (
options []string
@@ -71,6 +71,20 @@ func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*Na
}
src = splitVol[0]
+
+ // Support relative paths beginning with ./
+ if strings.HasPrefix(src, "./") {
+ path, err := filepath.EvalSymlinks(src)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ src, err = filepath.Abs(path)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ splitVol[0] = src
+ }
+
if len(splitVol) == 1 {
// This is an anonymous named volume. Only thing given
// is destination.
@@ -97,6 +111,8 @@ func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*Na
// This is not a named volume
overlayFlag := false
chownFlag := false
+ upperDirFlag := false
+ workDirFlag := false
for _, o := range options {
if o == "O" {
overlayFlag = true
@@ -105,8 +121,16 @@ func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*Na
if strings.Contains(joinedOpts, "U") {
chownFlag = true
}
-
- if len(options) > 2 || (len(options) == 2 && !chownFlag) {
+ if strings.Contains(joinedOpts, "upperdir") {
+ upperDirFlag = true
+ }
+ if strings.Contains(joinedOpts, "workdir") {
+ workDirFlag = true
+ }
+ if (workDirFlag && !upperDirFlag) || (!workDirFlag && upperDirFlag) {
+ return nil, nil, nil, errors.New("must set both `upperdir` and `workdir`")
+ }
+ if len(options) > 2 && !(len(options) == 3 && upperDirFlag && workDirFlag) || (len(options) == 2 && !chownFlag) {
return nil, nil, nil, errors.New("can't use 'O' with other options")
}
}