summaryrefslogtreecommitdiff
path: root/cmd/podman/common
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/common')
-rw-r--r--cmd/podman/common/create_opts.go130
-rw-r--r--cmd/podman/common/specgen.go8
-rw-r--r--cmd/podman/common/volumes.go139
3 files changed, 180 insertions, 97 deletions
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 5dea49c8b..05bb9de13 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -293,66 +293,61 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig) (*Cont
// like with start. We believe this is just a difference in podman/compat
cliOpts := ContainerCLIOpts{
//Attach: nil, // dont need?
- Authfile: "",
- BlkIOWeight: strconv.Itoa(int(cc.HostConfig.BlkioWeight)),
- BlkIOWeightDevice: nil, // TODO
- CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
- CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
- CGroupParent: cc.HostConfig.CgroupParent,
- CIDFile: cc.HostConfig.ContainerIDFile,
- CPUPeriod: uint64(cc.HostConfig.CPUPeriod),
- CPUQuota: cc.HostConfig.CPUQuota,
- CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
- CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
- CPUShares: uint64(cc.HostConfig.CPUShares),
+ Authfile: "",
+ CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
+ CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
+ CGroupParent: cc.HostConfig.CgroupParent,
+ CIDFile: cc.HostConfig.ContainerIDFile,
+ CPUPeriod: uint64(cc.HostConfig.CPUPeriod),
+ CPUQuota: cc.HostConfig.CPUQuota,
+ CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
+ CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
+ CPUShares: uint64(cc.HostConfig.CPUShares),
//CPUS: 0, // dont need?
CPUSetCPUs: cc.HostConfig.CpusetCpus,
CPUSetMems: cc.HostConfig.CpusetMems,
//Detach: false, // dont need
//DetachKeys: "", // dont need
- Devices: devices,
- DeviceCGroupRule: nil,
- DeviceReadBPs: readBps,
- DeviceReadIOPs: readIops,
- DeviceWriteBPs: writeBps,
- DeviceWriteIOPs: writeIops,
- Entrypoint: &entrypoint,
- Env: cc.Config.Env,
- Expose: expose,
- GroupAdd: cc.HostConfig.GroupAdd,
- Hostname: cc.Config.Hostname,
- ImageVolume: "bind",
- Init: init,
- Interactive: cc.Config.OpenStdin,
- IPC: string(cc.HostConfig.IpcMode),
- Label: stringMaptoArray(cc.Config.Labels),
- LogDriver: cc.HostConfig.LogConfig.Type,
- LogOptions: stringMaptoArray(cc.HostConfig.LogConfig.Config),
- Memory: strconv.Itoa(int(cc.HostConfig.Memory)),
- MemoryReservation: strconv.Itoa(int(cc.HostConfig.MemoryReservation)),
- MemorySwap: strconv.Itoa(int(cc.HostConfig.MemorySwap)),
- Name: cc.Name,
- OOMScoreAdj: cc.HostConfig.OomScoreAdj,
- OverrideArch: "",
- OverrideOS: "",
- OverrideVariant: "",
- PID: string(cc.HostConfig.PidMode),
- PIDsLimit: cc.HostConfig.PidsLimit,
- Privileged: cc.HostConfig.Privileged,
- PublishAll: cc.HostConfig.PublishAllPorts,
- Quiet: false,
- ReadOnly: cc.HostConfig.ReadonlyRootfs,
- ReadOnlyTmpFS: true, // podman default
- Rm: cc.HostConfig.AutoRemove,
- SecurityOpt: cc.HostConfig.SecurityOpt,
- ShmSize: strconv.Itoa(int(cc.HostConfig.ShmSize)),
- StopSignal: cc.Config.StopSignal,
- StoreageOpt: stringMaptoArray(cc.HostConfig.StorageOpt),
- Sysctl: stringMaptoArray(cc.HostConfig.Sysctls),
- Systemd: "true", // podman default
- TmpFS: stringMaptoArray(cc.HostConfig.Tmpfs),
- TTY: cc.Config.Tty,
+ Devices: devices,
+ DeviceCGroupRule: nil,
+ DeviceReadBPs: readBps,
+ DeviceReadIOPs: readIops,
+ DeviceWriteBPs: writeBps,
+ DeviceWriteIOPs: writeIops,
+ Entrypoint: &entrypoint,
+ Env: cc.Config.Env,
+ Expose: expose,
+ GroupAdd: cc.HostConfig.GroupAdd,
+ Hostname: cc.Config.Hostname,
+ ImageVolume: "bind",
+ Init: init,
+ Interactive: cc.Config.OpenStdin,
+ IPC: string(cc.HostConfig.IpcMode),
+ Label: stringMaptoArray(cc.Config.Labels),
+ LogDriver: cc.HostConfig.LogConfig.Type,
+ LogOptions: stringMaptoArray(cc.HostConfig.LogConfig.Config),
+ Name: cc.Name,
+ OOMScoreAdj: cc.HostConfig.OomScoreAdj,
+ OverrideArch: "",
+ OverrideOS: "",
+ OverrideVariant: "",
+ PID: string(cc.HostConfig.PidMode),
+ PIDsLimit: cc.HostConfig.PidsLimit,
+ Privileged: cc.HostConfig.Privileged,
+ PublishAll: cc.HostConfig.PublishAllPorts,
+ Quiet: false,
+ ReadOnly: cc.HostConfig.ReadonlyRootfs,
+ ReadOnlyTmpFS: true, // podman default
+ Rm: cc.HostConfig.AutoRemove,
+ SecurityOpt: cc.HostConfig.SecurityOpt,
+ StopSignal: cc.Config.StopSignal,
+ StoreageOpt: stringMaptoArray(cc.HostConfig.StorageOpt),
+ Sysctl: stringMaptoArray(cc.HostConfig.Sysctls),
+ Systemd: "true", // podman default
+ TmpFS: stringMaptoArray(cc.HostConfig.Tmpfs),
+ TTY: cc.Config.Tty,
//Ulimit: cc.HostConfig.Ulimits, // ask dan, no documented format
+ Ulimit: []string{"nproc=4194304:4194304"},
User: cc.Config.User,
UserNS: string(cc.HostConfig.UsernsMode),
UTS: string(cc.HostConfig.UTSMode),
@@ -363,10 +358,37 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig) (*Cont
Net: &netInfo,
}
+ if len(cc.HostConfig.BlkioWeightDevice) > 0 {
+ devices := make([]string, 0, len(cc.HostConfig.BlkioWeightDevice))
+ for _, d := range cc.HostConfig.BlkioWeightDevice {
+ devices = append(devices, d.String())
+ }
+ cliOpts.BlkIOWeightDevice = devices
+ }
+ if cc.HostConfig.BlkioWeight > 0 {
+ cliOpts.BlkIOWeight = strconv.Itoa(int(cc.HostConfig.BlkioWeight))
+ }
+
+ if cc.HostConfig.Memory > 0 {
+ cliOpts.Memory = strconv.Itoa(int(cc.HostConfig.Memory))
+ }
+
+ if cc.HostConfig.MemoryReservation > 0 {
+ cliOpts.MemoryReservation = strconv.Itoa(int(cc.HostConfig.MemoryReservation))
+ }
+
+ if cc.HostConfig.MemorySwap > 0 {
+ cliOpts.MemorySwap = strconv.Itoa(int(cc.HostConfig.MemorySwap))
+ }
+
if cc.Config.StopTimeout != nil {
cliOpts.StopTimeout = uint(*cc.Config.StopTimeout)
}
+ if cc.HostConfig.ShmSize > 0 {
+ cliOpts.ShmSize = strconv.Itoa(int(cc.HostConfig.ShmSize))
+ }
+
if cc.HostConfig.KernelMemory > 0 {
cliOpts.KernelMemory = strconv.Itoa(int(cc.HostConfig.KernelMemory))
}
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index f427830c6..ca1e25be1 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -25,11 +25,8 @@ func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU {
cpu := &specs.LinuxCPU{}
hasLimits := false
- const cpuPeriod = 100000
-
if c.CPUS > 0 {
- quota := int64(c.CPUS * cpuPeriod)
- period := uint64(cpuPeriod)
+ period, quota := util.CoresToPeriodAndQuota(c.CPUS)
cpu.Period = &period
cpu.Quota = &quota
@@ -533,13 +530,14 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
// Only add read-only tmpfs mounts in case that we are read-only and the
// read-only tmpfs flag has been set.
- mounts, volumes, overlayVolumes, err := parseVolumes(c.Volume, c.Mount, c.TmpFS, c.ReadOnlyTmpFS && c.ReadOnly)
+ mounts, volumes, overlayVolumes, imageVolumes, err := parseVolumes(c.Volume, c.Mount, c.TmpFS, c.ReadOnlyTmpFS && c.ReadOnly)
if err != nil {
return err
}
s.Mounts = mounts
s.Volumes = volumes
s.OverlayVolumes = overlayVolumes
+ s.ImageVolumes = imageVolumes
for _, dev := range c.Devices {
s.Devices = append(s.Devices, specs.LinuxDevice{Path: dev})
diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go
index 71f897264..b3c160ddf 100644
--- a/cmd/podman/common/volumes.go
+++ b/cmd/podman/common/volumes.go
@@ -37,43 +37,43 @@ var (
// Does not handle image volumes, init, and --volumes-from flags.
// Can also add tmpfs mounts from read-only tmpfs.
// TODO: handle options parsing/processing via containers/storage/pkg/mount
-func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bool) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) {
+func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bool) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, []*specgen.ImageVolume, error) {
// Get mounts from the --mounts flag.
- unifiedMounts, unifiedVolumes, err := getMounts(mountFlag)
+ unifiedMounts, unifiedVolumes, unifiedImageVolumes, err := getMounts(mountFlag)
if err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
// Next --volumes flag.
volumeMounts, volumeVolumes, overlayVolumes, err := getVolumeMounts(volumeFlag)
if err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
// Next --tmpfs flag.
tmpfsMounts, err := getTmpfsMounts(tmpfsFlag)
if err != nil {
- return nil, nil, nil, err
+ return nil, nil, nil, nil, err
}
// Unify mounts from --mount, --volume, --tmpfs.
// Start with --volume.
for dest, mount := range volumeMounts {
if _, ok := unifiedMounts[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, dest)
+ return nil, nil, nil, nil, errors.Wrapf(errDuplicateDest, dest)
}
unifiedMounts[dest] = mount
}
for dest, volume := range volumeVolumes {
if _, ok := unifiedVolumes[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, dest)
+ return nil, nil, nil, nil, errors.Wrapf(errDuplicateDest, dest)
}
unifiedVolumes[dest] = volume
}
// Now --tmpfs
for dest, tmpfs := range tmpfsMounts {
if _, ok := unifiedMounts[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, dest)
+ return nil, nil, nil, nil, errors.Wrapf(errDuplicateDest, dest)
}
unifiedMounts[dest] = tmpfs
}
@@ -98,29 +98,34 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo
}
}
- // Check for conflicts between named volumes, overlay volumes, and mounts
- for dest := range unifiedMounts {
- if _, ok := unifiedVolumes[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ // Check for conflicts between named volumes, overlay & image volumes,
+ // and mounts
+ allMounts := make(map[string]bool)
+ testAndSet := func(dest string) error {
+ if _, ok := allMounts[dest]; ok {
+ return errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
}
- if _, ok := overlayVolumes[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ allMounts[dest] = true
+ return nil
+ }
+ for dest := range unifiedMounts {
+ if err := testAndSet(dest); err != nil {
+ return nil, nil, nil, nil, err
}
}
for dest := range unifiedVolumes {
- if _, ok := unifiedMounts[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
- }
- if _, ok := overlayVolumes[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ if err := testAndSet(dest); err != nil {
+ return nil, nil, nil, nil, err
}
}
for dest := range overlayVolumes {
- if _, ok := unifiedMounts[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ if err := testAndSet(dest); err != nil {
+ return nil, nil, nil, nil, err
}
- if _, ok := unifiedVolumes[dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ }
+ for dest := range unifiedImageVolumes {
+ if err := testAndSet(dest); err != nil {
+ return nil, nil, nil, nil, err
}
}
@@ -130,7 +135,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo
if mount.Type == TypeBind {
absSrc, err := filepath.Abs(mount.Source)
if err != nil {
- return nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
+ return nil, nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
}
mount.Source = absSrc
}
@@ -144,8 +149,12 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo
for _, volume := range overlayVolumes {
finalOverlayVolume = append(finalOverlayVolume, volume)
}
+ finalImageVolumes := make([]*specgen.ImageVolume, 0, len(unifiedImageVolumes))
+ for _, volume := range unifiedImageVolumes {
+ finalImageVolumes = append(finalImageVolumes, volume)
+ }
- return finalMounts, finalVolumes, finalOverlayVolume, nil
+ return finalMounts, finalVolumes, finalOverlayVolume, finalImageVolumes, nil
}
// findMountType parses the input and extracts the type of the mount type and
@@ -174,59 +183,69 @@ func findMountType(input string) (mountType string, tokens []string, err error)
// podman run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ...
// podman run --mount type=tmpfs,target=/dev/shm ...
// podman run --mount type=volume,source=test-volume, ...
-func getMounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, error) {
+func getMounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.ImageVolume, error) {
finalMounts := make(map[string]spec.Mount)
finalNamedVolumes := make(map[string]*specgen.NamedVolume)
+ finalImageVolumes := make(map[string]*specgen.ImageVolume)
for _, mount := range mountFlag {
// TODO: Docker defaults to "volume" if no mount type is specified.
mountType, tokens, err := findMountType(mount)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
switch mountType {
case TypeBind:
mount, err := getBindMount(tokens)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
if _, ok := finalMounts[mount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
}
finalMounts[mount.Destination] = mount
case TypeTmpfs:
mount, err := getTmpfsMount(tokens)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
if _, ok := finalMounts[mount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
}
finalMounts[mount.Destination] = mount
case TypeDevpts:
mount, err := getDevptsMount(tokens)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
if _, ok := finalMounts[mount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
}
finalMounts[mount.Destination] = mount
+ case "image":
+ volume, err := getImageVolume(tokens)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if _, ok := finalImageVolumes[volume.Destination]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, volume.Destination)
+ }
+ finalImageVolumes[volume.Destination] = volume
case "volume":
volume, err := getNamedVolume(tokens)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
if _, ok := finalNamedVolumes[volume.Dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, volume.Dest)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, volume.Dest)
}
finalNamedVolumes[volume.Dest] = volume
default:
- return nil, nil, errors.Errorf("invalid filesystem type %q", mountType)
+ return nil, nil, nil, errors.Errorf("invalid filesystem type %q", mountType)
}
}
- return finalMounts, finalNamedVolumes, nil
+ return finalMounts, finalNamedVolumes, finalImageVolumes, nil
}
// Parse a single bind mount entry from the --mount flag.
@@ -294,7 +313,7 @@ func getBindMount(args []string) (spec.Mount, error) {
}
setExec = true
newMount.Options = append(newMount.Options, kv[0])
- case "shared", "rshared", "private", "rprivate", "slave", "rslave", "Z", "z":
+ case "shared", "rshared", "private", "rprivate", "slave", "rslave", "unbindable", "runbindable", "Z", "z":
newMount.Options = append(newMount.Options, kv[0])
case "bind-propagation":
if len(kv) == 1 {
@@ -531,6 +550,50 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) {
return newVolume, nil
}
+// Parse the arguments into an image volume. An image volume is a volume based
+// on a container image. The container image is first mounted on the host and
+// is then bind-mounted into the container. An ImageVolume is always mounted
+// read only.
+func getImageVolume(args []string) (*specgen.ImageVolume, error) {
+ newVolume := new(specgen.ImageVolume)
+
+ for _, val := range args {
+ kv := strings.SplitN(val, "=", 2)
+ switch kv[0] {
+ case "src", "source":
+ if len(kv) == 1 {
+ return nil, errors.Wrapf(optionArgError, kv[0])
+ }
+ newVolume.Source = kv[1]
+ case "target", "dst", "destination":
+ if len(kv) == 1 {
+ return nil, errors.Wrapf(optionArgError, kv[0])
+ }
+ if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
+ return nil, err
+ }
+ newVolume.Destination = filepath.Clean(kv[1])
+ case "rw", "readwrite":
+ switch kv[1] {
+ case "true":
+ newVolume.ReadWrite = true
+ case "false":
+ // Nothing to do. RO is default.
+ default:
+ return nil, errors.Wrapf(util.ErrBadMntOption, "invalid rw value %q", kv[1])
+ }
+ default:
+ return nil, errors.Wrapf(util.ErrBadMntOption, kv[0])
+ }
+ }
+
+ if len(newVolume.Source)*len(newVolume.Destination) == 0 {
+ return nil, errors.Errorf("must set source and destination for image volume")
+ }
+
+ return newVolume, nil
+}
+
func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.OverlayVolume, error) {
mounts := make(map[string]spec.Mount)
volumes := make(map[string]*specgen.NamedVolume)