summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/common/completion.go78
-rw-r--r--cmd/podman/common/completion_test.go13
-rw-r--r--cmd/podman/common/create.go1416
-rw-r--r--cmd/podman/common/create_opts.go165
-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
-rw-r--r--cmd/podman/containers/create.go211
-rw-r--r--cmd/podman/containers/logs.go4
-rw-r--r--cmd/podman/containers/prune.go3
-rw-r--r--cmd/podman/containers/restore.go3
-rw-r--r--cmd/podman/containers/run.go19
-rw-r--r--cmd/podman/generate/systemd.go18
-rw-r--r--cmd/podman/images/import.go4
-rw-r--r--cmd/podman/images/prune.go3
-rw-r--r--cmd/podman/machine/init.go9
-rw-r--r--cmd/podman/machine/list.go2
-rw-r--r--cmd/podman/machine/machine.go2
-rw-r--r--cmd/podman/machine/rm.go2
-rw-r--r--cmd/podman/machine/ssh.go2
-rw-r--r--cmd/podman/machine/start.go2
-rw-r--r--cmd/podman/machine/stop.go2
-rw-r--r--cmd/podman/networks/create.go9
-rw-r--r--cmd/podman/networks/prune.go3
-rw-r--r--cmd/podman/play/kube.go48
-rw-r--r--cmd/podman/pods/create.go155
-rw-r--r--cmd/podman/pods/logs.go140
-rw-r--r--cmd/podman/pods/ps.go2
-rw-r--r--cmd/podman/pods/rm.go3
-rw-r--r--cmd/podman/pods/start.go3
-rw-r--r--cmd/podman/pods/stop.go3
-rw-r--r--cmd/podman/secrets/list.go2
-rw-r--r--cmd/podman/volumes/import.go97
36 files changed, 1417 insertions, 3035 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 9a4524b46..e925fb4f1 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -223,7 +223,7 @@ func getSecrets(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCom
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
}
- secrets, err := engine.SecretList(registry.GetContext())
+ secrets, err := engine.SecretList(registry.GetContext(), entities.SecretListRequest{})
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
@@ -985,40 +985,14 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
f = f.Elem()
}
- // // the only supported type is struct
+ // the only supported type is struct
if f.Kind() != reflect.Struct {
return nil, cobra.ShellCompDirectiveNoFileComp
}
// last field get all names to suggest
if i == len(fields)-1 {
- suggestions := []string{}
- for j := 0; j < f.NumField(); j++ {
- fname := f.Type().Field(j).Name
- suffix := "}}"
- kind := f.Type().Field(j).Type.Kind()
- if kind == reflect.Ptr {
- // make sure to read the actual type when it is a pointer
- kind = f.Type().Field(j).Type.Elem().Kind()
- }
- // when we have a nested struct do not append braces instead append a dot
- if kind == reflect.Struct {
- suffix = "."
- }
- if strings.HasPrefix(fname, fields[i]) {
- // add field name with closing braces
- suggestions = append(suggestions, fname+suffix)
- }
- }
-
- for j := 0; j < f.NumMethod(); j++ {
- fname := f.Type().Method(j).Name
- if strings.HasPrefix(fname, fields[i]) {
- // add method name with closing braces
- suggestions = append(suggestions, fname+"}}")
- }
- }
-
+ suggestions := getStructFields(f, fields[i])
// add the current toComplete value in front so that the shell can complete this correctly
toCompArr := strings.Split(toComplete, ".")
toCompArr[len(toCompArr)-1] = ""
@@ -1032,6 +1006,52 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
}
}
+// getStructFields reads all struct field names and method names and returns them.
+func getStructFields(f reflect.Value, prefix string) []string {
+ suggestions := []string{}
+ // follow the pointer first
+ if f.Kind() == reflect.Ptr {
+ f = f.Elem()
+ }
+ // we only support structs
+ if f.Kind() != reflect.Struct {
+ return nil
+ }
+ // loop over all field names
+ for j := 0; j < f.NumField(); j++ {
+ field := f.Type().Field(j)
+ fname := field.Name
+ suffix := "}}"
+ kind := field.Type.Kind()
+ if kind == reflect.Ptr {
+ // make sure to read the actual type when it is a pointer
+ kind = field.Type.Elem().Kind()
+ }
+ // when we have a nested struct do not append braces instead append a dot
+ if kind == reflect.Struct {
+ suffix = "."
+ }
+ if strings.HasPrefix(fname, prefix) {
+ // add field name with suffix
+ suggestions = append(suggestions, fname+suffix)
+ }
+ // if field is anonymous add the child fields as well
+ if field.Anonymous {
+ suggestions = append(suggestions, getStructFields(f.FieldByIndex([]int{j}), prefix)...)
+ }
+ }
+
+ for j := 0; j < f.NumMethod(); j++ {
+ fname := f.Type().Method(j).Name
+ if strings.HasPrefix(fname, prefix) {
+ // add method name with closing braces
+ suggestions = append(suggestions, fname+"}}")
+ }
+ }
+
+ return suggestions
+}
+
// AutocompleteEventFilter - Autocomplete event filter flag options.
// -> "container=", "event=", "image=", "pod=", "volume=", "type="
func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
diff --git a/cmd/podman/common/completion_test.go b/cmd/podman/common/completion_test.go
index 5bd627b85..84b3c1132 100644
--- a/cmd/podman/common/completion_test.go
+++ b/cmd/podman/common/completion_test.go
@@ -17,6 +17,10 @@ type Car struct {
Extras map[string]string
}
+type Anonymous struct {
+ Hello string
+}
+
func (c Car) Type() string {
return ""
}
@@ -30,7 +34,10 @@ func TestAutocompleteFormat(t *testing.T) {
Name string
Age int
Car *Car
- }{}
+ *Anonymous
+ }{
+ Anonymous: &Anonymous{},
+ }
testStruct.Car = &Car{}
testStruct.Car.Extras = map[string]string{"test": "1"}
@@ -73,12 +80,12 @@ func TestAutocompleteFormat(t *testing.T) {
{
"fist level struct field name",
"{{.",
- []string{"{{.Name}}", "{{.Age}}", "{{.Car."},
+ []string{"{{.Name}}", "{{.Age}}", "{{.Car.", "{{.Anonymous.", "{{.Hello}}"},
},
{
"fist level struct field name",
"{{ .",
- []string{"{{ .Name}}", "{{ .Age}}", "{{ .Car."},
+ []string{"{{ .Name}}", "{{ .Age}}", "{{ .Car.", "{{ .Anonymous.", "{{ .Hello}}"},
},
{
"fist level struct field name",
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..09ac61f2e 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -16,125 +16,10 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
+ "github.com/docker/docker/api/types/mount"
"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 +30,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
@@ -210,18 +95,30 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
expose = append(expose, fmt.Sprintf("%s/%s", p.Port(), p.Proto()))
}
- // mounts type=tmpfs/bind,source=,dest=,opt=val
- // TODO options
+ // mounts type=tmpfs/bind,source=...,target=...=,opt=val
mounts := make([]string, 0, len(cc.HostConfig.Mounts))
+ var builder strings.Builder
for _, m := range cc.HostConfig.Mounts {
- mount := fmt.Sprintf("type=%s", m.Type)
- if len(m.Source) > 0 {
- mount += fmt.Sprintf(",source=%s", m.Source)
+ addField(&builder, "type", string(m.Type))
+ addField(&builder, "source", m.Source)
+ addField(&builder, "target", m.Target)
+ addField(&builder, "ro", strconv.FormatBool(m.ReadOnly))
+ addField(&builder, "consistency", string(m.Consistency))
+
+ // Map any specialized mount options that intersect between *Options and cli options
+ switch m.Type {
+ case mount.TypeBind:
+ addField(&builder, "bind-propagation", string(m.BindOptions.Propagation))
+ addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive))
+ case mount.TypeTmpfs:
+ addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10))
+ addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 10))
+ case mount.TypeVolume:
+ // All current VolumeOpts are handled above
+ // See vendor/github.com/containers/common/pkg/parse/parse.go:ValidateVolumeOpts()
}
- if len(m.Target) > 0 {
- mount += fmt.Sprintf(",dst=%s", m.Target)
- }
- mounts = append(mounts, mount)
+ mounts = append(mounts, builder.String())
+ builder.Reset()
}
// dns
@@ -341,7 +238,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...),
@@ -622,3 +519,17 @@ func logDriver() string {
}
return ""
}
+
+// addField is a helper function to populate mount options
+func addField(b *strings.Builder, name string, value string) {
+ if value == "" {
+ return
+ }
+
+ if b.Len() > 0 {
+ b.WriteRune(',')
+ }
+ b.WriteString(name)
+ b.WriteRune('=')
+ b.WriteString(value)
+}
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
-}
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index 7583a024e..8b27de53e 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -17,6 +17,7 @@ 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/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -52,8 +53,8 @@ var (
)
var (
- cliVals common.ContainerCLIOpts
InitContainerType string
+ cliVals entities.ContainerCreateOptions
)
func createFlags(cmd *cobra.Command) {
@@ -67,13 +68,18 @@ func createFlags(cmd *cobra.Command) {
)
flags.SetInterspersed(false)
- common.DefineCreateFlags(cmd, &cliVals)
+ common.DefineCreateFlags(cmd, &cliVals, false)
common.DefineNetFlags(cmd)
flags.SetNormalizeFunc(utils.AliasFlags)
if registry.IsRemote() {
- _ = flags.MarkHidden("conmon-pidfile")
+ if cliVals.IsInfra {
+ _ = flags.MarkHidden("infra-conmon-pidfile")
+ } else {
+ _ = flags.MarkHidden("conmon-pidfile")
+ }
+
_ = flags.MarkHidden("pidfile")
}
@@ -97,7 +103,8 @@ func create(cmd *cobra.Command, args []string) error {
var (
err error
)
- cliVals.Net, err = common.NetFlagsToNetOptions(cmd, cliVals.Pod == "" && cliVals.PodIDFile == "")
+ flags := cmd.Flags()
+ cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags, cliVals.Pod == "" && cliVals.PodIDFile == "")
if err != nil {
return err
}
@@ -113,22 +120,22 @@ func create(cmd *cobra.Command, args []string) error {
cliVals.InitContainerType = initctr
}
- if err := createInit(cmd); err != nil {
+ cliVals, err = CreateInit(cmd, cliVals, false)
+ if err != nil {
return err
}
-
imageName := args[0]
rawImageName := ""
if !cliVals.RootFS {
rawImageName = args[0]
- name, err := pullImage(args[0])
+ name, err := PullImage(args[0], cliVals)
if err != nil {
return err
}
imageName = name
}
s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
- if err := common.FillOutSpecGen(s, &cliVals, args); err != nil {
+ if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
}
s.RawImageName = rawImageName
@@ -169,100 +176,101 @@ func replaceContainer(name string) error {
return removeContainers([]string{name}, rmOptions, false)
}
-func createInit(c *cobra.Command) error {
- cliVals.StorageOpt = registry.PodmanConfig().StorageOpts
-
- if c.Flag("shm-size").Changed {
- cliVals.ShmSize = c.Flag("shm-size").Value.String()
+func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra bool) (entities.ContainerCreateOptions, error) {
+ vals.UserNS = c.Flag("userns").Value.String()
+ // if user did not modify --userns flag and did turn on
+ // uid/gid mappings, set userns flag to "private"
+ if !c.Flag("userns").Changed && vals.UserNS == "host" {
+ if len(vals.UIDMap) > 0 ||
+ len(vals.GIDMap) > 0 ||
+ vals.SubUIDName != "" ||
+ vals.SubGIDName != "" {
+ vals.UserNS = "private"
+ }
}
- if (c.Flag("dns").Changed || c.Flag("dns-opt").Changed || c.Flag("dns-search").Changed) && (cliVals.Net.Network.NSMode == specgen.NoNetwork || cliVals.Net.Network.IsContainer()) {
- return errors.Errorf("conflicting options: dns and the network mode.")
- }
+ if !isInfra {
+ if c.Flag("shm-size").Changed {
+ vals.ShmSize = c.Flag("shm-size").Value.String()
+ }
+ if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
+ return vals, errors.Errorf("--cpu-period and --cpus cannot be set together")
+ }
+ if c.Flag("cpu-quota").Changed && c.Flag("cpus").Changed {
+ return vals, errors.Errorf("--cpu-quota and --cpus cannot be set together")
+ }
+ vals.IPC = c.Flag("ipc").Value.String()
+ vals.UTS = c.Flag("uts").Value.String()
+ vals.PID = c.Flag("pid").Value.String()
+ vals.CgroupNS = c.Flag("cgroupns").Value.String()
+
+ if c.Flags().Changed("group-add") {
+ groups := []string{}
+ for _, g := range cliVals.GroupAdd {
+ if g == "keep-groups" {
+ if len(cliVals.GroupAdd) > 1 {
+ return vals, errors.New("the '--group-add keep-groups' option is not allowed with any other --group-add options")
+ }
+ if registry.IsRemote() {
+ return vals, errors.New("the '--group-add keep-groups' option is not supported in remote mode")
+ }
+ vals.Annotation = append(vals.Annotation, "run.oci.keep_original_groups=1")
+ } else {
+ groups = append(groups, g)
+ }
+ }
+ vals.GroupAdd = groups
+ }
- if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
- return errors.Errorf("--cpu-period and --cpus cannot be set together")
- }
- if c.Flag("cpu-quota").Changed && c.Flag("cpus").Changed {
- return errors.Errorf("--cpu-quota and --cpus cannot be set together")
+ if c.Flags().Changed("pids-limit") {
+ val := c.Flag("pids-limit").Value.String()
+ pidsLimit, err := strconv.ParseInt(val, 10, 32)
+ if err != nil {
+ return vals, err
+ }
+ vals.PIDsLimit = &pidsLimit
+ }
+ if c.Flags().Changed("env") {
+ env, err := c.Flags().GetStringArray("env")
+ if err != nil {
+ return vals, errors.Wrapf(err, "retrieve env flag")
+ }
+ vals.Env = env
+ }
+ if c.Flag("cgroups").Changed && vals.CGroupsMode == "split" && registry.IsRemote() {
+ return vals, errors.Errorf("the option --cgroups=%q is not supported in remote mode", vals.CGroupsMode)
+ }
+
+ if c.Flag("pod").Changed && !strings.HasPrefix(c.Flag("pod").Value.String(), "new:") && c.Flag("userns").Changed {
+ return vals, errors.Errorf("--userns and --pod cannot be set together")
+ }
}
- if c.Flag("pod").Changed && !strings.HasPrefix(c.Flag("pod").Value.String(), "new:") && c.Flag("userns").Changed {
- return errors.Errorf("--userns and --pod cannot be set together")
+ if (c.Flag("dns").Changed || c.Flag("dns-opt").Changed || c.Flag("dns-search").Changed) && vals.Net != nil && (vals.Net.Network.NSMode == specgen.NoNetwork || vals.Net.Network.IsContainer()) {
+ return vals, errors.Errorf("conflicting options: dns and the network mode: " + string(vals.Net.Network.NSMode))
}
-
noHosts, err := c.Flags().GetBool("no-hosts")
if err != nil {
- return err
+ return vals, err
}
if noHosts && c.Flag("add-host").Changed {
- return errors.Errorf("--no-hosts and --add-host cannot be set together")
- }
- cliVals.UserNS = c.Flag("userns").Value.String()
- // if user did not modify --userns flag and did turn on
- // uid/gid mappings, set userns flag to "private"
- if !c.Flag("userns").Changed && cliVals.UserNS == "host" {
- if len(cliVals.UIDMap) > 0 ||
- len(cliVals.GIDMap) > 0 ||
- cliVals.SubUIDName != "" ||
- cliVals.SubGIDName != "" {
- cliVals.UserNS = "private"
- }
+ return vals, errors.Errorf("--no-hosts and --add-host cannot be set together")
}
- cliVals.IPC = c.Flag("ipc").Value.String()
- cliVals.UTS = c.Flag("uts").Value.String()
- cliVals.PID = c.Flag("pid").Value.String()
- cliVals.CgroupNS = c.Flag("cgroupns").Value.String()
- if c.Flag("entrypoint").Changed {
+ if !isInfra && c.Flag("entrypoint").Changed {
val := c.Flag("entrypoint").Value.String()
- cliVals.Entrypoint = &val
- }
-
- if c.Flags().Changed("group-add") {
- groups := []string{}
- for _, g := range cliVals.GroupAdd {
- if g == "keep-groups" {
- if len(cliVals.GroupAdd) > 1 {
- return errors.New("the '--group-add keep-groups' option is not allowed with any other --group-add options")
- }
- if registry.IsRemote() {
- return errors.New("the '--group-add keep-groups' option is not supported in remote mode")
- }
- cliVals.Annotation = append(cliVals.Annotation, "run.oci.keep_original_groups=1")
- } else {
- groups = append(groups, g)
- }
- }
- cliVals.GroupAdd = groups
- }
+ vals.Entrypoint = &val
+ } else if isInfra && c.Flag("infra-command").Changed {
- if c.Flags().Changed("pids-limit") {
- val := c.Flag("pids-limit").Value.String()
- pidsLimit, err := strconv.ParseInt(val, 10, 32)
- if err != nil {
- return err
- }
- cliVals.PIDsLimit = &pidsLimit
- }
- if c.Flags().Changed("env") {
- env, err := c.Flags().GetStringArray("env")
- if err != nil {
- return errors.Wrapf(err, "retrieve env flag")
- }
- cliVals.Env = env
- }
- if c.Flag("cgroups").Changed && cliVals.CGroupsMode == "split" && registry.IsRemote() {
- return errors.Errorf("the option --cgroups=%q is not supported in remote mode", cliVals.CGroupsMode)
}
// Docker-compatibility: the "-h" flag for run/create is reserved for
// the hostname (see https://github.com/containers/podman/issues/1367).
- return nil
+ return vals, nil
}
-func pullImage(imageName string) (string, error) {
- pullPolicy, err := config.ParsePullPolicy(cliVals.Pull)
+func PullImage(imageName string, cliVals entities.ContainerCreateOptions) (string, error) {
+ pullPolicy, err := config.ValidatePullPolicy(cliVals.Pull)
if err != nil {
return "", err
}
@@ -316,11 +324,14 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
return nil, errors.Errorf("new pod name must be at least one character")
}
- userns, err := specgen.ParseUserNamespace(cliVals.UserNS)
- if err != nil {
- return nil, err
+ var err error
+ uns := specgen.Namespace{NSMode: specgen.Default}
+ if cliVals.UserNS != "" {
+ uns, err = specgen.ParseNamespace(cliVals.UserNS)
+ if err != nil {
+ return nil, err
+ }
}
-
createOptions := entities.PodCreateOptions{
Name: podName,
Infra: true,
@@ -330,12 +341,36 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
Cpus: cliVals.CPUS,
CpusetCpus: cliVals.CPUSetCPUs,
Pid: cliVals.PID,
- Userns: userns,
+ Userns: uns,
}
// Unset config values we passed to the pod to prevent them being used twice for the container and pod.
s.ContainerBasicConfig.Hostname = ""
s.ContainerNetworkConfig = specgen.ContainerNetworkConfig{}
s.Pod = podName
- return registry.ContainerEngine().PodCreate(context.Background(), createOptions)
+ podSpec := entities.PodSpec{}
+ podGen := specgen.NewPodSpecGenerator()
+ podSpec.PodSpecGen = *podGen
+ podGen, err = entities.ToPodSpecGen(*&podSpec.PodSpecGen, &createOptions)
+ if err != nil {
+ return nil, err
+ }
+
+ infraOpts := entities.ContainerCreateOptions{ImageVolume: "bind", Net: netOpts, Quiet: true}
+ rawImageName := config.DefaultInfraImage
+ name, err := PullImage(rawImageName, infraOpts)
+ if err != nil {
+ fmt.Println(err)
+ }
+ imageName := name
+ podGen.InfraImage = imageName
+ podGen.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
+ podGen.InfraContainerSpec.RawImageName = rawImageName
+ podGen.InfraContainerSpec.NetworkOptions = podGen.NetworkOptions
+ err = specgenutil.FillOutSpecGen(podGen.InfraContainerSpec, &infraOpts, []string{})
+ if err != nil {
+ return nil, err
+ }
+ podSpec.PodSpecGen = *podGen
+ return registry.ContainerEngine().PodCreate(context.Background(), podSpec)
}
diff --git a/cmd/podman/containers/logs.go b/cmd/podman/containers/logs.go
index 00a8d4b52..1548c6c24 100644
--- a/cmd/podman/containers/logs.go
+++ b/cmd/podman/containers/logs.go
@@ -120,7 +120,7 @@ func logsFlags(cmd *cobra.Command) {
func logs(_ *cobra.Command, args []string) error {
if logsOptions.SinceRaw != "" {
// parse time, error out if something is wrong
- since, err := util.ParseInputTime(logsOptions.SinceRaw)
+ since, err := util.ParseInputTime(logsOptions.SinceRaw, true)
if err != nil {
return errors.Wrapf(err, "error parsing --since %q", logsOptions.SinceRaw)
}
@@ -128,7 +128,7 @@ func logs(_ *cobra.Command, args []string) error {
}
if logsOptions.UntilRaw != "" {
// parse time, error out if something is wrong
- until, err := util.ParseInputTime(logsOptions.UntilRaw)
+ until, err := util.ParseInputTime(logsOptions.UntilRaw, false)
if err != nil {
return errors.Wrapf(err, "error parsing --until %q", logsOptions.UntilRaw)
}
diff --git a/cmd/podman/containers/prune.go b/cmd/podman/containers/prune.go
index e55bd8a53..e13b9e7f6 100644
--- a/cmd/podman/containers/prune.go
+++ b/cmd/podman/containers/prune.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra"
)
@@ -63,7 +64,7 @@ func prune(cmd *cobra.Command, args []string) error {
}
}
- pruneOptions.Filters, err = common.ParseFilters(filter)
+ pruneOptions.Filters, err = specgenutil.ParseFilters(filter)
if err != nil {
return err
}
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index 3b6f74efa..05214f32c 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/rootless"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -106,7 +107,7 @@ func restore(cmd *cobra.Command, args []string) error {
return err
}
if len(inputPorts) > 0 {
- restoreOptions.PublishPorts, err = common.CreatePortBindings(inputPorts)
+ restoreOptions.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
if err != nil {
return err
}
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index 830d1de7f..d14961829 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -60,7 +61,7 @@ func runFlags(cmd *cobra.Command) {
flags := cmd.Flags()
flags.SetInterspersed(false)
- common.DefineCreateFlags(cmd, &cliVals)
+ common.DefineCreateFlags(cmd, &cliVals, false)
common.DefineNetFlags(cmd)
flags.SetNormalizeFunc(utils.AliasFlags)
@@ -106,10 +107,6 @@ func init() {
func run(cmd *cobra.Command, args []string) error {
var err error
- cliVals.Net, err = common.NetFlagsToNetOptions(cmd, cliVals.Pod == "" && cliVals.PodIDFile == "")
- if err != nil {
- return err
- }
// TODO: Breaking change should be made fatal in next major Release
if cliVals.TTY && cliVals.Interactive && !terminal.IsTerminal(int(os.Stdin.Fd())) {
@@ -122,11 +119,17 @@ func run(cmd *cobra.Command, args []string) error {
}
}
+ flags := cmd.Flags()
+ cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags, cliVals.Pod == "" && cliVals.PodIDFile == "")
+ if err != nil {
+ return err
+ }
runOpts.CIDFile = cliVals.CIDFile
runOpts.Rm = cliVals.Rm
- if err := createInit(cmd); err != nil {
+ if cliVals, err = CreateInit(cmd, cliVals, false); err != nil {
return err
}
+
for fd := 3; fd < int(3+runOpts.PreserveFDs); fd++ {
if !rootless.IsFdInherited(fd) {
return errors.Errorf("file descriptor %d is not available - the preserve-fds option requires that file descriptors must be passed", fd)
@@ -137,7 +140,7 @@ func run(cmd *cobra.Command, args []string) error {
rawImageName := ""
if !cliVals.RootFS {
rawImageName = args[0]
- name, err := pullImage(args[0])
+ name, err := PullImage(args[0], cliVals)
if err != nil {
return err
}
@@ -178,7 +181,7 @@ func run(cmd *cobra.Command, args []string) error {
}
cliVals.PreserveFDs = runOpts.PreserveFDs
s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
- if err := common.FillOutSpecGen(s, &cliVals, args); err != nil {
+ if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
}
s.RawImageName = rawImageName
diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go
index 5461f1f6a..2ab33c26b 100644
--- a/cmd/podman/generate/systemd.go
+++ b/cmd/podman/generate/systemd.go
@@ -12,15 +12,22 @@ import (
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/pkg/domain/entities"
+ systemDefine "github.com/containers/podman/v3/pkg/systemd/define"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
+const (
+ restartPolicyFlagName = "restart-policy"
+ timeFlagName = "time"
+)
+
var (
files bool
format string
systemdTimeout uint
+ systemdRestart string
systemdOptions = entities.GenerateSystemdOptions{}
systemdDescription = `Generate systemd units for a pod or container.
The generated units can later be controlled via systemctl(1).`
@@ -47,10 +54,9 @@ func init() {
flags.BoolVarP(&systemdOptions.Name, "name", "n", false, "Use container/pod names instead of IDs")
flags.BoolVarP(&files, "files", "f", false, "Generate .service files instead of printing to stdout")
- timeFlagName := "time"
flags.UintVarP(&systemdTimeout, timeFlagName, "t", containerConfig.Engine.StopTimeout, "Stop timeout override")
_ = systemdCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone)
- flags.BoolVarP(&systemdOptions.New, "new", "", false, "Create a new container instead of starting an existing one")
+ flags.BoolVarP(&systemdOptions.New, "new", "", false, "Create a new container or pod instead of starting an existing one")
flags.BoolVarP(&systemdOptions.NoHeader, "no-header", "", false, "Skip header generation")
containerPrefixFlagName := "container-prefix"
@@ -65,8 +71,7 @@ func init() {
flags.StringVar(&systemdOptions.Separator, separatorFlagName, "-", "Systemd unit name separator between name/id and prefix")
_ = systemdCmd.RegisterFlagCompletionFunc(separatorFlagName, completion.AutocompleteNone)
- restartPolicyFlagName := "restart-policy"
- flags.StringVar(&systemdOptions.RestartPolicy, restartPolicyFlagName, "on-failure", "Systemd restart-policy")
+ flags.StringVar(&systemdRestart, restartPolicyFlagName, systemDefine.DefaultRestartPolicy, "Systemd restart-policy")
_ = systemdCmd.RegisterFlagCompletionFunc(restartPolicyFlagName, common.AutocompleteSystemdRestartOptions)
formatFlagName := "format"
@@ -77,9 +82,12 @@ func init() {
}
func systemd(cmd *cobra.Command, args []string) error {
- if cmd.Flags().Changed("time") {
+ if cmd.Flags().Changed(timeFlagName) {
systemdOptions.StopTimeout = &systemdTimeout
}
+ if cmd.Flags().Changed(restartPolicyFlagName) {
+ systemdOptions.RestartPolicy = &systemdRestart
+ }
if registry.IsRemote() {
logrus.Warnln("The generated units should be placed on your remote system")
diff --git a/cmd/podman/images/import.go b/cmd/podman/images/import.go
index bc80417cc..d4bc0f610 100644
--- a/cmd/podman/images/import.go
+++ b/cmd/podman/images/import.go
@@ -30,7 +30,7 @@ var (
RunE: importCon,
Args: cobra.RangeArgs(1, 2),
ValidArgsFunction: common.AutocompleteDefaultOneArg,
- Example: `podman import http://example.com/ctr.tar url-image
+ Example: `podman import https://example.com/ctr.tar url-image
cat ctr.tar | podman -q import --message "importing the ctr.tar tarball" - image-imported
cat ctr.tar | podman import -`,
}
@@ -42,7 +42,7 @@ var (
RunE: importCommand.RunE,
Args: importCommand.Args,
ValidArgsFunction: importCommand.ValidArgsFunction,
- Example: `podman image import http://example.com/ctr.tar url-image
+ Example: `podman image import https://example.com/ctr.tar url-image
cat ctr.tar | podman -q image import --message "importing the ctr.tar tarball" - image-imported
cat ctr.tar | podman image import -`,
}
diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go
index 6ecf4f2aa..8a484495a 100644
--- a/cmd/podman/images/prune.go
+++ b/cmd/podman/images/prune.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra"
)
@@ -59,7 +60,7 @@ func prune(cmd *cobra.Command, args []string) error {
return nil
}
}
- filterMap, err := common.ParseFilters(filter)
+ filterMap, err := specgenutil.ParseFilters(filter)
if err != nil {
return err
}
diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go
index f4133dbde..ec44a707d 100644
--- a/cmd/podman/machine/init.go
+++ b/cmd/podman/machine/init.go
@@ -1,4 +1,4 @@
-// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
+// +build amd64,!windows arm64,!windows
package machine
@@ -34,12 +34,13 @@ func init() {
Parent: machineCmd,
})
flags := initCmd.Flags()
+ cfg := registry.PodmanConfig()
cpusFlagName := "cpus"
flags.Uint64Var(
&initOpts.CPUS,
cpusFlagName, 1,
- "Number of CPUs. The default is 1.",
+ "Number of CPUs",
)
_ = initCmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone)
@@ -56,12 +57,12 @@ func init() {
flags.Uint64VarP(
&initOpts.Memory,
memoryFlagName, "m", 2048,
- "Memory (in MB)",
+ "Memory in MB",
)
_ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)
ImagePathFlagName := "image-path"
- flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, "", "Path to qcow image")
+ flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Engine.MachineImage, "Path to qcow image")
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
IgnitionPathFlagName := "ignition-path"
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index 134a081ab..d4360bb9b 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -1,4 +1,4 @@
-// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
+// +build amd64,!windows arm64,!windows
package machine
diff --git a/cmd/podman/machine/machine.go b/cmd/podman/machine/machine.go
index b059afc38..8ff9055f0 100644
--- a/cmd/podman/machine/machine.go
+++ b/cmd/podman/machine/machine.go
@@ -1,4 +1,4 @@
-// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
+// +build amd64,!windows arm64,!windows
package machine
diff --git a/cmd/podman/machine/rm.go b/cmd/podman/machine/rm.go
index 02e3dfeb8..c17399c78 100644
--- a/cmd/podman/machine/rm.go
+++ b/cmd/podman/machine/rm.go
@@ -1,4 +1,4 @@
-// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
+// +build amd64,!windows arm64,!windows
package machine
diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go
index b52a48faf..85101a641 100644
--- a/cmd/podman/machine/ssh.go
+++ b/cmd/podman/machine/ssh.go
@@ -1,4 +1,4 @@
-// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
+// +build amd64,!windows arm64,!windows
package machine
diff --git a/cmd/podman/machine/start.go b/cmd/podman/machine/start.go
index f8f0eed09..a5ba74599 100644
--- a/cmd/podman/machine/start.go
+++ b/cmd/podman/machine/start.go
@@ -1,4 +1,4 @@
-// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
+// +build amd64,!windows arm64,!windows
package machine
diff --git a/cmd/podman/machine/stop.go b/cmd/podman/machine/stop.go
index 2d5aa7b95..76ba85601 100644
--- a/cmd/podman/machine/stop.go
+++ b/cmd/podman/machine/stop.go
@@ -1,4 +1,4 @@
-// +build amd64,linux arm64,linux amd64,darwin arm64,darwin
+// +build amd64,!windows arm64,!windows
package machine
diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go
index 1f3b321ba..b5ddd215f 100644
--- a/cmd/podman/networks/create.go
+++ b/cmd/podman/networks/create.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -56,7 +57,8 @@ func networkCreateFlags(cmd *cobra.Command) {
macvlanFlagName := "macvlan"
flags.StringVar(&networkCreateOptions.MacVLAN, macvlanFlagName, "", "create a Macvlan connection based on this device")
- _ = cmd.RegisterFlagCompletionFunc(macvlanFlagName, completion.AutocompleteNone)
+ // This option is deprecated
+ flags.MarkHidden(macvlanFlagName)
labelFlagName := "label"
flags.StringArrayVar(&labels, labelFlagName, nil, "set metadata on a network")
@@ -100,6 +102,11 @@ func networkCreate(cmd *cobra.Command, args []string) error {
if err != nil {
return errors.Wrapf(err, "unable to process options")
}
+
+ if networkCreateOptions.MacVLAN != "" {
+ logrus.Warn("The --macvlan option is deprecated, use `--driver macvlan --opt parent=<device>` instead")
+ }
+
response, err := registry.ContainerEngine().NetworkCreate(registry.Context(), name, networkCreateOptions)
if err != nil {
return err
diff --git a/cmd/podman/networks/prune.go b/cmd/podman/networks/prune.go
index e6b779ded..311d098cd 100644
--- a/cmd/podman/networks/prune.go
+++ b/cmd/podman/networks/prune.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@@ -67,7 +68,7 @@ func networkPrune(cmd *cobra.Command, _ []string) error {
return nil
}
}
- networkPruneOptions.Filters, err = common.ParseFilters(filter)
+ networkPruneOptions.Filters, err = specgenutil.ParseFilters(filter)
if err != nil {
return err
}
diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go
index 2eebd9f86..9308371d2 100644
--- a/cmd/podman/play/kube.go
+++ b/cmd/podman/play/kube.go
@@ -86,6 +86,9 @@ func init() {
flags.StringVar(&kubeOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
_ = kubeCmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault)
+ downFlagName := "down"
+ flags.BoolVar(&kubeOptions.Down, downFlagName, false, "Stop pods defined in the YAML file")
+
if !registry.IsRemote() {
certDirFlagName := "cert-dir"
flags.StringVar(&kubeOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys")
@@ -144,12 +147,55 @@ func kube(cmd *cobra.Command, args []string) error {
}
kubeOptions.StaticMACs = append(kubeOptions.StaticMACs, m)
}
+ if kubeOptions.Down {
+ return teardown(yamlfile)
+ }
+ return playkube(yamlfile)
+}
- report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), yamlfile, kubeOptions.PlayKubeOptions)
+func teardown(yamlfile string) error {
+ var (
+ podStopErrors utils.OutputErrors
+ podRmErrors utils.OutputErrors
+ )
+ options := new(entities.PlayKubeDownOptions)
+ reports, err := registry.ContainerEngine().PlayKubeDown(registry.GetContext(), yamlfile, *options)
if err != nil {
return err
}
+ // Output stopped pods
+ fmt.Println("Pods stopped:")
+ for _, stopped := range reports.StopReport {
+ if len(stopped.Errs) == 0 {
+ fmt.Println(stopped.Id)
+ } else {
+ podStopErrors = append(podStopErrors, stopped.Errs...)
+ }
+ }
+ // Dump any stop errors
+ lastStopError := podStopErrors.PrintErrors()
+ if lastStopError != nil {
+ fmt.Fprintf(os.Stderr, "Error: %s\n", lastStopError)
+ }
+
+ // Output rm'd pods
+ fmt.Println("Pods removed:")
+ for _, removed := range reports.RmReport {
+ if removed.Err == nil {
+ fmt.Println(removed.Id)
+ } else {
+ podRmErrors = append(podRmErrors, removed.Err)
+ }
+ }
+ return podRmErrors.PrintErrors()
+}
+
+func playkube(yamlfile string) error {
+ report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), yamlfile, kubeOptions.PlayKubeOptions)
+ if err != nil {
+ return err
+ }
// Print volumes report
for i, volume := range report.Volumes {
if i == 0 {
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index bf5b9e350..b3f84dcd8 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -11,14 +11,17 @@ import (
"strings"
"github.com/containers/common/pkg/completion"
+ "github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/sysinfo"
"github.com/containers/podman/v3/cmd/podman/common"
+ "github.com/containers/podman/v3/cmd/podman/containers"
"github.com/containers/podman/v3/cmd/podman/parse"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/specgen"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/docker/docker/pkg/parsers"
"github.com/pkg/errors"
@@ -44,11 +47,11 @@ var (
var (
createOptions entities.PodCreateOptions
+ infraOptions entities.ContainerCreateOptions
labels, labelFile []string
podIDFile string
replace bool
share string
- userns string
)
func init() {
@@ -58,62 +61,19 @@ func init() {
})
flags := createCommand.Flags()
flags.SetInterspersed(false)
-
+ infraOptions.IsInfra = true
+ common.DefineCreateFlags(createCommand, &infraOptions, true)
common.DefineNetFlags(createCommand)
- cpusetflagName := "cpuset-cpus"
- flags.StringVar(&createOptions.CpusetCpus, cpusetflagName, "", "CPUs in which to allow execution")
- _ = createCommand.RegisterFlagCompletionFunc(cpusetflagName, completion.AutocompleteDefault)
-
- cpusflagName := "cpus"
- flags.Float64Var(&createOptions.Cpus, cpusflagName, 0.000, "set amount of CPUs for the pod")
- _ = createCommand.RegisterFlagCompletionFunc(cpusflagName, completion.AutocompleteDefault)
-
- cgroupParentflagName := "cgroup-parent"
- flags.StringVar(&createOptions.CGroupParent, cgroupParentflagName, "", "Set parent cgroup for the pod")
- _ = createCommand.RegisterFlagCompletionFunc(cgroupParentflagName, completion.AutocompleteDefault)
-
- usernsFlagName := "userns"
- flags.StringVar(&userns, usernsFlagName, os.Getenv("PODMAN_USERNS"), "User namespace to use")
- _ = createCommand.RegisterFlagCompletionFunc(usernsFlagName, common.AutocompleteUserNamespace)
-
flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
- infraConmonPidfileFlagName := "infra-conmon-pidfile"
- flags.StringVar(&createOptions.InfraConmonPidFile, infraConmonPidfileFlagName, "", "Path to the file that will receive the POD of the infra container's conmon")
- _ = createCommand.RegisterFlagCompletionFunc(infraConmonPidfileFlagName, completion.AutocompleteDefault)
-
- infraImageFlagName := "infra-image"
- flags.String(infraImageFlagName, containerConfig.Engine.InfraImage, "The image of the infra container to associate with the pod")
- _ = createCommand.RegisterFlagCompletionFunc(infraImageFlagName, common.AutocompleteImages)
-
- infraCommandFlagName := "infra-command"
- flags.String(infraCommandFlagName, containerConfig.Engine.InfraCommand, "The command to run on the infra container when the pod is started")
- _ = createCommand.RegisterFlagCompletionFunc(infraCommandFlagName, completion.AutocompleteNone)
-
- infraNameFlagName := "infra-name"
- flags.StringVarP(&createOptions.InfraName, infraNameFlagName, "", "", "The name used as infra container name")
- _ = createCommand.RegisterFlagCompletionFunc(infraNameFlagName, completion.AutocompleteNone)
-
- labelFileFlagName := "label-file"
- flags.StringSliceVar(&labelFile, labelFileFlagName, []string{}, "Read in a line delimited file of labels")
- _ = createCommand.RegisterFlagCompletionFunc(labelFileFlagName, completion.AutocompleteDefault)
-
- labelFlagName := "label"
- flags.StringSliceVarP(&labels, labelFlagName, "l", []string{}, "Set metadata on pod (default [])")
- _ = createCommand.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone)
-
nameFlagName := "name"
flags.StringVarP(&createOptions.Name, nameFlagName, "n", "", "Assign a name to the pod")
_ = createCommand.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)
- hostnameFlagName := "hostname"
- flags.StringVarP(&createOptions.Hostname, hostnameFlagName, "", "", "Set a hostname to the pod")
- _ = createCommand.RegisterFlagCompletionFunc(hostnameFlagName, completion.AutocompleteNone)
-
- pidFlagName := "pid"
- flags.StringVar(&createOptions.Pid, pidFlagName, "", "PID namespace to use")
- _ = createCommand.RegisterFlagCompletionFunc(pidFlagName, common.AutocompleteNamespace)
+ infraImageFlagName := "infra-image"
+ flags.String(infraImageFlagName, containerConfig.Engine.InfraImage, "The image of the infra container to associate with the pod")
+ _ = createCommand.RegisterFlagCompletionFunc(infraImageFlagName, common.AutocompleteImages)
podIDFileFlagName := "pod-id-file"
flags.StringVar(&podIDFile, podIDFileFlagName, "", "Write the pod ID to the file")
@@ -137,25 +97,30 @@ func aliasNetworkFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName {
func create(cmd *cobra.Command, args []string) error {
var (
- err error
- podIDFD *os.File
+ err error
+ podIDFD *os.File
+ imageName string
+ rawImageName string
)
+ labelFile = infraOptions.LabelFile
+ labels = infraOptions.Label
createOptions.Labels, err = parse.GetAllLabels(labelFile, labels)
if err != nil {
return errors.Wrapf(err, "unable to process labels")
}
+ imageName = config.DefaultInfraImage
+ img := imageName
if !createOptions.Infra {
- logrus.Debugf("Not creating an infra container")
- if cmd.Flag("infra-conmon-pidfile").Changed {
- return errors.New("cannot set infra-conmon-pid without an infra container")
+ if cmd.Flag("no-hosts").Changed {
+ return fmt.Errorf("cannot specify no-hosts without an infra container")
}
- if cmd.Flag("infra-command").Changed {
- return errors.New("cannot set infra-command without an infra container")
- }
- if cmd.Flag("infra-image").Changed {
- return errors.New("cannot set infra-image without an infra container")
+ flags := cmd.Flags()
+ createOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false)
+ if err != nil {
+ return err
}
+ logrus.Debugf("Not creating an infra container")
createOptions.InfraImage = ""
if createOptions.InfraName != "" {
return errors.New("cannot set infra-name without an infra container")
@@ -166,28 +131,43 @@ func create(cmd *cobra.Command, args []string) error {
}
createOptions.Share = nil
} else {
+ // reassign certain optios for lbpod api, these need to be populated in spec
+ createOptions.InfraConmonPidFile = infraOptions.ConmonPIDFile
+ createOptions.InfraName = infraOptions.Name
+ createOptions.Hostname = infraOptions.Hostname
+ createOptions.Cpus = infraOptions.CPUS
+ createOptions.CpusetCpus = infraOptions.CPUSetCPUs
+ createOptions.Pid = infraOptions.PID
+ flags := cmd.Flags()
+ infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false)
+ if err != nil {
+ return err
+ }
+ infraOptions, err = containers.CreateInit(cmd, infraOptions, true)
+ if err != nil {
+ return err
+ }
+ createOptions.Net = infraOptions.Net
createOptions.Share = strings.Split(share, ",")
if cmd.Flag("infra-command").Changed {
// Only send content to server side if user changed defaults
- createOptions.InfraCommand, err = cmd.Flags().GetString("infra-command")
+ cmdIn, err := cmd.Flags().GetString("infra-command")
+ infraOptions.Entrypoint = &cmdIn
+ createOptions.InfraCommand = cmdIn
if err != nil {
return err
}
}
if cmd.Flag("infra-image").Changed {
// Only send content to server side if user changed defaults
- createOptions.InfraImage, err = cmd.Flags().GetString("infra-image")
+ img, err = cmd.Flags().GetString("infra-image")
+ imageName = img
if err != nil {
return err
}
}
}
- createOptions.Userns, err = specgen.ParseUserNamespace(userns)
- if err != nil {
- return err
- }
-
if cmd.Flag("pod-id-file").Changed {
podIDFD, err = util.OpenExclusiveFile(podIDFile)
if err != nil && os.IsExist(err) {
@@ -200,13 +180,6 @@ func create(cmd *cobra.Command, args []string) error {
defer errorhandling.SyncQuiet(podIDFD)
}
- createOptions.Pid = cmd.Flag("pid").Value.String()
-
- createOptions.Net, err = common.NetFlagsToNetOptions(cmd, createOptions.Infra)
- if err != nil {
- return err
- }
-
if len(createOptions.Net.PublishPorts) > 0 {
if !createOptions.Infra {
return errors.Errorf("you must have an infra container to publish port bindings to the host")
@@ -261,10 +234,44 @@ func create(cmd *cobra.Command, args []string) error {
copy = "" + strconv.Itoa(core)
}
}
- response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
+ podSpec := specgen.NewPodSpecGenerator()
+ podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions)
if err != nil {
return err
}
+ if createOptions.Infra {
+ rawImageName = img
+ if !infraOptions.RootFS {
+ curr := infraOptions.Quiet
+ infraOptions.Quiet = true
+ name, err := containers.PullImage(imageName, infraOptions)
+ if err != nil {
+ fmt.Println(err)
+ }
+ imageName = name
+ infraOptions.Quiet = curr
+ }
+ podSpec.InfraImage = imageName
+ if infraOptions.Entrypoint != nil {
+ createOptions.InfraCommand = *infraOptions.Entrypoint
+ }
+ infraOptions.CPUS = createOptions.Cpus
+ infraOptions.CPUSetCPUs = createOptions.CpusetCpus
+ infraOptions.PID = createOptions.Pid
+ podSpec.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
+ podSpec.InfraContainerSpec.RawImageName = rawImageName
+ podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions
+ err = specgenutil.FillOutSpecGen(podSpec.InfraContainerSpec, &infraOptions, []string{})
+ if err != nil {
+ return err
+ }
+ }
+ PodSpec := entities.PodSpec{PodSpecGen: *podSpec}
+ response, err := registry.ContainerEngine().PodCreate(context.Background(), PodSpec)
+ if err != nil {
+ return err
+ }
+
if len(podIDFile) > 0 {
if err = ioutil.WriteFile(podIDFile, []byte(response.Id), 0644); err != nil {
return errors.Wrapf(err, "failed to write pod ID to file")
diff --git a/cmd/podman/pods/logs.go b/cmd/podman/pods/logs.go
new file mode 100644
index 000000000..fe5205669
--- /dev/null
+++ b/cmd/podman/pods/logs.go
@@ -0,0 +1,140 @@
+package pods
+
+import (
+ "os"
+
+ "github.com/containers/common/pkg/completion"
+ "github.com/containers/podman/v3/cmd/podman/common"
+ "github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/cmd/podman/validate"
+ "github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/util"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+// logsOptionsWrapper wraps entities.LogsOptions and prevents leaking
+// CLI-only fields into the API types.
+type logsOptionsWrapper struct {
+ entities.PodLogsOptions
+
+ SinceRaw string
+
+ UntilRaw string
+}
+
+var (
+ logsPodOptions logsOptionsWrapper
+ logsPodDescription = `Displays logs for pod with one or more containers.`
+ logsPodCommand = &cobra.Command{
+ Use: "logs [options] POD",
+ Short: "Fetch logs for pod with one or more containers",
+ Long: logsPodDescription,
+ // We dont want users to invoke latest and pod togather
+ Args: func(cmd *cobra.Command, args []string) error {
+ switch {
+ case registry.IsRemote() && logsPodOptions.Latest:
+ return errors.New(cmd.Name() + " does not support 'latest' when run remotely")
+ case len(args) > 1:
+ return errors.New("requires exactly 1 arg")
+ case logsPodOptions.Latest && len(args) > 0:
+ return errors.New("--latest and pods cannot be used together")
+ case !logsPodOptions.Latest && len(args) < 1:
+ return errors.New("specify at least one pod name or ID to log")
+ }
+ return nil
+ },
+ RunE: logs,
+ ValidArgsFunction: common.AutocompletePods,
+ Example: `podman pod logs podID
+ podman pod logs -c ctrname podName
+ podman pod logs --tail 2 mywebserver
+ podman pod logs --follow=true --since 10m podID
+ podman pod logs mywebserver`,
+ }
+
+ containerLogsCommand = &cobra.Command{
+ Use: logsPodCommand.Use,
+ Short: logsPodCommand.Short,
+ Long: logsPodCommand.Long,
+ Args: logsPodCommand.Args,
+ RunE: logsPodCommand.RunE,
+ ValidArgsFunction: logsPodCommand.ValidArgsFunction,
+ Example: `podman pod logs podId
+ podman pod logs -c ctrname podName
+ podman pod logs --tail 2 mywebserver
+ podman pod logs --follow=true --since 10m podID`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: logsPodCommand,
+ })
+ logsFlags(logsPodCommand)
+ validate.AddLatestFlag(logsPodCommand, &logsPodOptions.Latest)
+
+ // container logs
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: containerLogsCommand,
+ Parent: podCmd,
+ })
+ logsFlags(containerLogsCommand)
+ validate.AddLatestFlag(containerLogsCommand, &logsPodOptions.Latest)
+}
+
+func logsFlags(cmd *cobra.Command) {
+ flags := cmd.Flags()
+
+ flags.BoolVar(&logsPodOptions.Details, "details", false, "Show extra details provided to the logs")
+ flags.BoolVarP(&logsPodOptions.Follow, "follow", "f", false, "Follow log output.")
+
+ containerNameFlag := "container"
+ flags.StringVarP(&logsPodOptions.ContainerName, containerNameFlag, "c", "", "Filter logs by container name or id which belongs to pod")
+ _ = cmd.RegisterFlagCompletionFunc(containerNameFlag, common.AutocompleteContainers)
+
+ sinceFlagName := "since"
+ flags.StringVar(&logsPodOptions.SinceRaw, sinceFlagName, "", "Show logs since TIMESTAMP")
+ _ = cmd.RegisterFlagCompletionFunc(sinceFlagName, completion.AutocompleteNone)
+
+ untilFlagName := "until"
+ flags.StringVar(&logsPodOptions.UntilRaw, untilFlagName, "", "Show logs until TIMESTAMP")
+ _ = cmd.RegisterFlagCompletionFunc(untilFlagName, completion.AutocompleteNone)
+
+ tailFlagName := "tail"
+ flags.Int64Var(&logsPodOptions.Tail, tailFlagName, -1, "Output the specified number of LINES at the end of the logs.")
+ _ = cmd.RegisterFlagCompletionFunc(tailFlagName, completion.AutocompleteNone)
+
+ flags.BoolVarP(&logsPodOptions.Timestamps, "timestamps", "t", false, "Output the timestamps in the log")
+ flags.SetInterspersed(false)
+ _ = flags.MarkHidden("details")
+}
+
+func logs(_ *cobra.Command, args []string) error {
+ if logsPodOptions.SinceRaw != "" {
+ // parse time, error out if something is wrong
+ since, err := util.ParseInputTime(logsPodOptions.SinceRaw, true)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing --since %q", logsPodOptions.SinceRaw)
+ }
+ logsPodOptions.Since = since
+ }
+ if logsPodOptions.UntilRaw != "" {
+ // parse time, error out if something is wrong
+ until, err := util.ParseInputTime(logsPodOptions.UntilRaw, false)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing --until %q", logsPodOptions.UntilRaw)
+ }
+ logsPodOptions.Until = until
+ }
+
+ // Remote can only process one container at a time
+ if registry.IsRemote() && logsPodOptions.ContainerName == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "-c or --container cannot be empty")
+ }
+
+ logsPodOptions.StdoutWriter = os.Stdout
+ logsPodOptions.StderrWriter = os.Stderr
+ return registry.ContainerEngine().PodLogs(registry.GetContext(), args[0], logsPodOptions.PodLogsOptions)
+}
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index 14e3e2ea9..60aadf224 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -57,7 +57,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&psInput.Format, formatFlagName, "", "Pretty-print pods to JSON or using a Go template")
- _ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPodReporter{}))
+ _ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPodReporter{ListPodsReport: &entities.ListPodsReport{}}))
flags.Bool("noheading", false, "Do not print headers")
flags.BoolVar(&psInput.Namespace, "namespace", false, "Display namespace information of the pod")
diff --git a/cmd/podman/pods/rm.go b/cmd/podman/pods/rm.go
index fbaf64c1f..dc4c7eb83 100644
--- a/cmd/podman/pods/rm.go
+++ b/cmd/podman/pods/rm.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -66,7 +67,7 @@ func init() {
}
func rm(_ *cobra.Command, args []string) error {
- ids, err := common.ReadPodIDFiles(rmOptions.PodIDFiles)
+ ids, err := specgenutil.ReadPodIDFiles(rmOptions.PodIDFiles)
if err != nil {
return err
}
diff --git a/cmd/podman/pods/start.go b/cmd/podman/pods/start.go
index e39891a9b..e5f9eaa84 100644
--- a/cmd/podman/pods/start.go
+++ b/cmd/podman/pods/start.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra"
)
@@ -64,7 +65,7 @@ func start(cmd *cobra.Command, args []string) error {
errs utils.OutputErrors
)
- ids, err := common.ReadPodIDFiles(startOptions.PodIDFiles)
+ ids, err := specgenutil.ReadPodIDFiles(startOptions.PodIDFiles)
if err != nil {
return err
}
diff --git a/cmd/podman/pods/stop.go b/cmd/podman/pods/stop.go
index bcc054b8e..41325649f 100644
--- a/cmd/podman/pods/stop.go
+++ b/cmd/podman/pods/stop.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra"
)
@@ -78,7 +79,7 @@ func stop(cmd *cobra.Command, args []string) error {
stopOptions.Timeout = int(stopOptions.TimeoutCLI)
}
- ids, err := common.ReadPodIDFiles(stopOptions.PodIDFiles)
+ ids, err := specgenutil.ReadPodIDFiles(stopOptions.PodIDFiles)
if err != nil {
return err
}
diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go
index e64990c6f..f136de4ab 100644
--- a/cmd/podman/secrets/list.go
+++ b/cmd/podman/secrets/list.go
@@ -48,7 +48,7 @@ func init() {
}
func ls(cmd *cobra.Command, args []string) error {
- responses, err := registry.ContainerEngine().SecretList(context.Background())
+ responses, err := registry.ContainerEngine().SecretList(context.Background(), entities.SecretListRequest{})
if err != nil {
return err
}
diff --git a/cmd/podman/volumes/import.go b/cmd/podman/volumes/import.go
new file mode 100644
index 000000000..441bd0fe4
--- /dev/null
+++ b/cmd/podman/volumes/import.go
@@ -0,0 +1,97 @@
+package volumes
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/podman/v3/cmd/podman/common"
+ "github.com/containers/podman/v3/cmd/podman/inspect"
+ "github.com/containers/podman/v3/cmd/podman/parse"
+ "github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/utils"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ importDescription = `Imports contents into a podman volume from specified tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz).`
+ importCommand = &cobra.Command{
+ Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
+ Use: "import VOLUME [SOURCE]",
+ Short: "Import a tarball contents into a podman volume",
+ Long: importDescription,
+ RunE: importVol,
+ Args: cobra.ExactArgs(2),
+ ValidArgsFunction: common.AutocompleteVolumes,
+ Example: `podman volume import my_vol /home/user/import.tar
+ cat ctr.tar | podman import volume my_vol -`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: importCommand,
+ Parent: volumeCmd,
+ })
+}
+
+func importVol(cmd *cobra.Command, args []string) error {
+ var inspectOpts entities.InspectOptions
+ var tarFile *os.File
+ containerEngine := registry.ContainerEngine()
+ ctx := registry.Context()
+ // create a slice of volumes since inspect expects slice as arg
+ volumes := []string{args[0]}
+ tarPath := args[1]
+
+ if tarPath != "-" {
+ err := parse.ValidateFileName(tarPath)
+ if err != nil {
+ return err
+ }
+
+ // open tar file
+ tarFile, err = os.Open(tarPath)
+ if err != nil {
+ return err
+ }
+ } else {
+ tarFile = os.Stdin
+ }
+
+ inspectOpts.Type = inspect.VolumeType
+ volumeData, _, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts)
+ if err != nil {
+ return err
+ }
+ if len(volumeData) < 1 {
+ return errors.New("no volume data found")
+ }
+ mountPoint := volumeData[0].VolumeConfigResponse.Mountpoint
+ driver := volumeData[0].VolumeConfigResponse.Driver
+ volumeOptions := volumeData[0].VolumeConfigResponse.Options
+ volumeMountStatus, err := containerEngine.VolumeMounted(ctx, args[0])
+ if err != nil {
+ return err
+ }
+ if mountPoint == "" {
+ return errors.New("volume is not mounted anywhere on host")
+ }
+ // Check if volume is using external plugin and export only if volume is mounted
+ if driver != "" && driver != "local" {
+ if !volumeMountStatus.Value {
+ return fmt.Errorf("volume is using a driver %s and volume is not mounted on %s", driver, mountPoint)
+ }
+ }
+ // Check if volume is using `local` driver and has mount options type other than tmpfs
+ if driver == "local" {
+ if mountOptionType, ok := volumeOptions["type"]; ok {
+ if mountOptionType != "tmpfs" && !volumeMountStatus.Value {
+ return fmt.Errorf("volume is using a driver %s and volume is not mounted on %s", driver, mountPoint)
+ }
+ }
+ }
+ // dont care if volume is mounted or not we are gonna import everything to mountPoint
+ return utils.UntarToFileSystem(mountPoint, tarFile, nil)
+}