summaryrefslogtreecommitdiff
path: root/cmd/podman/common
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/common')
-rw-r--r--cmd/podman/common/create.go1416
-rw-r--r--cmd/podman/common/create_opts.go120
-rw-r--r--cmd/podman/common/createparse.go29
-rw-r--r--cmd/podman/common/netflags.go102
-rw-r--r--cmd/podman/common/ports.go22
-rw-r--r--cmd/podman/common/specgen.go972
-rw-r--r--cmd/podman/common/util.go274
-rw-r--r--cmd/podman/common/volumes.go630
8 files changed, 771 insertions, 2794 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 401cf2e09..325c1dc69 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -7,6 +7,7 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -14,663 +15,714 @@ const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes),
var containerConfig = registry.PodmanConfig()
-func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
+func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, isInfra bool) {
createFlags := cmd.Flags()
- annotationFlagName := "annotation"
- createFlags.StringSliceVar(
- &cf.Annotation,
- annotationFlagName, []string{},
- "Add annotations to container (key:value)",
- )
- _ = cmd.RegisterFlagCompletionFunc(annotationFlagName, completion.AutocompleteNone)
+ if !isInfra {
+ annotationFlagName := "annotation"
+ createFlags.StringSliceVar(
+ &cf.Annotation,
+ annotationFlagName, []string{},
+ "Add annotations to container (key:value)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(annotationFlagName, completion.AutocompleteNone)
- attachFlagName := "attach"
- createFlags.StringSliceVarP(
- &cf.Attach,
- attachFlagName, "a", []string{},
- "Attach to STDIN, STDOUT or STDERR",
- )
- _ = cmd.RegisterFlagCompletionFunc(attachFlagName, AutocompleteCreateAttach)
+ attachFlagName := "attach"
+ createFlags.StringSliceVarP(
+ &cf.Attach,
+ attachFlagName, "a", []string{},
+ "Attach to STDIN, STDOUT or STDERR",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(attachFlagName, AutocompleteCreateAttach)
- authfileFlagName := "authfile"
- createFlags.StringVar(
- &cf.Authfile,
- authfileFlagName, auth.GetDefaultAuthFile(),
- "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override",
- )
- _ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault)
+ authfileFlagName := "authfile"
+ createFlags.StringVar(
+ &cf.Authfile,
+ authfileFlagName, auth.GetDefaultAuthFile(),
+ "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault)
- blkioWeightFlagName := "blkio-weight"
- createFlags.StringVar(
- &cf.BlkIOWeight,
- blkioWeightFlagName, "",
- "Block IO weight (relative weight) accepts a weight value between 10 and 1000.",
- )
- _ = cmd.RegisterFlagCompletionFunc(blkioWeightFlagName, completion.AutocompleteNone)
+ blkioWeightFlagName := "blkio-weight"
+ createFlags.StringVar(
+ &cf.BlkIOWeight,
+ blkioWeightFlagName, "",
+ "Block IO weight (relative weight) accepts a weight value between 10 and 1000.",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(blkioWeightFlagName, completion.AutocompleteNone)
- blkioWeightDeviceFlagName := "blkio-weight-device"
- createFlags.StringSliceVar(
- &cf.BlkIOWeightDevice,
- blkioWeightDeviceFlagName, []string{},
- "Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)",
- )
- _ = cmd.RegisterFlagCompletionFunc(blkioWeightDeviceFlagName, completion.AutocompleteDefault)
+ blkioWeightDeviceFlagName := "blkio-weight-device"
+ createFlags.StringSliceVar(
+ &cf.BlkIOWeightDevice,
+ blkioWeightDeviceFlagName, []string{},
+ "Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(blkioWeightDeviceFlagName, completion.AutocompleteDefault)
- capAddFlagName := "cap-add"
- createFlags.StringSliceVar(
- &cf.CapAdd,
- capAddFlagName, []string{},
- "Add capabilities to the container",
- )
- _ = cmd.RegisterFlagCompletionFunc(capAddFlagName, completion.AutocompleteCapabilities)
+ capAddFlagName := "cap-add"
+ createFlags.StringSliceVar(
+ &cf.CapAdd,
+ capAddFlagName, []string{},
+ "Add capabilities to the container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(capAddFlagName, completion.AutocompleteCapabilities)
- capDropFlagName := "cap-drop"
- createFlags.StringSliceVar(
- &cf.CapDrop,
- capDropFlagName, []string{},
- "Drop capabilities from the container",
- )
- _ = cmd.RegisterFlagCompletionFunc(capDropFlagName, completion.AutocompleteCapabilities)
+ capDropFlagName := "cap-drop"
+ createFlags.StringSliceVar(
+ &cf.CapDrop,
+ capDropFlagName, []string{},
+ "Drop capabilities from the container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(capDropFlagName, completion.AutocompleteCapabilities)
- cgroupnsFlagName := "cgroupns"
- createFlags.String(
- cgroupnsFlagName, "",
- "cgroup namespace to use",
- )
- _ = cmd.RegisterFlagCompletionFunc(cgroupnsFlagName, AutocompleteNamespace)
+ cgroupnsFlagName := "cgroupns"
+ createFlags.String(
+ cgroupnsFlagName, "",
+ "cgroup namespace to use",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cgroupnsFlagName, AutocompleteNamespace)
- cgroupsFlagName := "cgroups"
- createFlags.StringVar(
- &cf.CGroupsMode,
- cgroupsFlagName, cgroupConfig(),
- `control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`,
- )
- _ = cmd.RegisterFlagCompletionFunc(cgroupsFlagName, AutocompleteCgroupMode)
+ cgroupsFlagName := "cgroups"
+ createFlags.StringVar(
+ &cf.CGroupsMode,
+ cgroupsFlagName, cgroupConfig(),
+ `control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cgroupsFlagName, AutocompleteCgroupMode)
- cgroupParentFlagName := "cgroup-parent"
- createFlags.StringVar(
- &cf.CGroupParent,
- cgroupParentFlagName, "",
- "Optional parent cgroup for the container",
- )
- _ = cmd.RegisterFlagCompletionFunc(cgroupParentFlagName, completion.AutocompleteDefault)
+ cpuPeriodFlagName := "cpu-period"
+ createFlags.Uint64Var(
+ &cf.CPUPeriod,
+ cpuPeriodFlagName, 0,
+ "Limit the CPU CFS (Completely Fair Scheduler) period",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cpuPeriodFlagName, completion.AutocompleteNone)
- cidfileFlagName := "cidfile"
- createFlags.StringVar(
- &cf.CIDFile,
- cidfileFlagName, "",
- "Write the container ID to the file",
- )
- _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
+ cpuQuotaFlagName := "cpu-quota"
+ createFlags.Int64Var(
+ &cf.CPUQuota,
+ cpuQuotaFlagName, 0,
+ "Limit the CPU CFS (Completely Fair Scheduler) quota",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cpuQuotaFlagName, completion.AutocompleteNone)
- conmonPidfileFlagName := "conmon-pidfile"
- createFlags.StringVar(
- &cf.ConmonPIDFile,
- conmonPidfileFlagName, "",
- "Path to the file that will receive the PID of conmon",
- )
- _ = cmd.RegisterFlagCompletionFunc(conmonPidfileFlagName, completion.AutocompleteDefault)
+ cpuRtPeriodFlagName := "cpu-rt-period"
+ createFlags.Uint64Var(
+ &cf.CPURTPeriod,
+ cpuRtPeriodFlagName, 0,
+ "Limit the CPU real-time period in microseconds",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cpuRtPeriodFlagName, completion.AutocompleteNone)
- cpuPeriodFlagName := "cpu-period"
- createFlags.Uint64Var(
- &cf.CPUPeriod,
- cpuPeriodFlagName, 0,
- "Limit the CPU CFS (Completely Fair Scheduler) period",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpuPeriodFlagName, completion.AutocompleteNone)
+ cpuRtRuntimeFlagName := "cpu-rt-runtime"
+ createFlags.Int64Var(
+ &cf.CPURTRuntime,
+ cpuRtRuntimeFlagName, 0,
+ "Limit the CPU real-time runtime in microseconds",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cpuRtRuntimeFlagName, completion.AutocompleteNone)
- cpuQuotaFlagName := "cpu-quota"
- createFlags.Int64Var(
- &cf.CPUQuota,
- cpuQuotaFlagName, 0,
- "Limit the CPU CFS (Completely Fair Scheduler) quota",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpuQuotaFlagName, completion.AutocompleteNone)
+ cpuSharesFlagName := "cpu-shares"
+ createFlags.Uint64Var(
+ &cf.CPUShares,
+ cpuSharesFlagName, 0,
+ "CPU shares (relative weight)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cpuSharesFlagName, completion.AutocompleteNone)
+ cidfileFlagName := "cidfile"
+ createFlags.StringVar(
+ &cf.CIDFile,
+ cidfileFlagName, "",
+ "Write the container ID to the file",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
+ cpusetMemsFlagName := "cpuset-mems"
+ createFlags.StringVar(
+ &cf.CPUSetMems,
+ cpusetMemsFlagName, "",
+ "Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cpusetMemsFlagName, completion.AutocompleteNone)
- cpuRtPeriodFlagName := "cpu-rt-period"
- createFlags.Uint64Var(
- &cf.CPURTPeriod,
- cpuRtPeriodFlagName, 0,
- "Limit the CPU real-time period in microseconds",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpuRtPeriodFlagName, completion.AutocompleteNone)
+ deviceFlagName := "device"
+ createFlags.StringSliceVar(
+ &cf.Devices,
+ deviceFlagName, devices(),
+ "Add a host device to the container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault)
- cpuRtRuntimeFlagName := "cpu-rt-runtime"
- createFlags.Int64Var(
- &cf.CPURTRuntime,
- cpuRtRuntimeFlagName, 0,
- "Limit the CPU real-time runtime in microseconds",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpuRtRuntimeFlagName, completion.AutocompleteNone)
+ deviceCgroupRuleFlagName := "device-cgroup-rule"
+ createFlags.StringSliceVar(
+ &cf.DeviceCGroupRule,
+ deviceCgroupRuleFlagName, []string{},
+ "Add a rule to the cgroup allowed devices list",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(deviceCgroupRuleFlagName, completion.AutocompleteNone)
- cpuSharesFlagName := "cpu-shares"
- createFlags.Uint64Var(
- &cf.CPUShares,
- cpuSharesFlagName, 0,
- "CPU shares (relative weight)",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpuSharesFlagName, completion.AutocompleteNone)
+ deviceReadBpsFlagName := "device-read-bps"
+ createFlags.StringSliceVar(
+ &cf.DeviceReadBPs,
+ deviceReadBpsFlagName, []string{},
+ "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(deviceReadBpsFlagName, completion.AutocompleteDefault)
- cpusFlagName := "cpus"
- createFlags.Float64Var(
- &cf.CPUS,
- cpusFlagName, 0,
- "Number of CPUs. The default is 0.000 which means no limit",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone)
+ deviceReadIopsFlagName := "device-read-iops"
+ createFlags.StringSliceVar(
+ &cf.DeviceReadIOPs,
+ deviceReadIopsFlagName, []string{},
+ "Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(deviceReadIopsFlagName, completion.AutocompleteDefault)
- cpusetCpusFlagName := "cpuset-cpus"
- createFlags.StringVar(
- &cf.CPUSetCPUs,
- cpusetCpusFlagName, "",
- "CPUs in which to allow execution (0-3, 0,1)",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpusetCpusFlagName, completion.AutocompleteNone)
+ deviceWriteBpsFlagName := "device-write-bps"
+ createFlags.StringSliceVar(
+ &cf.DeviceWriteBPs,
+ deviceWriteBpsFlagName, []string{},
+ "Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(deviceWriteBpsFlagName, completion.AutocompleteDefault)
- cpusetMemsFlagName := "cpuset-mems"
- createFlags.StringVar(
- &cf.CPUSetMems,
- cpusetMemsFlagName, "",
- "Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.",
- )
- _ = cmd.RegisterFlagCompletionFunc(cpusetMemsFlagName, completion.AutocompleteNone)
+ deviceWriteIopsFlagName := "device-write-iops"
+ createFlags.StringSliceVar(
+ &cf.DeviceWriteIOPs,
+ deviceWriteIopsFlagName, []string{},
+ "Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(deviceWriteIopsFlagName, completion.AutocompleteDefault)
- deviceFlagName := "device"
- createFlags.StringSliceVar(
- &cf.Devices,
- deviceFlagName, devices(),
- "Add a host device to the container",
- )
- _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault)
+ createFlags.Bool(
+ "disable-content-trust", false,
+ "This is a Docker specific option and is a NOOP",
+ )
- deviceCgroupRuleFlagName := "device-cgroup-rule"
- createFlags.StringSliceVar(
- &cf.DeviceCGroupRule,
- deviceCgroupRuleFlagName, []string{},
- "Add a rule to the cgroup allowed devices list",
- )
- _ = cmd.RegisterFlagCompletionFunc(deviceCgroupRuleFlagName, completion.AutocompleteNone)
+ envFlagName := "env"
+ createFlags.StringArrayP(
+ envFlagName, "e", env(),
+ "Set environment variables in container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone)
+
+ if !registry.IsRemote() {
+ createFlags.BoolVar(
+ &cf.EnvHost,
+ "env-host", false, "Use all current host environment variables in container",
+ )
+ }
+
+ envFileFlagName := "env-file"
+ createFlags.StringSliceVar(
+ &cf.EnvFile,
+ envFileFlagName, []string{},
+ "Read in a file of environment variables",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(envFileFlagName, completion.AutocompleteDefault)
- deviceReadBpsFlagName := "device-read-bps"
- createFlags.StringSliceVar(
- &cf.DeviceReadBPs,
- deviceReadBpsFlagName, []string{},
- "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)",
- )
- _ = cmd.RegisterFlagCompletionFunc(deviceReadBpsFlagName, completion.AutocompleteDefault)
+ exposeFlagName := "expose"
+ createFlags.StringSliceVar(
+ &cf.Expose,
+ exposeFlagName, []string{},
+ "Expose a port or a range of ports",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(exposeFlagName, completion.AutocompleteNone)
- deviceReadIopsFlagName := "device-read-iops"
- createFlags.StringSliceVar(
- &cf.DeviceReadIOPs,
- deviceReadIopsFlagName, []string{},
- "Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)",
- )
- _ = cmd.RegisterFlagCompletionFunc(deviceReadIopsFlagName, completion.AutocompleteDefault)
+ groupAddFlagName := "group-add"
+ createFlags.StringSliceVar(
+ &cf.GroupAdd,
+ groupAddFlagName, []string{},
+ "Add additional groups to the primary container process. 'keep-groups' allows container processes to use supplementary groups.",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(groupAddFlagName, completion.AutocompleteNone)
- deviceWriteBpsFlagName := "device-write-bps"
- createFlags.StringSliceVar(
- &cf.DeviceWriteBPs,
- deviceWriteBpsFlagName, []string{},
- "Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)",
- )
- _ = cmd.RegisterFlagCompletionFunc(deviceWriteBpsFlagName, completion.AutocompleteDefault)
+ healthCmdFlagName := "health-cmd"
+ createFlags.StringVar(
+ &cf.HealthCmd,
+ healthCmdFlagName, "",
+ "set a healthcheck command for the container ('none' disables the existing healthcheck)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(healthCmdFlagName, completion.AutocompleteNone)
- deviceWriteIopsFlagName := "device-write-iops"
- createFlags.StringSliceVar(
- &cf.DeviceWriteIOPs,
- deviceWriteIopsFlagName, []string{},
- "Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)",
- )
- _ = cmd.RegisterFlagCompletionFunc(deviceWriteIopsFlagName, completion.AutocompleteDefault)
+ healthIntervalFlagName := "health-interval"
+ createFlags.StringVar(
+ &cf.HealthInterval,
+ healthIntervalFlagName, DefaultHealthCheckInterval,
+ "set an interval for the healthchecks (a value of disable results in no automatic timer setup)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(healthIntervalFlagName, completion.AutocompleteNone)
- createFlags.Bool(
- "disable-content-trust", false,
- "This is a Docker specific option and is a NOOP",
- )
+ healthRetriesFlagName := "health-retries"
+ createFlags.UintVar(
+ &cf.HealthRetries,
+ healthRetriesFlagName, DefaultHealthCheckRetries,
+ "the number of retries allowed before a healthcheck is considered to be unhealthy",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(healthRetriesFlagName, completion.AutocompleteNone)
- entrypointFlagName := "entrypoint"
- createFlags.String(entrypointFlagName, "",
- "Overwrite the default ENTRYPOINT of the image",
- )
- _ = cmd.RegisterFlagCompletionFunc(entrypointFlagName, completion.AutocompleteNone)
+ healthStartPeriodFlagName := "health-start-period"
+ createFlags.StringVar(
+ &cf.HealthStartPeriod,
+ healthStartPeriodFlagName, DefaultHealthCheckStartPeriod,
+ "the initialization time needed for a container to bootstrap",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(healthStartPeriodFlagName, completion.AutocompleteNone)
- envFlagName := "env"
- createFlags.StringArrayP(
- envFlagName, "e", env(),
- "Set environment variables in container",
- )
- _ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone)
+ healthTimeoutFlagName := "health-timeout"
+ createFlags.StringVar(
+ &cf.HealthTimeout,
+ healthTimeoutFlagName, DefaultHealthCheckTimeout,
+ "the maximum time allowed to complete the healthcheck before an interval is considered failed",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(healthTimeoutFlagName, completion.AutocompleteNone)
- if !registry.IsRemote() {
createFlags.BoolVar(
- &cf.EnvHost,
- "env-host", false, "Use all current host environment variables in container",
+ &cf.HTTPProxy,
+ "http-proxy", containerConfig.Containers.HTTPProxy,
+ "Set proxy environment variables in the container based on the host proxy vars",
)
- }
-
- envFileFlagName := "env-file"
- createFlags.StringSliceVar(
- &cf.EnvFile,
- envFileFlagName, []string{},
- "Read in a file of environment variables",
- )
- _ = cmd.RegisterFlagCompletionFunc(envFileFlagName, completion.AutocompleteDefault)
-
- exposeFlagName := "expose"
- createFlags.StringSliceVar(
- &cf.Expose,
- exposeFlagName, []string{},
- "Expose a port or a range of ports",
- )
- _ = cmd.RegisterFlagCompletionFunc(exposeFlagName, completion.AutocompleteNone)
- gidmapFlagName := "gidmap"
- createFlags.StringSliceVar(
- &cf.GIDMap,
- gidmapFlagName, []string{},
- "GID map to use for the user namespace",
- )
- _ = cmd.RegisterFlagCompletionFunc(gidmapFlagName, completion.AutocompleteNone)
+ imageVolumeFlagName := "image-volume"
+ createFlags.StringVar(
+ &cf.ImageVolume,
+ imageVolumeFlagName, DefaultImageVolume,
+ `Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore")`,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(imageVolumeFlagName, AutocompleteImageVolume)
- groupAddFlagName := "group-add"
- createFlags.StringSliceVar(
- &cf.GroupAdd,
- groupAddFlagName, []string{},
- "Add additional groups to the primary container process. 'keep-groups' allows container processes to use supplementary groups.",
- )
- _ = cmd.RegisterFlagCompletionFunc(groupAddFlagName, completion.AutocompleteNone)
+ createFlags.BoolVar(
+ &cf.Init,
+ "init", false,
+ "Run an init binary inside the container that forwards signals and reaps processes",
+ )
- createFlags.Bool(
- "help", false, "",
- )
+ initPathFlagName := "init-path"
+ createFlags.StringVar(
+ &cf.InitPath,
+ initPathFlagName, initPath(),
+ // Do not use the Value field for setting the default value to determine user input (i.e., non-empty string)
+ "Path to the container-init binary",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(initPathFlagName, completion.AutocompleteDefault)
- healthCmdFlagName := "health-cmd"
- createFlags.StringVar(
- &cf.HealthCmd,
- healthCmdFlagName, "",
- "set a healthcheck command for the container ('none' disables the existing healthcheck)",
- )
- _ = cmd.RegisterFlagCompletionFunc(healthCmdFlagName, completion.AutocompleteNone)
+ createFlags.BoolVarP(
+ &cf.Interactive,
+ "interactive", "i", false,
+ "Keep STDIN open even if not attached",
+ )
+ ipcFlagName := "ipc"
+ createFlags.String(
+ ipcFlagName, "",
+ "IPC namespace to use",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(ipcFlagName, AutocompleteNamespace)
- healthIntervalFlagName := "health-interval"
- createFlags.StringVar(
- &cf.HealthInterval,
- healthIntervalFlagName, DefaultHealthCheckInterval,
- "set an interval for the healthchecks (a value of disable results in no automatic timer setup)",
- )
- _ = cmd.RegisterFlagCompletionFunc(healthIntervalFlagName, completion.AutocompleteNone)
+ kernelMemoryFlagName := "kernel-memory"
+ createFlags.StringVar(
+ &cf.KernelMemory,
+ kernelMemoryFlagName, "",
+ "Kernel memory limit "+sizeWithUnitFormat,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(kernelMemoryFlagName, completion.AutocompleteNone)
+ logDriverFlagName := "log-driver"
+ createFlags.StringVar(
+ &cf.LogDriver,
+ logDriverFlagName, logDriver(),
+ "Logging driver for the container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(logDriverFlagName, AutocompleteLogDriver)
- healthRetriesFlagName := "health-retries"
- createFlags.UintVar(
- &cf.HealthRetries,
- healthRetriesFlagName, DefaultHealthCheckRetries,
- "the number of retries allowed before a healthcheck is considered to be unhealthy",
- )
- _ = cmd.RegisterFlagCompletionFunc(healthRetriesFlagName, completion.AutocompleteNone)
+ logOptFlagName := "log-opt"
+ createFlags.StringSliceVar(
+ &cf.LogOptions,
+ logOptFlagName, []string{},
+ "Logging driver options",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(logOptFlagName, AutocompleteLogOpt)
- healthStartPeriodFlagName := "health-start-period"
- createFlags.StringVar(
- &cf.HealthStartPeriod,
- healthStartPeriodFlagName, DefaultHealthCheckStartPeriod,
- "the initialization time needed for a container to bootstrap",
- )
- _ = cmd.RegisterFlagCompletionFunc(healthStartPeriodFlagName, completion.AutocompleteNone)
+ memoryFlagName := "memory"
+ createFlags.StringVarP(
+ &cf.Memory,
+ memoryFlagName, "m", "",
+ "Memory limit "+sizeWithUnitFormat,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)
- healthTimeoutFlagName := "health-timeout"
- createFlags.StringVar(
- &cf.HealthTimeout,
- healthTimeoutFlagName, DefaultHealthCheckTimeout,
- "the maximum time allowed to complete the healthcheck before an interval is considered failed",
- )
- _ = cmd.RegisterFlagCompletionFunc(healthTimeoutFlagName, completion.AutocompleteNone)
+ memoryReservationFlagName := "memory-reservation"
+ createFlags.StringVar(
+ &cf.MemoryReservation,
+ memoryReservationFlagName, "",
+ "Memory soft limit "+sizeWithUnitFormat,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(memoryReservationFlagName, completion.AutocompleteNone)
- hostnameFlagName := "hostname"
- createFlags.StringVarP(
- &cf.Hostname,
- hostnameFlagName, "h", "",
- "Set container hostname",
- )
- _ = cmd.RegisterFlagCompletionFunc(hostnameFlagName, completion.AutocompleteNone)
+ memorySwapFlagName := "memory-swap"
+ createFlags.StringVar(
+ &cf.MemorySwap,
+ memorySwapFlagName, "",
+ "Swap limit equal to memory plus swap: '-1' to enable unlimited swap",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(memorySwapFlagName, completion.AutocompleteNone)
- createFlags.BoolVar(
- &cf.HTTPProxy,
- "http-proxy", containerConfig.Containers.HTTPProxy,
- "Set proxy environment variables in the container based on the host proxy vars",
- )
+ memorySwappinessFlagName := "memory-swappiness"
+ createFlags.Int64Var(
+ &cf.MemorySwappiness,
+ memorySwappinessFlagName, -1,
+ "Tune container memory swappiness (0 to 100, or -1 for system default)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(memorySwappinessFlagName, completion.AutocompleteNone)
- imageVolumeFlagName := "image-volume"
- createFlags.StringVar(
- &cf.ImageVolume,
- imageVolumeFlagName, DefaultImageVolume,
- `Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore")`,
- )
- _ = cmd.RegisterFlagCompletionFunc(imageVolumeFlagName, AutocompleteImageVolume)
+ createFlags.BoolVar(
+ &cf.NoHealthCheck,
+ "no-healthcheck", false,
+ "Disable healthchecks on container",
+ )
+ createFlags.BoolVar(
+ &cf.OOMKillDisable,
+ "oom-kill-disable", false,
+ "Disable OOM Killer",
+ )
- createFlags.BoolVar(
- &cf.Init,
- "init", false,
- "Run an init binary inside the container that forwards signals and reaps processes",
- )
+ oomScoreAdjFlagName := "oom-score-adj"
+ createFlags.IntVar(
+ &cf.OOMScoreAdj,
+ oomScoreAdjFlagName, 0,
+ "Tune the host's OOM preferences (-1000 to 1000)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(oomScoreAdjFlagName, completion.AutocompleteNone)
- initPathFlagName := "init-path"
- createFlags.StringVar(
- &cf.InitPath,
- initPathFlagName, initPath(),
- // Do not use the Value field for setting the default value to determine user input (i.e., non-empty string)
- "Path to the container-init binary",
- )
- _ = cmd.RegisterFlagCompletionFunc(initPathFlagName, completion.AutocompleteDefault)
+ archFlagName := "arch"
+ createFlags.StringVar(
+ &cf.Arch,
+ archFlagName, "",
+ "use `ARCH` instead of the architecture of the machine for choosing images",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteArch)
- createFlags.BoolVarP(
- &cf.Interactive,
- "interactive", "i", false,
- "Keep STDIN open even if not attached",
- )
+ osFlagName := "os"
+ createFlags.StringVar(
+ &cf.OS,
+ osFlagName, "",
+ "use `OS` instead of the running OS for choosing images",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS)
- ipcFlagName := "ipc"
- createFlags.String(
- ipcFlagName, "",
- "IPC namespace to use",
- )
- _ = cmd.RegisterFlagCompletionFunc(ipcFlagName, AutocompleteNamespace)
+ variantFlagName := "variant"
+ createFlags.StringVar(
+ &cf.Variant,
+ variantFlagName, "",
+ "Use _VARIANT_ instead of the running architecture variant for choosing images",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone)
- kernelMemoryFlagName := "kernel-memory"
- createFlags.StringVar(
- &cf.KernelMemory,
- kernelMemoryFlagName, "",
- "Kernel memory limit "+sizeWithUnitFormat,
- )
- _ = cmd.RegisterFlagCompletionFunc(kernelMemoryFlagName, completion.AutocompleteNone)
+ pidsLimitFlagName := "pids-limit"
+ createFlags.Int64(
+ pidsLimitFlagName, pidsLimit(),
+ "Tune container pids limit (set 0 for unlimited, -1 for server defaults)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone)
- labelFlagName := "label"
- createFlags.StringArrayVarP(
- &cf.Label,
- labelFlagName, "l", []string{},
- "Set metadata on container",
- )
- _ = cmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone)
+ platformFlagName := "platform"
+ createFlags.StringVar(
+ &cf.Platform,
+ platformFlagName, "",
+ "Specify the platform for selecting the image. (Conflicts with --arch and --os)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(platformFlagName, completion.AutocompleteNone)
- labelFileFlagName := "label-file"
- createFlags.StringSliceVar(
- &cf.LabelFile,
- labelFileFlagName, []string{},
- "Read in a line delimited file of labels",
- )
- _ = cmd.RegisterFlagCompletionFunc(labelFileFlagName, completion.AutocompleteDefault)
+ podFlagName := "pod"
+ createFlags.StringVar(
+ &cf.Pod,
+ podFlagName, "",
+ "Run container in an existing pod",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(podFlagName, AutocompletePods)
- logDriverFlagName := "log-driver"
- createFlags.StringVar(
- &cf.LogDriver,
- logDriverFlagName, logDriver(),
- "Logging driver for the container",
- )
- _ = cmd.RegisterFlagCompletionFunc(logDriverFlagName, AutocompleteLogDriver)
+ podIDFileFlagName := "pod-id-file"
+ createFlags.StringVar(
+ &cf.PodIDFile,
+ podIDFileFlagName, "",
+ "Read the pod ID from the file",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(podIDFileFlagName, completion.AutocompleteDefault)
+ createFlags.BoolVar(
+ &cf.Privileged,
+ "privileged", false,
+ "Give extended privileges to container",
+ )
+ createFlags.BoolVarP(
+ &cf.PublishAll,
+ "publish-all", "P", false,
+ "Publish all exposed ports to random ports on the host interface",
+ )
- logOptFlagName := "log-opt"
- createFlags.StringSliceVar(
- &cf.LogOptions,
- logOptFlagName, []string{},
- "Logging driver options",
- )
- _ = cmd.RegisterFlagCompletionFunc(logOptFlagName, AutocompleteLogOpt)
+ pullFlagName := "pull"
+ createFlags.StringVar(
+ &cf.Pull,
+ pullFlagName, policy(),
+ `Pull image before creating ("always"|"missing"|"never")`,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(pullFlagName, AutocompletePullOption)
- memoryFlagName := "memory"
- createFlags.StringVarP(
- &cf.Memory,
- memoryFlagName, "m", "",
- "Memory limit "+sizeWithUnitFormat,
- )
- _ = cmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)
+ createFlags.BoolVarP(
+ &cf.Quiet,
+ "quiet", "q", false,
+ "Suppress output information when pulling images",
+ )
+ createFlags.BoolVar(
+ &cf.ReadOnly,
+ "read-only", false,
+ "Make containers root filesystem read-only",
+ )
+ createFlags.BoolVar(
+ &cf.ReadOnlyTmpFS,
+ "read-only-tmpfs", true,
+ "When running containers in read-only mode mount a read-write tmpfs on /run, /tmp and /var/tmp",
+ )
+ requiresFlagName := "requires"
+ createFlags.StringSliceVar(
+ &cf.Requires,
+ requiresFlagName, []string{},
+ "Add one or more requirement containers that must be started before this container will start",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(requiresFlagName, AutocompleteContainers)
- memoryReservationFlagName := "memory-reservation"
- createFlags.StringVar(
- &cf.MemoryReservation,
- memoryReservationFlagName, "",
- "Memory soft limit "+sizeWithUnitFormat,
- )
- _ = cmd.RegisterFlagCompletionFunc(memoryReservationFlagName, completion.AutocompleteNone)
+ restartFlagName := "restart"
+ createFlags.StringVar(
+ &cf.Restart,
+ restartFlagName, "",
+ `Restart policy to apply when a container exits ("always"|"no"|"on-failure"|"unless-stopped")`,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(restartFlagName, AutocompleteRestartOption)
- memorySwapFlagName := "memory-swap"
- createFlags.StringVar(
- &cf.MemorySwap,
- memorySwapFlagName, "",
- "Swap limit equal to memory plus swap: '-1' to enable unlimited swap",
- )
- _ = cmd.RegisterFlagCompletionFunc(memorySwapFlagName, completion.AutocompleteNone)
+ createFlags.BoolVar(
+ &cf.Rm,
+ "rm", false,
+ "Remove container (and pod if created) after exit",
+ )
+ createFlags.BoolVar(
+ &cf.RootFS,
+ "rootfs", false,
+ "The first argument is not an image but the rootfs to the exploded container",
+ )
- memorySwappinessFlagName := "memory-swappiness"
- createFlags.Int64Var(
- &cf.MemorySwappiness,
- memorySwappinessFlagName, -1,
- "Tune container memory swappiness (0 to 100, or -1 for system default)",
- )
- _ = cmd.RegisterFlagCompletionFunc(memorySwappinessFlagName, completion.AutocompleteNone)
+ sdnotifyFlagName := "sdnotify"
+ createFlags.StringVar(
+ &cf.SdNotifyMode,
+ sdnotifyFlagName, define.SdNotifyModeContainer,
+ `control sd-notify behavior ("container"|"conmon"|"ignore")`,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(sdnotifyFlagName, AutocompleteSDNotify)
- nameFlagName := "name"
- createFlags.StringVar(
- &cf.Name,
- nameFlagName, "",
- "Assign a name to the container",
- )
- _ = cmd.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)
+ secretFlagName := "secret"
+ createFlags.StringArrayVar(
+ &cf.Secrets,
+ secretFlagName, []string{},
+ "Add secret to container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(secretFlagName, AutocompleteSecrets)
- createFlags.BoolVar(
- &cf.NoHealthCheck,
- "no-healthcheck", false,
- "Disable healthchecks on container",
- )
- createFlags.BoolVar(
- &cf.OOMKillDisable,
- "oom-kill-disable", false,
- "Disable OOM Killer",
- )
+ securityOptFlagName := "security-opt"
+ createFlags.StringArrayVar(
+ &cf.SecurityOpt,
+ securityOptFlagName, []string{},
+ "Security Options",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(securityOptFlagName, AutocompleteSecurityOption)
- oomScoreAdjFlagName := "oom-score-adj"
- createFlags.IntVar(
- &cf.OOMScoreAdj,
- oomScoreAdjFlagName, 0,
- "Tune the host's OOM preferences (-1000 to 1000)",
- )
- _ = cmd.RegisterFlagCompletionFunc(oomScoreAdjFlagName, completion.AutocompleteNone)
+ shmSizeFlagName := "shm-size"
+ createFlags.String(
+ shmSizeFlagName, shmSize(),
+ "Size of /dev/shm "+sizeWithUnitFormat,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone)
- archFlagName := "arch"
- createFlags.StringVar(
- &cf.Arch,
- archFlagName, "",
- "use `ARCH` instead of the architecture of the machine for choosing images",
- )
- _ = cmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteArch)
+ stopSignalFlagName := "stop-signal"
+ createFlags.StringVar(
+ &cf.SignaturePolicy,
+ "signature-policy", "",
+ "`Pathname` of signature policy file (not usually used)",
+ )
+ createFlags.StringVar(
+ &cf.StopSignal,
+ stopSignalFlagName, "",
+ "Signal to stop a container. Default is SIGTERM",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(stopSignalFlagName, AutocompleteStopSignal)
- osFlagName := "os"
- createFlags.StringVar(
- &cf.OS,
- osFlagName, "",
- "use `OS` instead of the running OS for choosing images",
- )
- _ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS)
+ stopTimeoutFlagName := "stop-timeout"
+ createFlags.UintVar(
+ &cf.StopTimeout,
+ stopTimeoutFlagName, containerConfig.Engine.StopTimeout,
+ "Timeout (in seconds) that containers stopped by user command have to exit. If exceeded, the container will be forcibly stopped via SIGKILL.",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(stopTimeoutFlagName, completion.AutocompleteNone)
- variantFlagName := "variant"
- createFlags.StringVar(
- &cf.Variant,
- variantFlagName, "",
- "Use _VARIANT_ instead of the running architecture variant for choosing images",
- )
- _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone)
+ sysctlFlagName := "sysctl"
+ createFlags.StringSliceVar(
+ &cf.Sysctl,
+ sysctlFlagName, []string{},
+ "Sysctl options",
+ )
+ //TODO: Add function for sysctl completion.
+ _ = cmd.RegisterFlagCompletionFunc(sysctlFlagName, completion.AutocompleteNone)
+
+ systemdFlagName := "systemd"
+ createFlags.StringVar(
+ &cf.Systemd,
+ systemdFlagName, "true",
+ `Run container in systemd mode ("true"|"false"|"always")`,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(systemdFlagName, AutocompleteSystemdFlag)
- personalityFlagName := "personality"
- createFlags.StringVar(
- &cf.Personality,
- personalityFlagName, "",
- "Configure execution domain using personality (e.g., LINUX/LINUX32)",
- )
- _ = cmd.RegisterFlagCompletionFunc(personalityFlagName, AutocompleteNamespace)
+ personalityFlagName := "personality"
+ createFlags.StringVar(
+ &cf.Personality,
+ personalityFlagName, "",
+ "Configure execution domain using personality (e.g., LINUX/LINUX32)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(personalityFlagName, AutocompleteNamespace)
- pidFlagName := "pid"
- createFlags.String(
- pidFlagName, "",
- "PID namespace to use",
- )
- _ = cmd.RegisterFlagCompletionFunc(pidFlagName, AutocompleteNamespace)
+ timeoutFlagName := "timeout"
+ createFlags.UintVar(
+ &cf.Timeout,
+ timeoutFlagName, 0,
+ "Maximum length of time a container is allowed to run. The container will be killed automatically after the time expires.",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(timeoutFlagName, completion.AutocompleteNone)
- pidsLimitFlagName := "pids-limit"
- createFlags.Int64(
- pidsLimitFlagName, pidsLimit(),
- "Tune container pids limit (set 0 for unlimited, -1 for server defaults)",
- )
- _ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone)
+ // Flag for TLS verification, so that `run` and `create` commands can make use of it.
+ // Make sure to use `=` while using this flag i.e `--tls-verify=false/true`
+ tlsVerifyFlagName := "tls-verify"
+ createFlags.BoolVar(
+ &cf.TLSVerify,
+ tlsVerifyFlagName, true,
+ "Require HTTPS and verify certificates when contacting registries for pulling images",
+ )
- platformFlagName := "platform"
- createFlags.StringVar(
- &cf.Platform,
- platformFlagName, "",
- "Specify the platform for selecting the image. (Conflicts with --arch and --os)",
- )
- _ = cmd.RegisterFlagCompletionFunc(platformFlagName, completion.AutocompleteNone)
+ tmpfsFlagName := "tmpfs"
+ createFlags.StringArrayVar(
+ &cf.TmpFS,
+ tmpfsFlagName, []string{},
+ "Mount a temporary filesystem (`tmpfs`) into a container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(tmpfsFlagName, completion.AutocompleteDefault)
- podFlagName := "pod"
- createFlags.StringVar(
- &cf.Pod,
- podFlagName, "",
- "Run container in an existing pod",
- )
- _ = cmd.RegisterFlagCompletionFunc(podFlagName, AutocompletePods)
+ createFlags.BoolVarP(
+ &cf.TTY,
+ "tty", "t", false,
+ "Allocate a pseudo-TTY for container",
+ )
- podIDFileFlagName := "pod-id-file"
- createFlags.StringVar(
- &cf.PodIDFile,
- podIDFileFlagName, "",
- "Read the pod ID from the file",
- )
- _ = cmd.RegisterFlagCompletionFunc(podIDFileFlagName, completion.AutocompleteDefault)
-
- // Flag for TLS verification, so that `run` and `create` commands can make use of it.
- // Make sure to use `=` while using this flag i.e `--tls-verify=false/true`
- tlsVerifyFlagName := "tls-verify"
- createFlags.BoolVar(
- &cf.TLSVerify,
- tlsVerifyFlagName, true,
- "Require HTTPS and verify certificates when contacting registries for pulling images",
- )
+ timezoneFlagName := "tz"
+ createFlags.StringVar(
+ &cf.Timezone,
+ timezoneFlagName, containerConfig.TZ(),
+ "Set timezone in container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(timezoneFlagName, completion.AutocompleteNone) //TODO: add timezone completion
- createFlags.BoolVar(
- &cf.Privileged,
- "privileged", false,
- "Give extended privileges to container",
- )
- createFlags.BoolVarP(
- &cf.PublishAll,
- "publish-all", "P", false,
- "Publish all exposed ports to random ports on the host interface",
- )
+ umaskFlagName := "umask"
+ createFlags.StringVar(
+ &cf.Umask,
+ umaskFlagName, containerConfig.Umask(),
+ "Set umask in container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(umaskFlagName, completion.AutocompleteNone)
- pullFlagName := "pull"
- createFlags.StringVar(
- &cf.Pull,
- pullFlagName, policy(),
- `Pull image before creating ("always"|"missing"|"never")`,
- )
- _ = cmd.RegisterFlagCompletionFunc(pullFlagName, AutocompletePullOption)
+ ulimitFlagName := "ulimit"
+ createFlags.StringSliceVar(
+ &cf.Ulimit,
+ ulimitFlagName, ulimits(),
+ "Ulimit options",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(ulimitFlagName, completion.AutocompleteNone)
- createFlags.BoolVarP(
- &cf.Quiet,
- "quiet", "q", false,
- "Suppress output information when pulling images",
- )
- createFlags.BoolVar(
- &cf.ReadOnly,
- "read-only", false,
- "Make containers root filesystem read-only",
- )
- createFlags.BoolVar(
- &cf.ReadOnlyTmpFS,
- "read-only-tmpfs", true,
- "When running containers in read-only mode mount a read-write tmpfs on /run, /tmp and /var/tmp",
- )
- createFlags.BoolVar(
- &cf.Replace,
- "replace", false,
- `If a container with the same name exists, replace it`,
- )
+ userFlagName := "user"
+ createFlags.StringVarP(
+ &cf.User,
+ userFlagName, "u", "",
+ "Username or UID (format: <name|uid>[:<group|gid>])",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(userFlagName, AutocompleteUserFlag)
- requiresFlagName := "requires"
- createFlags.StringSliceVar(
- &cf.Requires,
- requiresFlagName, []string{},
- "Add one or more requirement containers that must be started before this container will start",
- )
- _ = cmd.RegisterFlagCompletionFunc(requiresFlagName, AutocompleteContainers)
+ utsFlagName := "uts"
+ createFlags.String(
+ utsFlagName, "",
+ "UTS namespace to use",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(utsFlagName, AutocompleteNamespace)
- restartFlagName := "restart"
- createFlags.StringVar(
- &cf.Restart,
- restartFlagName, "",
- `Restart policy to apply when a container exits ("always"|"no"|"on-failure"|"unless-stopped")`,
- )
- _ = cmd.RegisterFlagCompletionFunc(restartFlagName, AutocompleteRestartOption)
+ mountFlagName := "mount"
+ createFlags.StringArrayVar(
+ &cf.Mount,
+ mountFlagName, []string{},
+ "Attach a filesystem mount to the container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(mountFlagName, AutocompleteMountFlag)
+
+ volumeDesciption := "Bind mount a volume into the container"
+ if registry.IsRemote() {
+ volumeDesciption = "Bind mount a volume into the container. Volume src will be on the server machine, not the client"
+ }
+ volumeFlagName := "volume"
+ createFlags.StringArrayVarP(
+ &cf.Volume,
+ volumeFlagName, "v", volumes(),
+ volumeDesciption,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag)
- createFlags.BoolVar(
- &cf.Rm,
- "rm", false,
- "Remove container (and pod if created) after exit",
- )
- createFlags.BoolVar(
- &cf.RootFS,
- "rootfs", false,
- "The first argument is not an image but the rootfs to the exploded container",
- )
+ volumesFromFlagName := "volumes-from"
+ createFlags.StringArrayVar(
+ &cf.VolumesFrom,
+ volumesFromFlagName, []string{},
+ "Mount volumes from the specified container(s)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(volumesFromFlagName, AutocompleteContainers)
- sdnotifyFlagName := "sdnotify"
- createFlags.StringVar(
- &cf.SdNotifyMode,
- sdnotifyFlagName, define.SdNotifyModeContainer,
- `control sd-notify behavior ("container"|"conmon"|"ignore")`,
- )
- _ = cmd.RegisterFlagCompletionFunc(sdnotifyFlagName, AutocompleteSDNotify)
+ workdirFlagName := "workdir"
+ createFlags.StringVarP(
+ &cf.Workdir,
+ workdirFlagName, "w", "",
+ "Working directory inside the container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(workdirFlagName, completion.AutocompleteDefault)
- secretFlagName := "secret"
- createFlags.StringArrayVar(
- &cf.Secrets,
- secretFlagName, []string{},
- "Add secret to container",
- )
- _ = cmd.RegisterFlagCompletionFunc(secretFlagName, AutocompleteSecrets)
+ seccompPolicyFlagName := "seccomp-policy"
+ createFlags.StringVar(
+ &cf.SeccompPolicy,
+ seccompPolicyFlagName, "default",
+ "Policy for selecting a seccomp profile (experimental)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(seccompPolicyFlagName, completion.AutocompleteDefault)
- securityOptFlagName := "security-opt"
- createFlags.StringArrayVar(
- &cf.SecurityOpt,
- securityOptFlagName, []string{},
- "Security Options",
- )
- _ = cmd.RegisterFlagCompletionFunc(securityOptFlagName, AutocompleteSecurityOption)
+ cgroupConfFlagName := "cgroup-conf"
+ createFlags.StringSliceVar(
+ &cf.CgroupConf,
+ cgroupConfFlagName, []string{},
+ "Configure cgroup v2 (key=value)",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cgroupConfFlagName, completion.AutocompleteNone)
- shmSizeFlagName := "shm-size"
- createFlags.String(
- shmSizeFlagName, shmSize(),
- "Size of /dev/shm "+sizeWithUnitFormat,
- )
- _ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone)
+ pidFileFlagName := "pidfile"
+ createFlags.StringVar(
+ &cf.PidFile,
+ pidFileFlagName, "",
+ "Write the container process ID to the file")
+ _ = cmd.RegisterFlagCompletionFunc(pidFileFlagName, completion.AutocompleteDefault)
- stopSignalFlagName := "stop-signal"
- createFlags.StringVar(
- &cf.SignaturePolicy,
- "signature-policy", "",
- "`Pathname` of signature policy file (not usually used)",
- )
- createFlags.StringVar(
- &cf.StopSignal,
- stopSignalFlagName, "",
- "Signal to stop a container. Default is SIGTERM",
- )
- _ = cmd.RegisterFlagCompletionFunc(stopSignalFlagName, AutocompleteStopSignal)
+ _ = createFlags.MarkHidden("signature-policy")
+ if registry.IsRemote() {
+ _ = createFlags.MarkHidden("env-host")
+ _ = createFlags.MarkHidden("http-proxy")
+ }
- stopTimeoutFlagName := "stop-timeout"
- createFlags.UintVar(
- &cf.StopTimeout,
- stopTimeoutFlagName, containerConfig.Engine.StopTimeout,
- "Timeout (in seconds) that containers stopped by user command have to exit. If exceeded, the container will be forcibly stopped via SIGKILL.",
- )
- _ = cmd.RegisterFlagCompletionFunc(stopTimeoutFlagName, completion.AutocompleteNone)
+ createFlags.BoolVar(
+ &cf.Replace,
+ "replace", false,
+ `If a container with the same name exists, replace it`,
+ )
+ }
subgidnameFlagName := "subgidname"
createFlags.StringVar(
@@ -688,60 +740,13 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
)
_ = cmd.RegisterFlagCompletionFunc(subuidnameFlagName, completion.AutocompleteSubuidName)
- sysctlFlagName := "sysctl"
+ gidmapFlagName := "gidmap"
createFlags.StringSliceVar(
- &cf.Sysctl,
- sysctlFlagName, []string{},
- "Sysctl options",
- )
- //TODO: Add function for sysctl completion.
- _ = cmd.RegisterFlagCompletionFunc(sysctlFlagName, completion.AutocompleteNone)
-
- systemdFlagName := "systemd"
- createFlags.StringVar(
- &cf.Systemd,
- systemdFlagName, "true",
- `Run container in systemd mode ("true"|"false"|"always")`,
- )
- _ = cmd.RegisterFlagCompletionFunc(systemdFlagName, AutocompleteSystemdFlag)
-
- timeoutFlagName := "timeout"
- createFlags.UintVar(
- &cf.Timeout,
- timeoutFlagName, 0,
- "Maximum length of time a container is allowed to run. The container will be killed automatically after the time expires.",
- )
- _ = cmd.RegisterFlagCompletionFunc(timeoutFlagName, completion.AutocompleteNone)
-
- tmpfsFlagName := "tmpfs"
- createFlags.StringArrayVar(
- &cf.TmpFS,
- tmpfsFlagName, []string{},
- "Mount a temporary filesystem (`tmpfs`) into a container",
- )
- _ = cmd.RegisterFlagCompletionFunc(tmpfsFlagName, completion.AutocompleteDefault)
-
- createFlags.BoolVarP(
- &cf.TTY,
- "tty", "t", false,
- "Allocate a pseudo-TTY for container",
- )
-
- timezoneFlagName := "tz"
- createFlags.StringVar(
- &cf.Timezone,
- timezoneFlagName, containerConfig.TZ(),
- "Set timezone in container",
- )
- _ = cmd.RegisterFlagCompletionFunc(timezoneFlagName, completion.AutocompleteNone) //TODO: add timezone completion
-
- umaskFlagName := "umask"
- createFlags.StringVar(
- &cf.Umask,
- umaskFlagName, containerConfig.Umask(),
- "Set umask in container",
+ &cf.GIDMap,
+ gidmapFlagName, []string{},
+ "GID map to use for the user namespace",
)
- _ = cmd.RegisterFlagCompletionFunc(umaskFlagName, completion.AutocompleteNone)
+ _ = cmd.RegisterFlagCompletionFunc(gidmapFlagName, completion.AutocompleteNone)
uidmapFlagName := "uidmap"
createFlags.StringSliceVar(
@@ -751,22 +756,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
)
_ = cmd.RegisterFlagCompletionFunc(uidmapFlagName, completion.AutocompleteNone)
- ulimitFlagName := "ulimit"
- createFlags.StringSliceVar(
- &cf.Ulimit,
- ulimitFlagName, ulimits(),
- "Ulimit options",
- )
- _ = cmd.RegisterFlagCompletionFunc(ulimitFlagName, completion.AutocompleteNone)
-
- userFlagName := "user"
- createFlags.StringVarP(
- &cf.User,
- userFlagName, "u", "",
- "Username or UID (format: <name|uid>[:<group|gid>])",
- )
- _ = cmd.RegisterFlagCompletionFunc(userFlagName, AutocompleteUserFlag)
-
usernsFlagName := "userns"
createFlags.String(
usernsFlagName, os.Getenv("PODMAN_USERNS"),
@@ -774,75 +763,106 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
)
_ = cmd.RegisterFlagCompletionFunc(usernsFlagName, AutocompleteUserNamespace)
- utsFlagName := "uts"
- createFlags.String(
- utsFlagName, "",
- "UTS namespace to use",
+ cgroupParentFlagName := "cgroup-parent"
+ createFlags.StringVar(
+ &cf.CGroupParent,
+ cgroupParentFlagName, "",
+ "Optional parent cgroup for the container",
)
- _ = cmd.RegisterFlagCompletionFunc(utsFlagName, AutocompleteNamespace)
+ _ = cmd.RegisterFlagCompletionFunc(cgroupParentFlagName, completion.AutocompleteDefault)
- mountFlagName := "mount"
- createFlags.StringArrayVar(
- &cf.Mount,
- mountFlagName, []string{},
- "Attach a filesystem mount to the container",
+ conmonPidfileFlagName := ""
+ if !isInfra {
+ conmonPidfileFlagName = "conmon-pidfile"
+ } else {
+ conmonPidfileFlagName = "infra-conmon-pidfile"
+ }
+ createFlags.StringVar(
+ &cf.ConmonPIDFile,
+ conmonPidfileFlagName, "",
+ "Path to the file that will receive the PID of conmon",
)
- _ = cmd.RegisterFlagCompletionFunc(mountFlagName, AutocompleteMountFlag)
+ _ = cmd.RegisterFlagCompletionFunc(conmonPidfileFlagName, completion.AutocompleteDefault)
- volumeDesciption := "Bind mount a volume into the container"
- if registry.IsRemote() {
- volumeDesciption = "Bind mount a volume into the container. Volume src will be on the server machine, not the client"
- }
- volumeFlagName := "volume"
- createFlags.StringArrayVarP(
- &cf.Volume,
- volumeFlagName, "v", volumes(),
- volumeDesciption,
+ cpusFlagName := "cpus"
+ createFlags.Float64Var(
+ &cf.CPUS,
+ cpusFlagName, 0,
+ "Number of CPUs. The default is 0.000 which means no limit",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone)
+
+ cpusetCpusFlagName := "cpuset-cpus"
+ createFlags.StringVar(
+ &cf.CPUSetCPUs,
+ cpusetCpusFlagName, "",
+ "CPUs in which to allow execution (0-3, 0,1)",
)
- _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag)
+ _ = cmd.RegisterFlagCompletionFunc(cpusetCpusFlagName, completion.AutocompleteNone)
+
+ entrypointFlagName := ""
+ if !isInfra {
+ entrypointFlagName = "entrypoint"
+ } else {
+ entrypointFlagName = "infra-command"
+ }
- volumesFromFlagName := "volumes-from"
- createFlags.StringArrayVar(
- &cf.VolumesFrom,
- volumesFromFlagName, []string{},
- "Mount volumes from the specified container(s)",
+ createFlags.String(entrypointFlagName, "",
+ "Overwrite the default ENTRYPOINT of the image",
)
- _ = cmd.RegisterFlagCompletionFunc(volumesFromFlagName, AutocompleteContainers)
+ _ = cmd.RegisterFlagCompletionFunc(entrypointFlagName, completion.AutocompleteNone)
- workdirFlagName := "workdir"
+ hostnameFlagName := "hostname"
createFlags.StringVarP(
- &cf.Workdir,
- workdirFlagName, "w", "",
- "Working directory inside the container",
+ &cf.Hostname,
+ hostnameFlagName, "h", "",
+ "Set container hostname",
)
- _ = cmd.RegisterFlagCompletionFunc(workdirFlagName, completion.AutocompleteDefault)
+ _ = cmd.RegisterFlagCompletionFunc(hostnameFlagName, completion.AutocompleteNone)
- seccompPolicyFlagName := "seccomp-policy"
- createFlags.StringVar(
- &cf.SeccompPolicy,
- seccompPolicyFlagName, "default",
- "Policy for selecting a seccomp profile (experimental)",
+ labelFlagName := "label"
+ createFlags.StringArrayVarP(
+ &cf.Label,
+ labelFlagName, "l", []string{},
+ "Set metadata on container",
)
- _ = cmd.RegisterFlagCompletionFunc(seccompPolicyFlagName, completion.AutocompleteDefault)
+ _ = cmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone)
- cgroupConfFlagName := "cgroup-conf"
+ labelFileFlagName := "label-file"
createFlags.StringSliceVar(
- &cf.CgroupConf,
- cgroupConfFlagName, []string{},
- "Configure cgroup v2 (key=value)",
+ &cf.LabelFile,
+ labelFileFlagName, []string{},
+ "Read in a line delimited file of labels",
)
- _ = cmd.RegisterFlagCompletionFunc(cgroupConfFlagName, completion.AutocompleteNone)
+ _ = cmd.RegisterFlagCompletionFunc(labelFileFlagName, completion.AutocompleteDefault)
- pidFileFlagName := "pidfile"
- createFlags.StringVar(
- &cf.PidFile,
- pidFileFlagName, "",
- "Write the container process ID to the file")
- _ = cmd.RegisterFlagCompletionFunc(pidFileFlagName, completion.AutocompleteDefault)
-
- _ = createFlags.MarkHidden("signature-policy")
- if registry.IsRemote() {
- _ = createFlags.MarkHidden("env-host")
- _ = createFlags.MarkHidden("http-proxy")
+ nameFlagName := ""
+ if !isInfra {
+ nameFlagName = "name"
+ createFlags.StringVar(
+ &cf.Name,
+ nameFlagName, "",
+ "Assign a name to the container",
+ )
+ } else {
+ nameFlagName = "infra-name"
+ createFlags.StringVar(
+ &cf.Name,
+ nameFlagName, "",
+ "Assign a name to the container",
+ )
}
+ _ = cmd.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)
+
+ createFlags.Bool(
+ "help", false, "",
+ )
+
+ pidFlagName := "pid"
+ createFlags.StringVar(
+ &cf.PID,
+ pidFlagName, "",
+ "PID namespace to use",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(pidFlagName, AutocompleteNamespace)
}
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index c94f46cf2..2f592cba7 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -19,122 +19,6 @@ import (
"github.com/pkg/errors"
)
-type ContainerCLIOpts struct {
- Annotation []string
- Attach []string
- Authfile string
- BlkIOWeight string
- BlkIOWeightDevice []string
- CapAdd []string
- CapDrop []string
- CgroupNS string
- CGroupsMode string
- CGroupParent string
- CIDFile string
- ConmonPIDFile string
- CPUPeriod uint64
- CPUQuota int64
- CPURTPeriod uint64
- CPURTRuntime int64
- CPUShares uint64
- CPUS float64
- CPUSetCPUs string
- CPUSetMems string
- Devices []string
- DeviceCGroupRule []string
- DeviceReadBPs []string
- DeviceReadIOPs []string
- DeviceWriteBPs []string
- DeviceWriteIOPs []string
- Entrypoint *string
- Env []string
- EnvHost bool
- EnvFile []string
- Expose []string
- GIDMap []string
- GroupAdd []string
- HealthCmd string
- HealthInterval string
- HealthRetries uint
- HealthStartPeriod string
- HealthTimeout string
- Hostname string
- HTTPProxy bool
- ImageVolume string
- Init bool
- InitContainerType string
- InitPath string
- Interactive bool
- IPC string
- KernelMemory string
- Label []string
- LabelFile []string
- LogDriver string
- LogOptions []string
- Memory string
- MemoryReservation string
- MemorySwap string
- MemorySwappiness int64
- Name string
- NoHealthCheck bool
- OOMKillDisable bool
- OOMScoreAdj int
- Arch string
- OS string
- Variant string
- Personality string
- PID string
- PIDsLimit *int64
- Platform string
- Pod string
- PodIDFile string
- PreserveFDs uint
- Privileged bool
- PublishAll bool
- Pull string
- Quiet bool
- ReadOnly bool
- ReadOnlyTmpFS bool
- Restart string
- Replace bool
- Requires []string
- Rm bool
- RootFS bool
- Secrets []string
- SecurityOpt []string
- SdNotifyMode string
- ShmSize string
- SignaturePolicy string
- StopSignal string
- StopTimeout uint
- StorageOpt []string
- SubUIDName string
- SubGIDName string
- Sysctl []string
- Systemd string
- Timeout uint
- TLSVerify bool
- TmpFS []string
- TTY bool
- Timezone string
- Umask string
- UIDMap []string
- Ulimit []string
- User string
- UserNS string
- UTS string
- Mount []string
- Volume []string
- VolumesFrom []string
- Workdir string
- SeccompPolicy string
- PidFile string
-
- Net *entities.NetOptions
-
- CgroupConf []string
-}
-
func stringMaptoArray(m map[string]string) []string {
a := make([]string, 0, len(m))
for k, v := range m {
@@ -145,7 +29,7 @@ func stringMaptoArray(m map[string]string) []string {
// ContainerCreateToContainerCLIOpts converts a compat input struct to cliopts so it can be converted to
// a specgen spec.
-func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*ContainerCLIOpts, []string, error) {
+func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.ContainerCreateOptions, []string, error) {
var (
capAdd []string
cappDrop []string
@@ -341,7 +225,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
// Note: several options here are marked as "don't need". this is based
// on speculation by Matt and I. We think that these come into play later
// like with start. We believe this is just a difference in podman/compat
- cliOpts := ContainerCLIOpts{
+ cliOpts := entities.ContainerCreateOptions{
// Attach: nil, // don't need?
Authfile: "",
CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
diff --git a/cmd/podman/common/createparse.go b/cmd/podman/common/createparse.go
deleted file mode 100644
index dcef1a151..000000000
--- a/cmd/podman/common/createparse.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package common
-
-import (
- "github.com/containers/common/pkg/config"
- "github.com/pkg/errors"
-)
-
-// validate determines if the flags and values given by the user are valid. things checked
-// by validate must not need any state information on the flag (i.e. changed)
-func (c *ContainerCLIOpts) validate() error {
- var ()
- if c.Rm && (c.Restart != "" && c.Restart != "no" && c.Restart != "on-failure") {
- return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`)
- }
-
- if _, err := config.ParsePullPolicy(c.Pull); err != nil {
- return err
- }
-
- var imageVolType = map[string]string{
- "bind": "",
- "tmpfs": "",
- "ignore": "",
- }
- if _, ok := imageVolType[c.ImageVolume]; !ok {
- return errors.Errorf("invalid image-volume type %q. Pick one of bind, tmpfs, or ignore", c.ImageVolume)
- }
- return nil
-}
diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go
index aa8714b50..d11f3c9d2 100644
--- a/cmd/podman/common/netflags.go
+++ b/cmd/podman/common/netflags.go
@@ -8,8 +8,10 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/spf13/cobra"
+ "github.com/spf13/pflag"
)
func DefineNetFlags(cmd *cobra.Command) {
@@ -87,12 +89,15 @@ func DefineNetFlags(cmd *cobra.Command) {
// NetFlagsToNetOptions parses the network flags for the given cmd.
// The netnsFromConfig bool is used to indicate if the --network flag
// should always be parsed regardless if it was set on the cli.
-func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.NetOptions, error) {
+func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet, netnsFromConfig bool) (*entities.NetOptions, error) {
var (
err error
)
- opts := entities.NetOptions{}
- opts.AddHosts, err = cmd.Flags().GetStringSlice("add-host")
+ if opts == nil {
+ opts = &entities.NetOptions{}
+ }
+
+ opts.AddHosts, err = flags.GetStringSlice("add-host")
if err != nil {
return nil, err
}
@@ -103,56 +108,50 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
}
}
- if cmd.Flags().Changed("dns") {
- servers, err := cmd.Flags().GetStringSlice("dns")
- if err != nil {
- return nil, err
- }
- for _, d := range servers {
- if d == "none" {
- opts.UseImageResolvConf = true
- if len(servers) > 1 {
- return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
- }
- break
- }
- dns := net.ParseIP(d)
- if dns == nil {
- return nil, errors.Errorf("%s is not an ip address", d)
+ servers, err := flags.GetStringSlice("dns")
+ if err != nil {
+ return nil, err
+ }
+ for _, d := range servers {
+ if d == "none" {
+ opts.UseImageResolvConf = true
+ if len(servers) > 1 {
+ return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
}
- opts.DNSServers = append(opts.DNSServers, dns)
+ break
+ }
+ dns := net.ParseIP(d)
+ if dns == nil {
+ return nil, errors.Errorf("%s is not an ip address", d)
}
+ opts.DNSServers = append(opts.DNSServers, dns)
}
- if cmd.Flags().Changed("dns-opt") {
- options, err := cmd.Flags().GetStringSlice("dns-opt")
- if err != nil {
- return nil, err
- }
- opts.DNSOptions = options
+ options, err := flags.GetStringSlice("dns-opt")
+ if err != nil {
+ return nil, err
}
+ opts.DNSOptions = options
- if cmd.Flags().Changed("dns-search") {
- dnsSearches, err := cmd.Flags().GetStringSlice("dns-search")
- if err != nil {
- return nil, err
- }
- // Validate domains are good
- for _, dom := range dnsSearches {
- if dom == "." {
- if len(dnsSearches) > 1 {
- return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
- }
- continue
- }
- if _, err := parse.ValidateDomain(dom); err != nil {
- return nil, err
+ dnsSearches, err := flags.GetStringSlice("dns-search")
+ if err != nil {
+ return nil, err
+ }
+ // Validate domains are good
+ for _, dom := range dnsSearches {
+ if dom == "." {
+ if len(dnsSearches) > 1 {
+ return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
}
+ continue
+ }
+ if _, err := parse.ValidateDomain(dom); err != nil {
+ return nil, err
}
- opts.DNSSearch = dnsSearches
}
+ opts.DNSSearch = dnsSearches
- m, err := cmd.Flags().GetString("mac-address")
+ m, err := flags.GetString("mac-address")
if err != nil {
return nil, err
}
@@ -164,18 +163,18 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.StaticMAC = &mac
}
- inputPorts, err := cmd.Flags().GetStringSlice("publish")
+ inputPorts, err := flags.GetStringSlice("publish")
if err != nil {
return nil, err
}
if len(inputPorts) > 0 {
- opts.PublishPorts, err = CreatePortBindings(inputPorts)
+ opts.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
if err != nil {
return nil, err
}
}
- ip, err := cmd.Flags().GetString("ip")
+ ip, err := flags.GetString("ip")
if err != nil {
return nil, err
}
@@ -190,15 +189,15 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.StaticIP = &staticIP
}
- opts.NoHosts, err = cmd.Flags().GetBool("no-hosts")
+ opts.NoHosts, err = flags.GetBool("no-hosts")
if err != nil {
return nil, err
}
// parse the --network value only when the flag is set or we need to use
// the netns config value, e.g. when --pod is not used
- if netnsFromConfig || cmd.Flag("network").Changed {
- network, err := cmd.Flags().GetString("network")
+ if netnsFromConfig || flags.Changed("network") {
+ network, err := flags.GetString("network")
if err != nil {
return nil, err
}
@@ -215,12 +214,13 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.CNINetworks = cniNets
}
- aliases, err := cmd.Flags().GetStringSlice("network-alias")
+ aliases, err := flags.GetStringSlice("network-alias")
if err != nil {
return nil, err
}
if len(aliases) > 0 {
opts.Aliases = aliases
}
- return &opts, err
+
+ return opts, err
}
diff --git a/cmd/podman/common/ports.go b/cmd/podman/common/ports.go
deleted file mode 100644
index 2092bbe53..000000000
--- a/cmd/podman/common/ports.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package common
-
-import (
- "github.com/docker/go-connections/nat"
- "github.com/pkg/errors"
-)
-
-func verifyExpose(expose []string) error {
- // add the expose ports from the user (--expose)
- // can be single or a range
- for _, expose := range expose {
- // support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
- _, port := nat.SplitProtoPort(expose)
- // parse the start and end port and create a sequence of ports to expose
- // if expose a port, the start and end port are the same
- _, _, err := nat.ParsePortRange(port)
- if err != nil {
- return errors.Wrapf(err, "invalid range format for --expose: %s", expose)
- }
- }
- return nil
-}
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
deleted file mode 100644
index 59d32f568..000000000
--- a/cmd/podman/common/specgen.go
+++ /dev/null
@@ -1,972 +0,0 @@
-package common
-
-import (
- "fmt"
- "os"
- "strconv"
- "strings"
- "time"
-
- "github.com/containers/image/v5/manifest"
- "github.com/containers/podman/v3/cmd/podman/parse"
- "github.com/containers/podman/v3/libpod/define"
- ann "github.com/containers/podman/v3/pkg/annotations"
- envLib "github.com/containers/podman/v3/pkg/env"
- ns "github.com/containers/podman/v3/pkg/namespaces"
- "github.com/containers/podman/v3/pkg/specgen"
- systemdDefine "github.com/containers/podman/v3/pkg/systemd/define"
- "github.com/containers/podman/v3/pkg/util"
- "github.com/docker/go-units"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
-)
-
-func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU {
- cpu := &specs.LinuxCPU{}
- hasLimits := false
-
- if c.CPUS > 0 {
- period, quota := util.CoresToPeriodAndQuota(c.CPUS)
-
- cpu.Period = &period
- cpu.Quota = &quota
- hasLimits = true
- }
- if c.CPUShares > 0 {
- cpu.Shares = &c.CPUShares
- hasLimits = true
- }
- if c.CPUPeriod > 0 {
- cpu.Period = &c.CPUPeriod
- hasLimits = true
- }
- if c.CPUSetCPUs != "" {
- cpu.Cpus = c.CPUSetCPUs
- hasLimits = true
- }
- if c.CPUSetMems != "" {
- cpu.Mems = c.CPUSetMems
- hasLimits = true
- }
- if c.CPUQuota > 0 {
- cpu.Quota = &c.CPUQuota
- hasLimits = true
- }
- if c.CPURTPeriod > 0 {
- cpu.RealtimePeriod = &c.CPURTPeriod
- hasLimits = true
- }
- if c.CPURTRuntime > 0 {
- cpu.RealtimeRuntime = &c.CPURTRuntime
- hasLimits = true
- }
-
- if !hasLimits {
- return nil
- }
- return cpu
-}
-
-func getIOLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.LinuxBlockIO, error) {
- var err error
- io := &specs.LinuxBlockIO{}
- hasLimits := false
- if b := c.BlkIOWeight; len(b) > 0 {
- u, err := strconv.ParseUint(b, 10, 16)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for blkio-weight")
- }
- nu := uint16(u)
- io.Weight = &nu
- hasLimits = true
- }
-
- if len(c.BlkIOWeightDevice) > 0 {
- if err := parseWeightDevices(s, c.BlkIOWeightDevice); err != nil {
- return nil, err
- }
- hasLimits = true
- }
-
- if bps := c.DeviceReadBPs; len(bps) > 0 {
- if s.ThrottleReadBpsDevice, err = parseThrottleBPSDevices(bps); err != nil {
- return nil, err
- }
- hasLimits = true
- }
-
- if bps := c.DeviceWriteBPs; len(bps) > 0 {
- if s.ThrottleWriteBpsDevice, err = parseThrottleBPSDevices(bps); err != nil {
- return nil, err
- }
- hasLimits = true
- }
-
- if iops := c.DeviceReadIOPs; len(iops) > 0 {
- if s.ThrottleReadIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil {
- return nil, err
- }
- hasLimits = true
- }
-
- if iops := c.DeviceWriteIOPs; len(iops) > 0 {
- if s.ThrottleWriteIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil {
- return nil, err
- }
- hasLimits = true
- }
-
- if !hasLimits {
- return nil, nil
- }
- return io, nil
-}
-
-func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.LinuxMemory, error) {
- var err error
- memory := &specs.LinuxMemory{}
- hasLimits := false
- if m := c.Memory; len(m) > 0 {
- ml, err := units.RAMInBytes(m)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory")
- }
- memory.Limit = &ml
- if c.MemorySwap == "" {
- limit := 2 * ml
- memory.Swap = &(limit)
- }
- hasLimits = true
- }
- if m := c.MemoryReservation; len(m) > 0 {
- mr, err := units.RAMInBytes(m)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory")
- }
- memory.Reservation = &mr
- hasLimits = true
- }
- if m := c.MemorySwap; len(m) > 0 {
- var ms int64
- // only set memory swap if it was set
- // -1 indicates unlimited
- if m != "-1" {
- ms, err = units.RAMInBytes(m)
- memory.Swap = &ms
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory")
- }
- hasLimits = true
- }
- }
- if m := c.KernelMemory; len(m) > 0 {
- mk, err := units.RAMInBytes(m)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for kernel-memory")
- }
- memory.Kernel = &mk
- hasLimits = true
- }
- if c.MemorySwappiness >= 0 {
- swappiness := uint64(c.MemorySwappiness)
- memory.Swappiness = &swappiness
- hasLimits = true
- }
- if c.OOMKillDisable {
- memory.DisableOOMKiller = &c.OOMKillDisable
- hasLimits = true
- }
- if !hasLimits {
- return nil, nil
- }
- return memory, nil
-}
-
-func setNamespaces(s *specgen.SpecGenerator, c *ContainerCLIOpts) error {
- var err error
-
- if c.PID != "" {
- s.PidNS, err = specgen.ParseNamespace(c.PID)
- if err != nil {
- return err
- }
- }
- if c.IPC != "" {
- s.IpcNS, err = specgen.ParseNamespace(c.IPC)
- if err != nil {
- return err
- }
- }
- if c.UTS != "" {
- s.UtsNS, err = specgen.ParseNamespace(c.UTS)
- if err != nil {
- return err
- }
- }
- if c.CgroupNS != "" {
- s.CgroupNS, err = specgen.ParseNamespace(c.CgroupNS)
- if err != nil {
- return err
- }
- }
- // userns must be treated differently
- if c.UserNS != "" {
- s.UserNS, err = specgen.ParseUserNamespace(c.UserNS)
- if err != nil {
- return err
- }
- }
- if c.Net != nil {
- s.NetNS = c.Net.Network
- }
- return nil
-}
-
-func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) error {
- var (
- err error
- )
-
- // validate flags as needed
- if err := c.validate(); err != nil {
- return err
- }
-
- s.User = c.User
- inputCommand := args[1:]
- if len(c.HealthCmd) > 0 {
- if c.NoHealthCheck {
- return errors.New("Cannot specify both --no-healthcheck and --health-cmd")
- }
- s.HealthConfig, err = makeHealthCheckFromCli(c.HealthCmd, c.HealthInterval, c.HealthRetries, c.HealthTimeout, c.HealthStartPeriod)
- if err != nil {
- return err
- }
- } else if c.NoHealthCheck {
- s.HealthConfig = &manifest.Schema2HealthConfig{
- Test: []string{"NONE"},
- }
- }
-
- userNS := ns.UsernsMode(c.UserNS)
- s.IDMappings, err = util.ParseIDMapping(userNS, c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName)
- if err != nil {
- return err
- }
- // If some mappings are specified, assume a private user namespace
- if userNS.IsDefaultValue() && (!s.IDMappings.HostUIDMapping || !s.IDMappings.HostGIDMapping) {
- s.UserNS.NSMode = specgen.Private
- } else {
- s.UserNS.NSMode = specgen.NamespaceMode(userNS)
- }
-
- s.Terminal = c.TTY
-
- if err := verifyExpose(c.Expose); err != nil {
- return err
- }
- // We are not handling the Expose flag yet.
- // s.PortsExpose = c.Expose
- s.PortMappings = c.Net.PublishPorts
- s.PublishExposedPorts = c.PublishAll
- s.Pod = c.Pod
-
- if len(c.PodIDFile) > 0 {
- if len(s.Pod) > 0 {
- return errors.New("Cannot specify both --pod and --pod-id-file")
- }
- podID, err := ReadPodIDFile(c.PodIDFile)
- if err != nil {
- return err
- }
- s.Pod = podID
- }
-
- expose, err := createExpose(c.Expose)
- if err != nil {
- return err
- }
- s.Expose = expose
-
- if err := setNamespaces(s, c); err != nil {
- return err
- }
-
- if sig := c.StopSignal; len(sig) > 0 {
- stopSignal, err := util.ParseSignal(sig)
- if err != nil {
- return err
- }
- s.StopSignal = &stopSignal
- }
-
- // ENVIRONMENT VARIABLES
- //
- // Precedence order (higher index wins):
- // 1) containers.conf (EnvHost, EnvHTTP, Env) 2) image data, 3 User EnvHost/EnvHTTP, 4) env-file, 5) env
- // containers.conf handled and image data handled on the server side
- // user specified EnvHost and EnvHTTP handled on Server Side relative to Server
- // env-file and env handled on client side
- var env map[string]string
-
- // First transform the os env into a map. We need it for the labels later in
- // any case.
- osEnv, err := envLib.ParseSlice(os.Environ())
- if err != nil {
- return errors.Wrap(err, "error parsing host environment variables")
- }
-
- s.EnvHost = c.EnvHost
- s.HTTPProxy = c.HTTPProxy
-
- // env-file overrides any previous variables
- for _, f := range c.EnvFile {
- fileEnv, err := envLib.ParseFile(f)
- if err != nil {
- return err
- }
- // File env is overridden by env.
- env = envLib.Join(env, fileEnv)
- }
-
- parsedEnv, err := envLib.ParseSlice(c.Env)
- if err != nil {
- return err
- }
-
- s.Env = envLib.Join(env, parsedEnv)
-
- // LABEL VARIABLES
- labels, err := parse.GetAllLabels(c.LabelFile, c.Label)
- if err != nil {
- return errors.Wrapf(err, "unable to process labels")
- }
-
- if systemdUnit, exists := osEnv[systemdDefine.EnvVariable]; exists {
- labels[systemdDefine.EnvVariable] = systemdUnit
- }
-
- s.Labels = labels
-
- // ANNOTATIONS
- annotations := make(map[string]string)
-
- // First, add our default annotations
- annotations[ann.TTY] = "false"
- if c.TTY {
- annotations[ann.TTY] = "true"
- }
-
- // Last, add user annotations
- for _, annotation := range c.Annotation {
- splitAnnotation := strings.SplitN(annotation, "=", 2)
- if len(splitAnnotation) < 2 {
- return errors.Errorf("Annotations must be formatted KEY=VALUE")
- }
- annotations[splitAnnotation[0]] = splitAnnotation[1]
- }
- s.Annotations = annotations
-
- s.WorkDir = c.Workdir
- if c.Entrypoint != nil {
- entrypoint := []string{}
- if ep := *c.Entrypoint; len(ep) > 0 {
- // Check if entrypoint specified is json
- if err := json.Unmarshal([]byte(*c.Entrypoint), &entrypoint); err != nil {
- entrypoint = append(entrypoint, ep)
- }
- }
- s.Entrypoint = entrypoint
- }
-
- // Include the command used to create the container.
- s.ContainerCreateCommand = os.Args
-
- if len(inputCommand) > 0 {
- s.Command = inputCommand
- }
-
- // SHM Size
- if c.ShmSize != "" {
- shmSize, err := units.FromHumanSize(c.ShmSize)
- if err != nil {
- return errors.Wrapf(err, "unable to translate --shm-size")
- }
- s.ShmSize = &shmSize
- }
- s.CNINetworks = c.Net.CNINetworks
-
- // Network aliases
- if len(c.Net.Aliases) > 0 {
- // build a map of aliases where key=cniName
- aliases := make(map[string][]string, len(s.CNINetworks))
- for _, cniNetwork := range s.CNINetworks {
- aliases[cniNetwork] = c.Net.Aliases
- }
- s.Aliases = aliases
- }
-
- s.HostAdd = c.Net.AddHosts
- s.UseImageResolvConf = c.Net.UseImageResolvConf
- s.DNSServers = c.Net.DNSServers
- s.DNSSearch = c.Net.DNSSearch
- s.DNSOptions = c.Net.DNSOptions
- s.StaticIP = c.Net.StaticIP
- s.StaticMAC = c.Net.StaticMAC
- s.NetworkOptions = c.Net.NetworkOptions
- s.UseImageHosts = c.Net.NoHosts
-
- s.ImageVolumeMode = c.ImageVolume
- if s.ImageVolumeMode == "bind" {
- s.ImageVolumeMode = "anonymous"
- }
-
- s.Systemd = c.Systemd
- s.SdNotifyMode = c.SdNotifyMode
- if s.ResourceLimits == nil {
- s.ResourceLimits = &specs.LinuxResources{}
- }
- s.ResourceLimits.Memory, err = getMemoryLimits(s, c)
- if err != nil {
- return err
- }
- s.ResourceLimits.BlockIO, err = getIOLimits(s, c)
- if err != nil {
- return err
- }
- if c.PIDsLimit != nil {
- pids := specs.LinuxPids{
- Limit: *c.PIDsLimit,
- }
-
- s.ResourceLimits.Pids = &pids
- }
- s.ResourceLimits.CPU = getCPULimits(c)
-
- unifieds := make(map[string]string)
- for _, unified := range c.CgroupConf {
- splitUnified := strings.SplitN(unified, "=", 2)
- if len(splitUnified) < 2 {
- return errors.Errorf("--cgroup-conf must be formatted KEY=VALUE")
- }
- unifieds[splitUnified[0]] = splitUnified[1]
- }
- if len(unifieds) > 0 {
- s.ResourceLimits.Unified = unifieds
- }
-
- if s.ResourceLimits.CPU == nil && s.ResourceLimits.Pids == nil && s.ResourceLimits.BlockIO == nil && s.ResourceLimits.Memory == nil && s.ResourceLimits.Unified == nil {
- s.ResourceLimits = nil
- }
-
- if s.LogConfiguration == nil {
- s.LogConfiguration = &specgen.LogConfig{}
- }
-
- if ld := c.LogDriver; len(ld) > 0 {
- s.LogConfiguration.Driver = ld
- }
- s.CgroupParent = c.CGroupParent
- s.CgroupsMode = c.CGroupsMode
- s.Groups = c.GroupAdd
-
- s.Hostname = c.Hostname
- sysctl := map[string]string{}
- if ctl := c.Sysctl; len(ctl) > 0 {
- sysctl, err = util.ValidateSysctls(ctl)
- if err != nil {
- return err
- }
- }
- s.Sysctl = sysctl
-
- s.CapAdd = c.CapAdd
- s.CapDrop = c.CapDrop
- s.Privileged = c.Privileged
- s.ReadOnlyFilesystem = c.ReadOnly
- s.ConmonPidFile = c.ConmonPIDFile
-
- s.DependencyContainers = c.Requires
-
- // TODO
- // outside of specgen and oci though
- // defaults to true, check spec/storage
- // s.readonly = c.ReadOnlyTmpFS
- // TODO convert to map?
- // check if key=value and convert
- sysmap := make(map[string]string)
- for _, ctl := range c.Sysctl {
- splitCtl := strings.SplitN(ctl, "=", 2)
- if len(splitCtl) < 2 {
- return errors.Errorf("invalid sysctl value %q", ctl)
- }
- sysmap[splitCtl[0]] = splitCtl[1]
- }
- s.Sysctl = sysmap
-
- if c.CIDFile != "" {
- s.Annotations[define.InspectAnnotationCIDFile] = c.CIDFile
- }
-
- for _, opt := range c.SecurityOpt {
- if opt == "no-new-privileges" {
- s.ContainerSecurityConfig.NoNewPrivileges = true
- } else {
- con := strings.SplitN(opt, "=", 2)
- if len(con) != 2 {
- return fmt.Errorf("invalid --security-opt 1: %q", opt)
- }
- switch con[0] {
- case "apparmor":
- s.ContainerSecurityConfig.ApparmorProfile = con[1]
- s.Annotations[define.InspectAnnotationApparmor] = con[1]
- case "label":
- // TODO selinux opts and label opts are the same thing
- s.ContainerSecurityConfig.SelinuxOpts = append(s.ContainerSecurityConfig.SelinuxOpts, con[1])
- s.Annotations[define.InspectAnnotationLabel] = strings.Join(s.ContainerSecurityConfig.SelinuxOpts, ",label=")
- case "mask":
- s.ContainerSecurityConfig.Mask = append(s.ContainerSecurityConfig.Mask, strings.Split(con[1], ":")...)
- case "proc-opts":
- s.ProcOpts = strings.Split(con[1], ",")
- case "seccomp":
- s.SeccompProfilePath = con[1]
- s.Annotations[define.InspectAnnotationSeccomp] = con[1]
- // this option is for docker compatibility, it is the same as unmask=ALL
- case "systempaths":
- if con[1] == "unconfined" {
- s.ContainerSecurityConfig.Unmask = append(s.ContainerSecurityConfig.Unmask, []string{"ALL"}...)
- } else {
- return fmt.Errorf("invalid systempaths option %q, only `unconfined` is supported", con[1])
- }
- case "unmask":
- s.ContainerSecurityConfig.Unmask = append(s.ContainerSecurityConfig.Unmask, con[1:]...)
- default:
- return fmt.Errorf("invalid --security-opt 2: %q", opt)
- }
- }
- }
-
- s.SeccompPolicy = c.SeccompPolicy
-
- s.VolumesFrom = c.VolumesFrom
-
- // 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, 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})
- }
-
- for _, rule := range c.DeviceCGroupRule {
- dev, err := parseLinuxResourcesDeviceAccess(rule)
- if err != nil {
- return err
- }
- s.DeviceCGroupRule = append(s.DeviceCGroupRule, dev)
- }
-
- s.Init = c.Init
- s.InitPath = c.InitPath
- s.Stdin = c.Interactive
- // quiet
- // DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
-
- // Rlimits/Ulimits
- for _, u := range c.Ulimit {
- if u == "host" {
- s.Rlimits = nil
- break
- }
- ul, err := units.ParseUlimit(u)
- if err != nil {
- return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u)
- }
- rl := specs.POSIXRlimit{
- Type: ul.Name,
- Hard: uint64(ul.Hard),
- Soft: uint64(ul.Soft),
- }
- s.Rlimits = append(s.Rlimits, rl)
- }
-
- logOpts := make(map[string]string)
- for _, o := range c.LogOptions {
- split := strings.SplitN(o, "=", 2)
- if len(split) < 2 {
- return errors.Errorf("invalid log option %q", o)
- }
- switch strings.ToLower(split[0]) {
- case "driver":
- s.LogConfiguration.Driver = split[1]
- case "path":
- s.LogConfiguration.Path = split[1]
- case "max-size":
- logSize, err := units.FromHumanSize(split[1])
- if err != nil {
- return err
- }
- s.LogConfiguration.Size = logSize
- default:
- logOpts[split[0]] = split[1]
- }
- }
- s.LogConfiguration.Options = logOpts
- s.Name = c.Name
- s.PreserveFDs = c.PreserveFDs
-
- s.OOMScoreAdj = &c.OOMScoreAdj
- if c.Restart != "" {
- splitRestart := strings.Split(c.Restart, ":")
- switch len(splitRestart) {
- case 1:
- // No retries specified
- case 2:
- if strings.ToLower(splitRestart[0]) != "on-failure" {
- return errors.Errorf("restart policy retries can only be specified with on-failure restart policy")
- }
- retries, err := strconv.Atoi(splitRestart[1])
- if err != nil {
- return errors.Wrapf(err, "error parsing restart policy retry count")
- }
- if retries < 0 {
- return errors.Errorf("must specify restart policy retry count as a number greater than 0")
- }
- var retriesUint = uint(retries)
- s.RestartRetries = &retriesUint
- default:
- return errors.Errorf("invalid restart policy: may specify retries at most once")
- }
- s.RestartPolicy = splitRestart[0]
- }
-
- s.Secrets, s.EnvSecrets, err = parseSecrets(c.Secrets)
- if err != nil {
- return err
- }
-
- if c.Personality != "" {
- s.Personality = &specs.LinuxPersonality{}
- s.Personality.Domain = specs.LinuxPersonalityDomain(c.Personality)
- }
-
- s.Remove = c.Rm
- s.StopTimeout = &c.StopTimeout
- s.Timeout = c.Timeout
- s.Timezone = c.Timezone
- s.Umask = c.Umask
- s.PidFile = c.PidFile
- s.Volatile = c.Rm
-
- // Initcontainers
- s.InitContainerType = c.InitContainerType
- return nil
-}
-
-func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, startPeriod string) (*manifest.Schema2HealthConfig, error) {
- cmdArr := []string{}
- isArr := true
- err := json.Unmarshal([]byte(inCmd), &cmdArr) // array unmarshalling
- if err != nil {
- cmdArr = strings.SplitN(inCmd, " ", 2) // default for compat
- isArr = false
- }
- // Every healthcheck requires a command
- if len(cmdArr) == 0 {
- return nil, errors.New("Must define a healthcheck command for all healthchecks")
- }
- concat := ""
- if cmdArr[0] == "CMD" || cmdArr[0] == "none" { // this is for compat, we are already split properly for most compat cases
- cmdArr = strings.Fields(inCmd)
- } else if cmdArr[0] != "CMD-SHELL" { // this is for podman side of things, won't contain the keywords
- if isArr && len(cmdArr) > 1 { // an array of consecutive commands
- cmdArr = append([]string{"CMD"}, cmdArr...)
- } else { // one singular command
- if len(cmdArr) == 1 {
- concat = cmdArr[0]
- } else {
- concat = strings.Join(cmdArr[0:], " ")
- }
- cmdArr = append([]string{"CMD-SHELL"}, concat)
- }
- }
-
- if cmdArr[0] == "none" { // if specified to remove healtcheck
- cmdArr = []string{"NONE"}
- }
-
- // healthcheck is by default an array, so we simply pass the user input
- hc := manifest.Schema2HealthConfig{
- Test: cmdArr,
- }
-
- if interval == "disable" {
- interval = "0"
- }
- intervalDuration, err := time.ParseDuration(interval)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid healthcheck-interval")
- }
-
- hc.Interval = intervalDuration
-
- if retries < 1 {
- return nil, errors.New("healthcheck-retries must be greater than 0")
- }
- hc.Retries = int(retries)
- timeoutDuration, err := time.ParseDuration(timeout)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid healthcheck-timeout")
- }
- if timeoutDuration < time.Duration(1) {
- return nil, errors.New("healthcheck-timeout must be at least 1 second")
- }
- hc.Timeout = timeoutDuration
-
- startPeriodDuration, err := time.ParseDuration(startPeriod)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid healthcheck-start-period")
- }
- if startPeriodDuration < time.Duration(0) {
- return nil, errors.New("healthcheck-start-period must be 0 seconds or greater")
- }
- hc.StartPeriod = startPeriodDuration
-
- return &hc, nil
-}
-
-func parseWeightDevices(s *specgen.SpecGenerator, weightDevs []string) error {
- for _, val := range weightDevs {
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return fmt.Errorf("bad format for device path: %s", val)
- }
- weight, err := strconv.ParseUint(split[1], 10, 0)
- if err != nil {
- return fmt.Errorf("invalid weight for device: %s", val)
- }
- if weight > 0 && (weight < 10 || weight > 1000) {
- return fmt.Errorf("invalid weight for device: %s", val)
- }
- w := uint16(weight)
- s.WeightDevice[split[0]] = specs.LinuxWeightDevice{
- Weight: &w,
- LeafWeight: nil,
- }
- }
- return nil
-}
-
-func parseThrottleBPSDevices(bpsDevices []string) (map[string]specs.LinuxThrottleDevice, error) {
- td := make(map[string]specs.LinuxThrottleDevice)
- for _, val := range bpsDevices {
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- rate, err := units.RAMInBytes(split[1])
- if err != nil {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
- }
- if rate < 0 {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
- }
- td[split[0]] = specs.LinuxThrottleDevice{Rate: uint64(rate)}
- }
- return td, nil
-}
-
-func parseThrottleIOPsDevices(iopsDevices []string) (map[string]specs.LinuxThrottleDevice, error) {
- td := make(map[string]specs.LinuxThrottleDevice)
- for _, val := range iopsDevices {
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- rate, err := strconv.ParseUint(split[1], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
- }
- td[split[0]] = specs.LinuxThrottleDevice{Rate: rate}
- }
- return td, nil
-}
-
-func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) {
- secretParseError := errors.New("error parsing secret")
- var mount []specgen.Secret
- envs := make(map[string]string)
- for _, val := range secrets {
- // mount only tells if user has set an option that can only be used with mount secret type
- mountOnly := false
- source := ""
- secretType := ""
- target := ""
- var uid, gid uint32
- // default mode 444 octal = 292 decimal
- var mode uint32 = 292
- split := strings.Split(val, ",")
-
- // --secret mysecret
- if len(split) == 1 {
- mountSecret := specgen.Secret{
- Source: val,
- UID: uid,
- GID: gid,
- Mode: mode,
- }
- mount = append(mount, mountSecret)
- continue
- }
- // --secret mysecret,opt=opt
- if !strings.Contains(split[0], "=") {
- source = split[0]
- split = split[1:]
- }
-
- for _, val := range split {
- kv := strings.SplitN(val, "=", 2)
- if len(kv) < 2 {
- return nil, nil, errors.Wrapf(secretParseError, "option %s must be in form option=value", val)
- }
- switch kv[0] {
- case "source":
- source = kv[1]
- case "type":
- if secretType != "" {
- return nil, nil, errors.Wrap(secretParseError, "cannot set more tha one secret type")
- }
- if kv[1] != "mount" && kv[1] != "env" {
- return nil, nil, errors.Wrapf(secretParseError, "type %s is invalid", kv[1])
- }
- secretType = kv[1]
- case "target":
- target = kv[1]
- case "mode":
- mountOnly = true
- mode64, err := strconv.ParseUint(kv[1], 8, 32)
- if err != nil {
- return nil, nil, errors.Wrapf(secretParseError, "mode %s invalid", kv[1])
- }
- mode = uint32(mode64)
- case "uid", "UID":
- mountOnly = true
- uid64, err := strconv.ParseUint(kv[1], 10, 32)
- if err != nil {
- return nil, nil, errors.Wrapf(secretParseError, "UID %s invalid", kv[1])
- }
- uid = uint32(uid64)
- case "gid", "GID":
- mountOnly = true
- gid64, err := strconv.ParseUint(kv[1], 10, 32)
- if err != nil {
- return nil, nil, errors.Wrapf(secretParseError, "GID %s invalid", kv[1])
- }
- gid = uint32(gid64)
-
- default:
- return nil, nil, errors.Wrapf(secretParseError, "option %s invalid", val)
- }
- }
-
- if secretType == "" {
- secretType = "mount"
- }
- if source == "" {
- return nil, nil, errors.Wrapf(secretParseError, "no source found %s", val)
- }
- if secretType == "mount" {
- if target != "" {
- return nil, nil, errors.Wrapf(secretParseError, "target option is invalid for mounted secrets")
- }
- mountSecret := specgen.Secret{
- Source: source,
- UID: uid,
- GID: gid,
- Mode: mode,
- }
- mount = append(mount, mountSecret)
- }
- if secretType == "env" {
- if mountOnly {
- return nil, nil, errors.Wrap(secretParseError, "UID, GID, Mode options cannot be set with secret type env")
- }
- if target == "" {
- target = source
- }
- envs[target] = source
- }
- }
- return mount, envs, nil
-}
-
-var cgroupDeviceType = map[string]bool{
- "a": true, // all
- "b": true, // block device
- "c": true, // character device
-}
-
-var cgroupDeviceAccess = map[string]bool{
- "r": true, //read
- "w": true, //write
- "m": true, //mknod
-}
-
-// parseLinuxResourcesDeviceAccess parses the raw string passed with the --device-access-add flag
-func parseLinuxResourcesDeviceAccess(device string) (specs.LinuxDeviceCgroup, error) {
- var devType, access string
- var major, minor *int64
-
- value := strings.Split(device, " ")
- if len(value) != 3 {
- return specs.LinuxDeviceCgroup{}, fmt.Errorf("invalid device cgroup rule requires type, major:Minor, and access rules: %q", device)
- }
-
- devType = value[0]
- if !cgroupDeviceType[devType] {
- return specs.LinuxDeviceCgroup{}, fmt.Errorf("invalid device type in device-access-add: %s", devType)
- }
-
- number := strings.SplitN(value[1], ":", 2)
- i, err := strconv.ParseInt(number[0], 10, 64)
- if err != nil {
- return specs.LinuxDeviceCgroup{}, err
- }
- major = &i
- if len(number) == 2 && number[1] != "*" {
- i, err := strconv.ParseInt(number[1], 10, 64)
- if err != nil {
- return specs.LinuxDeviceCgroup{}, err
- }
- minor = &i
- }
- access = value[2]
- for _, c := range strings.Split(access, "") {
- if !cgroupDeviceAccess[c] {
- return specs.LinuxDeviceCgroup{}, fmt.Errorf("invalid device access in device-access-add: %s", c)
- }
- }
- return specs.LinuxDeviceCgroup{
- Allow: true,
- Type: devType,
- Major: major,
- Minor: minor,
- Access: access,
- }, nil
-}
diff --git a/cmd/podman/common/util.go b/cmd/podman/common/util.go
deleted file mode 100644
index cdfff9d6f..000000000
--- a/cmd/podman/common/util.go
+++ /dev/null
@@ -1,274 +0,0 @@
-package common
-
-import (
- "io/ioutil"
- "net"
- "strconv"
- "strings"
-
- "github.com/containers/podman/v3/libpod/network/types"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// ReadPodIDFile reads the specified file and returns its content (i.e., first
-// line).
-func ReadPodIDFile(path string) (string, error) {
- content, err := ioutil.ReadFile(path)
- if err != nil {
- return "", errors.Wrap(err, "error reading pod ID file")
- }
- return strings.Split(string(content), "\n")[0], nil
-}
-
-// ReadPodIDFiles reads the specified files and returns their content (i.e.,
-// first line).
-func ReadPodIDFiles(files []string) ([]string, error) {
- ids := []string{}
- for _, file := range files {
- id, err := ReadPodIDFile(file)
- if err != nil {
- return nil, err
- }
- ids = append(ids, id)
- }
- return ids, nil
-}
-
-// ParseFilters transforms one filter format to another and validates input
-func ParseFilters(filter []string) (map[string][]string, error) {
- // TODO Remove once filter refactor is finished and url.Values done.
- filters := map[string][]string{}
- for _, f := range filter {
- t := strings.SplitN(f, "=", 2)
- filters = make(map[string][]string)
- if len(t) < 2 {
- return map[string][]string{}, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
- }
- filters[t[0]] = append(filters[t[0]], t[1])
- }
- return filters, nil
-}
-
-// createExpose parses user-provided exposed port definitions and converts them
-// into SpecGen format.
-// TODO: The SpecGen format should really handle ranges more sanely - we could
-// be massively inflating what is sent over the wire with a large range.
-func createExpose(expose []string) (map[uint16]string, error) {
- toReturn := make(map[uint16]string)
-
- for _, e := range expose {
- // Check for protocol
- proto := "tcp"
- splitProto := strings.Split(e, "/")
- if len(splitProto) > 2 {
- return nil, errors.Errorf("invalid expose format - protocol can only be specified once")
- } else if len(splitProto) == 2 {
- proto = splitProto[1]
- }
-
- // Check for a range
- start, len, err := parseAndValidateRange(splitProto[0])
- if err != nil {
- return nil, err
- }
-
- var index uint16
- for index = 0; index < len; index++ {
- portNum := start + index
- protocols, ok := toReturn[portNum]
- if !ok {
- toReturn[portNum] = proto
- } else {
- newProto := strings.Join(append(strings.Split(protocols, ","), strings.Split(proto, ",")...), ",")
- toReturn[portNum] = newProto
- }
- }
- }
-
- return toReturn, nil
-}
-
-// CreatePortBindings iterates ports mappings into SpecGen format.
-func CreatePortBindings(ports []string) ([]types.PortMapping, error) {
- // --publish is formatted as follows:
- // [[hostip:]hostport[-endPort]:]containerport[-endPort][/protocol]
- toReturn := make([]types.PortMapping, 0, len(ports))
-
- for _, p := range ports {
- var (
- ctrPort string
- proto, hostIP, hostPort *string
- )
-
- splitProto := strings.Split(p, "/")
- switch len(splitProto) {
- case 1:
- // No protocol was provided
- case 2:
- proto = &(splitProto[1])
- default:
- return nil, errors.Errorf("invalid port format - protocol can only be specified once")
- }
-
- remainder := splitProto[0]
- haveV6 := false
-
- // Check for an IPv6 address in brackets
- splitV6 := strings.Split(remainder, "]")
- switch len(splitV6) {
- case 1:
- // Do nothing, proceed as before
- case 2:
- // We potentially have an IPv6 address
- haveV6 = true
- if !strings.HasPrefix(splitV6[0], "[") {
- return nil, errors.Errorf("invalid port format - IPv6 addresses must be enclosed by []")
- }
- if !strings.HasPrefix(splitV6[1], ":") {
- return nil, errors.Errorf("invalid port format - IPv6 address must be followed by a colon (':')")
- }
- ipNoPrefix := strings.TrimPrefix(splitV6[0], "[")
- hostIP = &ipNoPrefix
- remainder = strings.TrimPrefix(splitV6[1], ":")
- default:
- return nil, errors.Errorf("invalid port format - at most one IPv6 address can be specified in a --publish")
- }
-
- splitPort := strings.Split(remainder, ":")
- switch len(splitPort) {
- case 1:
- if haveV6 {
- return nil, errors.Errorf("invalid port format - must provide host and destination port if specifying an IP")
- }
- ctrPort = splitPort[0]
- case 2:
- hostPort = &(splitPort[0])
- ctrPort = splitPort[1]
- case 3:
- if haveV6 {
- return nil, errors.Errorf("invalid port format - when v6 address specified, must be [ipv6]:hostPort:ctrPort")
- }
- hostIP = &(splitPort[0])
- hostPort = &(splitPort[1])
- ctrPort = splitPort[2]
- default:
- return nil, errors.Errorf("invalid port format - format is [[hostIP:]hostPort:]containerPort")
- }
-
- newPort, err := parseSplitPort(hostIP, hostPort, ctrPort, proto)
- if err != nil {
- return nil, err
- }
-
- toReturn = append(toReturn, newPort)
- }
-
- return toReturn, nil
-}
-
-// parseSplitPort parses individual components of the --publish flag to produce
-// a single port mapping in SpecGen format.
-func parseSplitPort(hostIP, hostPort *string, ctrPort string, protocol *string) (types.PortMapping, error) {
- newPort := types.PortMapping{}
- if ctrPort == "" {
- return newPort, errors.Errorf("must provide a non-empty container port to publish")
- }
- ctrStart, ctrLen, err := parseAndValidateRange(ctrPort)
- if err != nil {
- return newPort, errors.Wrapf(err, "error parsing container port")
- }
- newPort.ContainerPort = ctrStart
- newPort.Range = ctrLen
-
- if protocol != nil {
- if *protocol == "" {
- return newPort, errors.Errorf("must provide a non-empty protocol to publish")
- }
- newPort.Protocol = *protocol
- }
- if hostIP != nil {
- if *hostIP == "" {
- return newPort, errors.Errorf("must provide a non-empty container host IP to publish")
- } else if *hostIP != "0.0.0.0" {
- // If hostIP is 0.0.0.0, leave it unset - CNI treats
- // 0.0.0.0 and empty differently, Docker does not.
- testIP := net.ParseIP(*hostIP)
- if testIP == nil {
- return newPort, errors.Errorf("cannot parse %q as an IP address", *hostIP)
- }
- newPort.HostIP = testIP.String()
- }
- }
- if hostPort != nil {
- if *hostPort == "" {
- // Set 0 as a placeholder. The server side of Specgen
- // will find a random, open, unused port to use.
- newPort.HostPort = 0
- } else {
- hostStart, hostLen, err := parseAndValidateRange(*hostPort)
- if err != nil {
- return newPort, errors.Wrapf(err, "error parsing host port")
- }
- if hostLen != ctrLen {
- return newPort, errors.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen)
- }
- newPort.HostPort = hostStart
- }
- }
-
- hport := newPort.HostPort
- logrus.Debugf("Adding port mapping from %d to %d length %d protocol %q", hport, newPort.ContainerPort, newPort.Range, newPort.Protocol)
-
- return newPort, nil
-}
-
-// Parse and validate a port range.
-// Returns start port, length of range, error.
-func parseAndValidateRange(portRange string) (uint16, uint16, error) {
- splitRange := strings.Split(portRange, "-")
- if len(splitRange) > 2 {
- return 0, 0, errors.Errorf("invalid port format - port ranges are formatted as startPort-stopPort")
- }
-
- if splitRange[0] == "" {
- return 0, 0, errors.Errorf("port numbers cannot be negative")
- }
-
- startPort, err := parseAndValidatePort(splitRange[0])
- if err != nil {
- return 0, 0, err
- }
-
- var rangeLen uint16 = 1
- if len(splitRange) == 2 {
- if splitRange[1] == "" {
- return 0, 0, errors.Errorf("must provide ending number for port range")
- }
- endPort, err := parseAndValidatePort(splitRange[1])
- if err != nil {
- return 0, 0, err
- }
- if endPort <= startPort {
- return 0, 0, errors.Errorf("the end port of a range must be higher than the start port - %d is not higher than %d", endPort, startPort)
- }
- // Our range is the total number of ports
- // involved, so we need to add 1 (8080:8081 is
- // 2 ports, for example, not 1)
- rangeLen = endPort - startPort + 1
- }
-
- return startPort, rangeLen, nil
-}
-
-// Turn a single string into a valid U16 port.
-func parseAndValidatePort(port string) (uint16, error) {
- num, err := strconv.Atoi(port)
- if err != nil {
- return 0, errors.Wrapf(err, "invalid port number")
- }
- if num < 1 || num > 65535 {
- return 0, errors.Errorf("port numbers must be between 1 and 65535 (inclusive), got %d", num)
- }
- return uint16(num), nil
-}
diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go
deleted file mode 100644
index 883d604da..000000000
--- a/cmd/podman/common/volumes.go
+++ /dev/null
@@ -1,630 +0,0 @@
-package common
-
-import (
- "fmt"
- "path/filepath"
- "strings"
-
- "github.com/containers/common/pkg/parse"
- "github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/pkg/specgen"
- "github.com/containers/podman/v3/pkg/util"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
-)
-
-var (
- errDuplicateDest = errors.Errorf("duplicate mount destination")
- optionArgError = errors.Errorf("must provide an argument for option")
- noDestError = errors.Errorf("must set volume destination")
- errInvalidSyntax = errors.Errorf("incorrect mount format: should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]")
-)
-
-// Parse all volume-related options in the create config into a set of mounts
-// and named volumes to add to the container.
-// Handles --volumes, --mount, and --tmpfs flags.
-// 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, []*specgen.ImageVolume, error) {
- // Get mounts from the --mounts flag.
- unifiedMounts, unifiedVolumes, unifiedImageVolumes, err := getMounts(mountFlag)
- if err != nil {
- return nil, nil, nil, nil, err
- }
-
- // Next --volumes flag.
- volumeMounts, volumeVolumes, overlayVolumes, err := specgen.GenVolumeMounts(volumeFlag)
- if err != nil {
- return nil, nil, nil, nil, err
- }
-
- // Next --tmpfs flag.
- tmpfsMounts, err := getTmpfsMounts(tmpfsFlag)
- if err != nil {
- 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, nil, errors.Wrapf(errDuplicateDest, dest)
- }
- unifiedMounts[dest] = mount
- }
- for dest, volume := range volumeVolumes {
- if _, ok := unifiedVolumes[dest]; ok {
- 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, nil, errors.Wrapf(errDuplicateDest, dest)
- }
- unifiedMounts[dest] = tmpfs
- }
-
- // If requested, add tmpfs filesystems for read-only containers.
- if addReadOnlyTmpfs {
- readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"}
- options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
- for _, dest := range readonlyTmpfs {
- if _, ok := unifiedMounts[dest]; ok {
- continue
- }
- if _, ok := unifiedVolumes[dest]; ok {
- continue
- }
- unifiedMounts[dest] = spec.Mount{
- Destination: dest,
- Type: define.TypeTmpfs,
- Source: "tmpfs",
- Options: options,
- }
- }
- }
-
- // 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)
- }
- 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 err := testAndSet(dest); err != nil {
- return nil, nil, nil, nil, err
- }
- }
- for dest := range overlayVolumes {
- if err := testAndSet(dest); err != nil {
- return nil, nil, nil, nil, err
- }
- }
- for dest := range unifiedImageVolumes {
- if err := testAndSet(dest); err != nil {
- return nil, nil, nil, nil, err
- }
- }
-
- // Final step: maps to arrays
- finalMounts := make([]spec.Mount, 0, len(unifiedMounts))
- for _, mount := range unifiedMounts {
- if mount.Type == define.TypeBind {
- absSrc, err := filepath.Abs(mount.Source)
- if err != nil {
- return nil, nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
- }
- mount.Source = absSrc
- }
- finalMounts = append(finalMounts, mount)
- }
- finalVolumes := make([]*specgen.NamedVolume, 0, len(unifiedVolumes))
- for _, volume := range unifiedVolumes {
- finalVolumes = append(finalVolumes, volume)
- }
- finalOverlayVolume := make([]*specgen.OverlayVolume, 0)
- 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, finalImageVolumes, nil
-}
-
-// findMountType parses the input and extracts the type of the mount type and
-// the remaining non-type tokens.
-func findMountType(input string) (mountType string, tokens []string, err error) {
- // Split by comma, iterate over the slice and look for
- // "type=$mountType". Everything else is appended to tokens.
- found := false
- for _, s := range strings.Split(input, ",") {
- kv := strings.Split(s, "=")
- if found || !(len(kv) == 2 && kv[0] == "type") {
- tokens = append(tokens, s)
- continue
- }
- mountType = kv[1]
- found = true
- }
- if !found {
- err = errInvalidSyntax
- }
- return
-}
-
-// getMounts takes user-provided input from the --mount flag and creates OCI
-// spec mounts and Libpod named volumes.
-// 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, 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, nil, err
- }
- switch mountType {
- case define.TypeBind:
- mount, err := getBindMount(tokens)
- if err != nil {
- return nil, nil, nil, err
- }
- if _, ok := finalMounts[mount.Destination]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
- }
- finalMounts[mount.Destination] = mount
- case define.TypeTmpfs:
- mount, err := getTmpfsMount(tokens)
- if err != nil {
- return nil, nil, nil, err
- }
- if _, ok := finalMounts[mount.Destination]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
- }
- finalMounts[mount.Destination] = mount
- case define.TypeDevpts:
- mount, err := getDevptsMount(tokens)
- if err != nil {
- return nil, nil, nil, err
- }
- if _, ok := finalMounts[mount.Destination]; ok {
- 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, nil, err
- }
- if _, ok := finalNamedVolumes[volume.Dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, volume.Dest)
- }
- finalNamedVolumes[volume.Dest] = volume
- default:
- return nil, nil, nil, errors.Errorf("invalid filesystem type %q", mountType)
- }
- }
-
- return finalMounts, finalNamedVolumes, finalImageVolumes, nil
-}
-
-// Parse a single bind mount entry from the --mount flag.
-func getBindMount(args []string) (spec.Mount, error) {
- newMount := spec.Mount{
- Type: define.TypeBind,
- }
-
- var setSource, setDest, setRORW, setSuid, setDev, setExec, setRelabel bool
-
- for _, val := range args {
- kv := strings.SplitN(val, "=", 2)
- switch kv[0] {
- case "bind-nonrecursive":
- newMount.Options = append(newMount.Options, "bind")
- case "readonly", "ro", "rw":
- if setRORW {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'readonly', 'ro', or 'rw' options more than once")
- }
- setRORW = true
- // Can be formatted as one of:
- // readonly
- // readonly=[true|false]
- // ro
- // ro=[true|false]
- // rw
- // rw=[true|false]
- if kv[0] == "readonly" {
- kv[0] = "ro"
- }
- switch len(kv) {
- case 1:
- newMount.Options = append(newMount.Options, kv[0])
- case 2:
- switch strings.ToLower(kv[1]) {
- case "true":
- newMount.Options = append(newMount.Options, kv[0])
- case "false":
- // Set the opposite only for rw
- // ro's opposite is the default
- if kv[0] == "rw" {
- newMount.Options = append(newMount.Options, "ro")
- }
- default:
- return newMount, errors.Wrapf(optionArgError, "'readonly', 'ro', or 'rw' must be set to true or false, instead received %q", kv[1])
- }
- default:
- return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val)
- }
- case "nosuid", "suid":
- if setSuid {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once")
- }
- setSuid = true
- newMount.Options = append(newMount.Options, kv[0])
- case "nodev", "dev":
- if setDev {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once")
- }
- setDev = true
- newMount.Options = append(newMount.Options, kv[0])
- case "noexec", "exec":
- if setExec {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once")
- }
- setExec = true
- newMount.Options = append(newMount.Options, kv[0])
- 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 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- newMount.Options = append(newMount.Options, kv[1])
- case "src", "source":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- if len(kv[1]) == 0 {
- return newMount, errors.Wrapf(optionArgError, "host directory cannot be empty")
- }
- newMount.Source = kv[1]
- setSource = true
- case "target", "dst", "destination":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
- return newMount, err
- }
- newMount.Destination = filepath.Clean(kv[1])
- setDest = true
- case "relabel":
- if setRelabel {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'relabel' option more than once")
- }
- setRelabel = true
- if len(kv) != 2 {
- return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0])
- }
- switch kv[1] {
- case "private":
- newMount.Options = append(newMount.Options, "Z")
- case "shared":
- newMount.Options = append(newMount.Options, "z")
- default:
- return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0])
- }
- case "consistency":
- // Often used on MACs and mistakenly on Linux platforms.
- // Since Docker ignores this option so shall we.
- continue
- default:
- return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
- }
- }
-
- if !setDest {
- return newMount, noDestError
- }
-
- if !setSource {
- newMount.Source = newMount.Destination
- }
-
- options, err := parse.ValidateVolumeOpts(newMount.Options)
- if err != nil {
- return newMount, err
- }
- newMount.Options = options
- return newMount, nil
-}
-
-// Parse a single tmpfs mount entry from the --mount flag
-func getTmpfsMount(args []string) (spec.Mount, error) {
- newMount := spec.Mount{
- Type: define.TypeTmpfs,
- Source: define.TypeTmpfs,
- }
-
- var setDest, setRORW, setSuid, setDev, setExec, setTmpcopyup bool
-
- for _, val := range args {
- kv := strings.SplitN(val, "=", 2)
- switch kv[0] {
- case "tmpcopyup", "notmpcopyup":
- if setTmpcopyup {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'tmpcopyup' and 'notmpcopyup' options more than once")
- }
- setTmpcopyup = true
- newMount.Options = append(newMount.Options, kv[0])
- case "ro", "rw":
- if setRORW {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once")
- }
- setRORW = true
- newMount.Options = append(newMount.Options, kv[0])
- case "nosuid", "suid":
- if setSuid {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once")
- }
- setSuid = true
- newMount.Options = append(newMount.Options, kv[0])
- case "nodev", "dev":
- if setDev {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once")
- }
- setDev = true
- newMount.Options = append(newMount.Options, kv[0])
- case "noexec", "exec":
- if setExec {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once")
- }
- setExec = true
- newMount.Options = append(newMount.Options, kv[0])
- case "tmpfs-mode":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- newMount.Options = append(newMount.Options, fmt.Sprintf("mode=%s", kv[1]))
- case "tmpfs-size":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- newMount.Options = append(newMount.Options, fmt.Sprintf("size=%s", kv[1]))
- case "src", "source":
- return newMount, errors.Errorf("source is not supported with tmpfs mounts")
- case "target", "dst", "destination":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
- return newMount, err
- }
- newMount.Destination = filepath.Clean(kv[1])
- setDest = true
- case "consistency":
- // Often used on MACs and mistakenly on Linux platforms.
- // Since Docker ignores this option so shall we.
- continue
- default:
- return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
- }
- }
-
- if !setDest {
- return newMount, noDestError
- }
-
- return newMount, nil
-}
-
-// Parse a single devpts mount entry from the --mount flag
-func getDevptsMount(args []string) (spec.Mount, error) {
- newMount := spec.Mount{
- Type: define.TypeDevpts,
- Source: define.TypeDevpts,
- }
-
- var setDest bool
-
- for _, val := range args {
- kv := strings.SplitN(val, "=", 2)
- switch kv[0] {
- case "target", "dst", "destination":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
- return newMount, err
- }
- newMount.Destination = filepath.Clean(kv[1])
- setDest = true
- default:
- return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
- }
- }
-
- if !setDest {
- return newMount, noDestError
- }
-
- return newMount, nil
-}
-
-// Parse a single volume mount entry from the --mount flag.
-// Note that the volume-label option for named volumes is currently NOT supported.
-// TODO: add support for --volume-label
-func getNamedVolume(args []string) (*specgen.NamedVolume, error) {
- newVolume := new(specgen.NamedVolume)
-
- var setSource, setDest, setRORW, setSuid, setDev, setExec bool
-
- for _, val := range args {
- kv := strings.SplitN(val, "=", 2)
- switch kv[0] {
- case "ro", "rw":
- if setRORW {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once")
- }
- setRORW = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "nosuid", "suid":
- if setSuid {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once")
- }
- setSuid = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "nodev", "dev":
- if setDev {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once")
- }
- setDev = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "noexec", "exec":
- if setExec {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once")
- }
- setExec = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "volume-label":
- return nil, errors.Errorf("the --volume-label option is not presently implemented")
- case "src", "source":
- if len(kv) == 1 {
- return nil, errors.Wrapf(optionArgError, kv[0])
- }
- newVolume.Name = kv[1]
- setSource = true
- 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.Dest = filepath.Clean(kv[1])
- setDest = true
- case "consistency":
- // Often used on MACs and mistakenly on Linux platforms.
- // Since Docker ignores this option so shall we.
- continue
- default:
- return nil, errors.Wrapf(util.ErrBadMntOption, kv[0])
- }
- }
-
- if !setSource {
- return nil, errors.Errorf("must set source volume")
- }
- if !setDest {
- return nil, noDestError
- }
-
- 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])
- }
- case "consistency":
- // Often used on MACs and mistakenly on Linux platforms.
- // Since Docker ignores this option so shall we.
- continue
- 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
-}
-
-// GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts
-func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) {
- m := make(map[string]spec.Mount)
- for _, i := range tmpfsFlag {
- // Default options if nothing passed
- var options []string
- spliti := strings.Split(i, ":")
- destPath := spliti[0]
- if err := parse.ValidateVolumeCtrDir(spliti[0]); err != nil {
- return nil, err
- }
- if len(spliti) > 1 {
- options = strings.Split(spliti[1], ",")
- }
-
- if _, ok := m[destPath]; ok {
- return nil, errors.Wrapf(errDuplicateDest, destPath)
- }
-
- mount := spec.Mount{
- Destination: filepath.Clean(destPath),
- Type: string(define.TypeTmpfs),
- Options: options,
- Source: string(define.TypeTmpfs),
- }
- m[destPath] = mount
- }
- return m, nil
-}