summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/auto-update.go2
-rw-r--r--cmd/podman/common/completion.go46
-rw-r--r--cmd/podman/common/completion_test.go14
-rw-r--r--cmd/podman/containers/inspect.go7
-rw-r--r--cmd/podman/containers/ps.go2
-rw-r--r--cmd/podman/containers/stats.go2
-rw-r--r--cmd/podman/images/history.go10
-rw-r--r--cmd/podman/images/inspect.go2
-rw-r--r--cmd/podman/images/list.go2
-rw-r--r--cmd/podman/images/search.go9
-rw-r--r--cmd/podman/machine/inspect.go10
-rw-r--r--cmd/podman/machine/list.go2
-rw-r--r--cmd/podman/machine/set.go60
-rw-r--r--cmd/podman/networks/inspect.go3
-rw-r--r--cmd/podman/networks/list.go2
-rw-r--r--cmd/podman/pods/create.go2
-rw-r--r--cmd/podman/pods/inspect.go3
-rw-r--r--cmd/podman/pods/ps.go2
-rw-r--r--cmd/podman/pods/stats.go2
-rw-r--r--cmd/podman/root.go4
-rw-r--r--cmd/podman/secrets/inspect.go6
-rw-r--r--cmd/podman/secrets/list.go2
-rw-r--r--cmd/podman/system/connection/list.go2
-rw-r--r--cmd/podman/system/events.go2
-rw-r--r--cmd/podman/system/info.go2
-rw-r--r--cmd/podman/system/reset.go5
-rw-r--r--cmd/podman/system/version.go2
-rw-r--r--cmd/podman/volumes/inspect.go2
-rw-r--r--cmd/podman/volumes/list.go3
-rw-r--r--cmd/rootlessport/main.go24
-rw-r--r--cmd/rootlessport/wsl.go37
-rw-r--r--cmd/rootlessport/wsl_test.go89
32 files changed, 292 insertions, 70 deletions
diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go
index f8b9fba08..1dc29530e 100644
--- a/cmd/podman/auto-update.go
+++ b/cmd/podman/auto-update.go
@@ -57,7 +57,7 @@ func init() {
flags.BoolVar(&autoUpdateOptions.Rollback, "rollback", true, "Rollback to previous image if update fails")
flags.StringVar(&autoUpdateOptions.format, "format", "", "Change the output format to JSON or a Go template")
- _ = autoUpdateCommand.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(autoUpdateOutput{}))
+ _ = autoUpdateCommand.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(&autoUpdateOutput{}))
}
func autoUpdate(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index c7d5d6d60..ddf922b2a 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -987,14 +987,12 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
fields := strings.Split(field[len(field)-1], ".")
f := reflect.ValueOf(o)
for i := 1; i < len(fields); i++ {
- if f.Kind() == reflect.Ptr {
- f = f.Elem()
- }
-
- // the only supported type is struct
- if f.Kind() != reflect.Struct {
+ val := getActualStructType(f)
+ if val == nil {
+ // no struct return nothing to complete
return nil, cobra.ShellCompDirectiveNoFileComp
}
+ f = *val
// last field get all names to suggest
if i == len(fields)-1 {
@@ -1012,17 +1010,38 @@ 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{}
+// getActualStructType take the value and check if it is a struct,
+// if it is pointer it will dereference it and when it is nil,
+// it will create a new value from it to get the actual struct
+// returns nil when type is not a struct
+func getActualStructType(f reflect.Value) *reflect.Value {
// follow the pointer first
if f.Kind() == reflect.Ptr {
+ // if the pointer is nil we create a new value from the elements type
+ // this allows us to follow nil pointers and get the actual struct fields
+ if f.IsNil() {
+ f = reflect.New(f.Type().Elem())
+ }
f = f.Elem()
}
// we only support structs
if f.Kind() != reflect.Struct {
return nil
}
+ return &f
+}
+
+// getStructFields reads all struct field names and method names and returns them.
+func getStructFields(f reflect.Value, prefix string) []string {
+ suggestions := []string{}
+
+ val := getActualStructType(f)
+ if val == nil {
+ // no struct return nothing to complete
+ return nil
+ }
+ f = *val
+
// loop over all field names
for j := 0; j < f.NumField(); j++ {
field := f.Type().Field(j)
@@ -1037,13 +1056,12 @@ func getStructFields(f reflect.Value, prefix string) []string {
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)...)
+ suggestions = append(suggestions, getStructFields(f.Field(j), prefix)...)
+ } else if strings.HasPrefix(fname, prefix) {
+ // add field name with suffix
+ suggestions = append(suggestions, fname+suffix)
}
}
diff --git a/cmd/podman/common/completion_test.go b/cmd/podman/common/completion_test.go
index d28ac3928..ae117a173 100644
--- a/cmd/podman/common/completion_test.go
+++ b/cmd/podman/common/completion_test.go
@@ -34,10 +34,9 @@ func TestAutocompleteFormat(t *testing.T) {
Name string
Age int
Car *Car
+ Car2 *Car
*Anonymous
- }{
- Anonymous: &Anonymous{},
- }
+ }{}
testStruct.Car = &Car{}
testStruct.Car.Extras = map[string]string{"test": "1"}
@@ -80,12 +79,12 @@ func TestAutocompleteFormat(t *testing.T) {
{
"fist level struct field name",
"{{.",
- []string{"{{.Name}}", "{{.Age}}", "{{.Car.", "{{.Anonymous.", "{{.Hello}}"},
+ []string{"{{.Name}}", "{{.Age}}", "{{.Car.", "{{.Car2.", "{{.Hello}}"},
},
{
"fist level struct field name",
"{{ .",
- []string{"{{ .Name}}", "{{ .Age}}", "{{ .Car.", "{{ .Anonymous.", "{{ .Hello}}"},
+ []string{"{{ .Name}}", "{{ .Age}}", "{{ .Car.", "{{ .Car2.", "{{ .Hello}}"},
},
{
"fist level struct field name",
@@ -103,6 +102,11 @@ func TestAutocompleteFormat(t *testing.T) {
[]string{"{{ .Car.Brand}}"},
},
{
+ "second level nil struct field name",
+ "{{ .Car2.",
+ []string{"{{ .Car2.Brand}}", "{{ .Car2.Stats.", "{{ .Car2.Extras}}", "{{ .Car2.Color}}", "{{ .Car2.Type}}"},
+ },
+ {
"three level struct field name",
"{{ .Car.Stats.",
[]string{"{{ .Car.Stats.HP}}", "{{ .Car.Stats.Displacement}}"},
diff --git a/cmd/podman/containers/inspect.go b/cmd/podman/containers/inspect.go
index 8c219b67c..03e6411a1 100644
--- a/cmd/podman/containers/inspect.go
+++ b/cmd/podman/containers/inspect.go
@@ -35,12 +35,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectContainerData{
- State: &define.InspectContainerState{},
- NetworkSettings: &define.InspectNetworkSettings{},
- Config: &define.InspectContainerConfig{},
- HostConfig: &define.InspectContainerHostConfig{},
- }))
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&define.InspectContainerData{}))
validate.AddLatestFlag(inspectCmd, &inspectOpts.Latest)
}
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 4adae30c2..a011a8ae6 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -80,7 +80,7 @@ func listFlagSet(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&listOpts.Format, formatFlagName, "", "Pretty-print containers to JSON or using a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.ListContainer{}))
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&psReporter{}))
lastFlagName := "last"
flags.IntVarP(&listOpts.Last, lastFlagName, "n", -1, "Print the n last created containers (all states)")
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index 715f5c081..500671d31 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -67,7 +67,7 @@ func statFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&statsOptions.Format, formatFlagName, "", "Pretty-print container statistics to JSON or using a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.ContainerStats{}))
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&containerStats{}))
flags.BoolVar(&statsOptions.NoReset, "no-reset", false, "Disable resetting the screen between intervals")
flags.BoolVar(&statsOptions.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false")
diff --git a/cmd/podman/images/history.go b/cmd/podman/images/history.go
index c05d3475b..e190941e7 100644
--- a/cmd/podman/images/history.go
+++ b/cmd/podman/images/history.go
@@ -69,7 +69,7 @@ func historyFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&opts.format, formatFlagName, "", "Change the output to JSON or a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.ImageHistoryLayer{}))
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&historyReporter{}))
flags.BoolVarP(&opts.human, "human", "H", true, "Display sizes and dates in human readable format")
flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate the output")
@@ -168,3 +168,11 @@ func (h historyReporter) ID() string {
}
return h.ImageHistoryLayer.ID
}
+
+func (h historyReporter) CreatedAt() string {
+ return time.Unix(h.ImageHistoryLayer.Created.Unix(), 0).UTC().String()
+}
+
+func (h historyReporter) CreatedSince() string {
+ return h.Created()
+}
diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go
index b4a79bc96..22c404b3f 100644
--- a/cmd/podman/images/inspect.go
+++ b/cmd/podman/images/inspect.go
@@ -34,7 +34,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(inspectTypes.ImageData{}))
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&inspectTypes.ImageData{}))
}
func inspectExec(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index 58fb3e919..81011f9b1 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -94,7 +94,7 @@ func imageListFlagSet(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "", "Change the output format to JSON or a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.ImageSummary{}))
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&imageReporter{}))
flags.BoolVar(&listFlag.digests, "digests", false, "Show digests")
flags.BoolVarP(&listFlag.noHeading, "noheading", "n", false, "Do not print column headings")
diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go
index aa11cf254..335ea2b5a 100644
--- a/cmd/podman/images/search.go
+++ b/cmd/podman/images/search.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
"github.com/containers/image/v5/types"
+ "github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/pkg/errors"
@@ -23,6 +24,7 @@ type searchOptionsWrapper struct {
Compatible bool // Docker compat
TLSVerifyCLI bool // Used to convert to an optional bool later
Format string // For go templating
+ NoTrunc bool
}
// listEntryTag is a utility structure used for json serialization.
@@ -86,13 +88,13 @@ func searchFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&searchOptions.Format, formatFlagName, "", "Change the output format to JSON or a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.ImageSearchReport{}))
limitFlagName := "limit"
flags.IntVar(&searchOptions.Limit, limitFlagName, 0, "Limit the number of results")
_ = cmd.RegisterFlagCompletionFunc(limitFlagName, completion.AutocompleteNone)
- flags.Bool("no-trunc", true, "Do not truncate the output. Default: true")
+ flags.BoolVar(&searchOptions.NoTrunc, "no-trunc", false, "Do not truncate the output")
flags.BoolVar(&searchOptions.Compatible, "compatible", false, "List stars, official and automated columns (Docker compatibility)")
authfileFlagName := "authfile"
@@ -139,11 +141,10 @@ func imageSearch(cmd *cobra.Command, args []string) error {
return nil
}
- noTrunc, _ := cmd.Flags().GetBool("no-trunc")
isJSON := report.IsJSON(searchOptions.Format)
for i, element := range searchReport {
d := strings.ReplaceAll(element.Description, "\n", " ")
- if len(d) > 44 && !(noTrunc || isJSON) {
+ if len(d) > 44 && !(searchOptions.NoTrunc || isJSON) {
d = strings.TrimSpace(d[:44]) + "..."
}
searchReport[i].Description = d
diff --git a/cmd/podman/machine/inspect.go b/cmd/podman/machine/inspect.go
index 1884cf94d..21e5074b7 100644
--- a/cmd/podman/machine/inspect.go
+++ b/cmd/podman/machine/inspect.go
@@ -41,7 +41,7 @@ func init() {
flags := inspectCmd.Flags()
formatFlagName := "format"
flags.StringVar(&inspectFlag.format, formatFlagName, "", "Format volume output using JSON or a Go template")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(machine.InspectInfo{}))
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&machine.InspectInfo{}))
}
func inspect(cmd *cobra.Command, args []string) error {
@@ -59,16 +59,12 @@ func inspect(cmd *cobra.Command, args []string) error {
errs = append(errs, err)
continue
}
- state, err := vm.State(false)
+ ii, err := vm.Inspect()
if err != nil {
errs = append(errs, err)
continue
}
- ii := machine.InspectInfo{
- State: state,
- VM: vm,
- }
- vms = append(vms, ii)
+ vms = append(vms, *ii)
}
if len(inspectFlag.format) > 0 {
// need jhonce to work his template magic
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index 587e521a3..c987bf71a 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -69,7 +69,7 @@ func init() {
flags := lsCmd.Flags()
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n", "Format volume output using JSON or a Go template")
- _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(machineReporter{}))
+ _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&machineReporter{}))
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Show only machine names")
}
diff --git a/cmd/podman/machine/set.go b/cmd/podman/machine/set.go
index 4c15f1de1..a994c981b 100644
--- a/cmd/podman/machine/set.go
+++ b/cmd/podman/machine/set.go
@@ -4,6 +4,9 @@
package machine
import (
+ "fmt"
+ "os"
+
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/machine"
@@ -23,9 +26,17 @@ var (
)
var (
- setOpts = machine.SetOptions{}
+ setFlags = SetFlags{}
+ setOpts = machine.SetOptions{}
)
+type SetFlags struct {
+ CPUs uint64
+ DiskSize uint64
+ Memory uint64
+ Rootful bool
+}
+
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: setCmd,
@@ -34,7 +45,32 @@ func init() {
flags := setCmd.Flags()
rootfulFlagName := "rootful"
- flags.BoolVar(&setOpts.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container execution")
+ flags.BoolVar(&setFlags.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container execution")
+
+ cpusFlagName := "cpus"
+ flags.Uint64Var(
+ &setFlags.CPUs,
+ cpusFlagName, 0,
+ "Number of CPUs",
+ )
+ _ = setCmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone)
+
+ diskSizeFlagName := "disk-size"
+ flags.Uint64Var(
+ &setFlags.DiskSize,
+ diskSizeFlagName, 0,
+ "Disk size in GB",
+ )
+
+ _ = setCmd.RegisterFlagCompletionFunc(diskSizeFlagName, completion.AutocompleteNone)
+
+ memoryFlagName := "memory"
+ flags.Uint64VarP(
+ &setFlags.Memory,
+ memoryFlagName, "m", 0,
+ "Memory in MB",
+ )
+ _ = setCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)
}
func setMachine(cmd *cobra.Command, args []string) error {
@@ -53,5 +89,23 @@ func setMachine(cmd *cobra.Command, args []string) error {
return err
}
- return vm.Set(vmName, setOpts)
+ if cmd.Flags().Changed("rootful") {
+ setOpts.Rootful = &setFlags.Rootful
+ }
+ if cmd.Flags().Changed("cpus") {
+ setOpts.CPUs = &setFlags.CPUs
+ }
+ if cmd.Flags().Changed("memory") {
+ setOpts.Memory = &setFlags.Memory
+ }
+ if cmd.Flags().Changed("disk-size") {
+ setOpts.DiskSize = &setFlags.DiskSize
+ }
+
+ setErrs, lasterr := vm.Set(vmName, setOpts)
+ for _, err := range setErrs {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ }
+
+ return lasterr
}
diff --git a/cmd/podman/networks/inspect.go b/cmd/podman/networks/inspect.go
index 3c07e5492..8f39ec395 100644
--- a/cmd/podman/networks/inspect.go
+++ b/cmd/podman/networks/inspect.go
@@ -1,6 +1,7 @@
package network
import (
+ "github.com/containers/common/libnetwork/types"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/inspect"
"github.com/containers/podman/v4/cmd/podman/registry"
@@ -32,7 +33,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "", "Pretty-print network to JSON or using a Go template")
- _ = networkinspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
+ _ = networkinspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&types.Network{}))
}
func networkInspect(_ *cobra.Command, args []string) error {
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go
index f14e0ed0f..5d4be2a81 100644
--- a/cmd/podman/networks/list.go
+++ b/cmd/podman/networks/list.go
@@ -40,7 +40,7 @@ var (
func networkListFlags(flags *pflag.FlagSet) {
formatFlagName := "format"
flags.StringVar(&networkListOptions.Format, formatFlagName, "", "Pretty-print networks to JSON or using a Go template")
- _ = networklistCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPrintReports{}))
+ _ = networklistCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&ListPrintReports{}))
flags.BoolVarP(&networkListOptions.Quiet, "quiet", "q", false, "display only names")
flags.BoolVar(&noTrunc, "no-trunc", false, "Do not truncate the network ID")
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 891ff2e3c..4623ade63 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -214,7 +214,7 @@ func create(cmd *cobra.Command, args []string) error {
ret, err := parsers.ParseUintList(copy)
copy = ""
if err != nil {
- errors.Wrapf(err, "could not parse list")
+ return errors.Wrapf(err, "could not parse list")
}
var vals []int
for ind, val := range ret {
diff --git a/cmd/podman/pods/inspect.go b/cmd/podman/pods/inspect.go
index ae6a5ba88..bb30fe6e6 100644
--- a/cmd/podman/pods/inspect.go
+++ b/cmd/podman/pods/inspect.go
@@ -9,7 +9,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
- "github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -43,7 +42,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOptions.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectPodData{}))
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.PodInspectReport{}))
validate.AddLatestFlag(inspectCmd, &inspectOptions.Latest)
}
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index 4a049541a..1275e65dc 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{ListPodsReport: &entities.ListPodsReport{}}))
+ _ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&ListPodReporter{}))
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/stats.go b/cmd/podman/pods/stats.go
index f7a56d3f3..9833f4cea 100644
--- a/cmd/podman/pods/stats.go
+++ b/cmd/podman/pods/stats.go
@@ -54,7 +54,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&statsOptions.Format, formatFlagName, "", "Pretty-print container statistics to JSON or using a Go template")
- _ = statsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.PodStatsReport{}))
+ _ = statsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.PodStatsReport{}))
flags.BoolVar(&statsOptions.NoReset, "no-reset", false, "Disable resetting the screen when streaming")
flags.BoolVar(&statsOptions.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result")
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 9b1aa778b..2bd4fa723 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -153,7 +153,9 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
*runtime,
)
}
- runtimeFlag.Value.Set(*runtime)
+ if err := runtimeFlag.Value.Set(*runtime); err != nil {
+ return err
+ }
runtimeFlag.Changed = true
logrus.Debugf("Checkpoint was created using '%s'. Restore will use the same runtime", *runtime)
} else if cfg.RuntimePath != *runtime {
diff --git a/cmd/podman/secrets/inspect.go b/cmd/podman/secrets/inspect.go
index 0977434f7..473d5620c 100644
--- a/cmd/podman/secrets/inspect.go
+++ b/cmd/podman/secrets/inspect.go
@@ -36,7 +36,7 @@ func init() {
flags := inspectCmd.Flags()
formatFlagName := "format"
flags.StringVar(&format, formatFlagName, "", "Format volume output using Go template")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.SecretInfoReport{}))
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.SecretInfoReport{}))
}
func inspect(cmd *cobra.Command, args []string) error {
@@ -61,7 +61,9 @@ func inspect(cmd *cobra.Command, args []string) error {
return err
}
defer w.Flush()
- tmpl.Execute(w, inspected)
+ if err := tmpl.Execute(w, inspected); err != nil {
+ return err
+ }
} else {
buf, err := json.MarshalIndent(inspected, "", " ")
if err != nil {
diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go
index 2ef84cd48..558a16ccf 100644
--- a/cmd/podman/secrets/list.go
+++ b/cmd/podman/secrets/list.go
@@ -45,7 +45,7 @@ func init() {
flags := lsCmd.Flags()
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}\t\n", "Format volume output using Go template")
- _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.SecretInfoReport{}))
+ _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.SecretInfoReport{}))
filterFlagName := "filter"
flags.StringSliceVarP(&listFlag.filter, filterFlagName, "f", []string{}, "Filter secret output")
_ = lsCmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteSecretFilters)
diff --git a/cmd/podman/system/connection/list.go b/cmd/podman/system/connection/list.go
index fe37677df..2c5f6a310 100644
--- a/cmd/podman/system/connection/list.go
+++ b/cmd/podman/system/connection/list.go
@@ -38,7 +38,7 @@ func init() {
})
listCmd.Flags().String("format", "", "Custom Go template for printing connections")
- _ = listCmd.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(namedDestination{}))
+ _ = listCmd.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(&namedDestination{}))
}
type namedDestination struct {
diff --git a/cmd/podman/system/events.go b/cmd/podman/system/events.go
index 2723adc43..09e589d3c 100644
--- a/cmd/podman/system/events.go
+++ b/cmd/podman/system/events.go
@@ -51,7 +51,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&eventFormat, formatFlagName, "", "format the output using a Go template")
- _ = eventsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(events.Event{}))
+ _ = eventsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&events.Event{}))
flags.BoolVar(&eventOptions.Stream, "stream", true, "stream new events; for testing only")
diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go
index e95e9336d..f8fd946cd 100644
--- a/cmd/podman/system/info.go
+++ b/cmd/podman/system/info.go
@@ -66,7 +66,7 @@ func infoFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVarP(&inFormat, formatFlagName, "f", "", "Change the output format to JSON or a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.Info{Host: &define.HostInfo{}, Store: &define.StoreInfo{}}))
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&define.Info{}))
}
func info(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/system/reset.go b/cmd/podman/system/reset.go
index 03783170f..8f2e73375 100644
--- a/cmd/podman/system/reset.go
+++ b/cmd/podman/system/reset.go
@@ -81,7 +81,10 @@ func reset(cmd *cobra.Command, args []string) {
}
// Purge all the external containers with storage
- registry.ContainerEngine().ContainerRm(registry.Context(), listCtnIds, entities.RmOptions{Force: true, All: true, Ignore: true, Volumes: true})
+ _, err := registry.ContainerEngine().ContainerRm(registry.Context(), listCtnIds, entities.RmOptions{Force: true, All: true, Ignore: true, Volumes: true})
+ if err != nil {
+ logrus.Error(err)
+ }
// Shutdown all running engines, `reset` will hijack repository
registry.ContainerEngine().Shutdown(registry.Context())
registry.ImageEngine().Shutdown(registry.Context())
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 9fb4a966a..7202b2c08 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -34,7 +34,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&versionFormat, formatFlagName, "f", "", "Change the output format to JSON or a Go template")
- _ = versionCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.SystemVersionReport{}))
+ _ = versionCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.SystemVersionReport{}))
}
func version(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/volumes/inspect.go b/cmd/podman/volumes/inspect.go
index 2230a2818..f21f9c233 100644
--- a/cmd/podman/volumes/inspect.go
+++ b/cmd/podman/volumes/inspect.go
@@ -41,7 +41,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format volume output using Go template")
- _ = inspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectVolumeData{}))
+ _ = inspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&define.InspectVolumeData{}))
}
func volumeInspect(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go
index 2edf04097..c14cf08bd 100644
--- a/cmd/podman/volumes/list.go
+++ b/cmd/podman/volumes/list.go
@@ -11,7 +11,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
- "github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -57,7 +56,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&cliOpts.Format, formatFlagName, "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
- _ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectVolumeData{}))
+ _ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.VolumeListReport{}))
flags.Bool("noheading", false, "Do not print headers")
flags.BoolVarP(&cliOpts.Quiet, "quiet", "q", false, "Print volume output in quiet mode")
diff --git a/cmd/rootlessport/main.go b/cmd/rootlessport/main.go
index e9ab8b076..5bd35a985 100644
--- a/cmd/rootlessport/main.go
+++ b/cmd/rootlessport/main.go
@@ -1,3 +1,6 @@
+//go:build linux
+// +build linux
+
package main
import (
@@ -307,11 +310,11 @@ func exposePorts(pm rkport.Manager, portMappings []types.PortMapping, childIP st
ChildPort: int(port.ContainerPort + i),
ChildIP: childIP,
}
- if err := rkportutil.ValidatePortSpec(spec, nil); err != nil {
- return err
- }
- if _, err := pm.AddPort(ctx, spec); err != nil {
- return err
+
+ for _, spec = range splitDualStackSpecIfWsl(spec) {
+ if err := validateAndAddPort(ctx, pm, spec); err != nil {
+ return err
+ }
}
}
}
@@ -319,6 +322,17 @@ func exposePorts(pm rkport.Manager, portMappings []types.PortMapping, childIP st
return nil
}
+func validateAndAddPort(ctx context.Context, pm rkport.Manager, spec rkport.Spec) error {
+ if err := rkportutil.ValidatePortSpec(spec, nil); err != nil {
+ return err
+ }
+ if _, err := pm.AddPort(ctx, spec); err != nil {
+ return err
+ }
+
+ return nil
+}
+
func child() error {
// load the config from the parent
var opaque map[string]string
diff --git a/cmd/rootlessport/wsl.go b/cmd/rootlessport/wsl.go
new file mode 100644
index 000000000..c1e67ba87
--- /dev/null
+++ b/cmd/rootlessport/wsl.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "net"
+ "strings"
+
+ "github.com/containers/common/pkg/machine"
+ rkport "github.com/rootless-containers/rootlesskit/pkg/port"
+)
+
+// WSL machines do not relay ipv4 traffic to dual-stack ports, simulate instead
+func splitDualStackSpecIfWsl(spec rkport.Spec) []rkport.Spec {
+ specs := []rkport.Spec{spec}
+ protocol := spec.Proto
+ if machine.MachineHostType() != machine.Wsl || strings.HasSuffix(protocol, "4") || strings.HasSuffix(protocol, "6") {
+ return specs
+ }
+
+ ip := net.ParseIP(spec.ParentIP)
+ splitLoopback := ip.IsLoopback() && ip.To4() == nil
+ // Map ::1 and 0.0.0.0/:: to ipv4 + ipv6 to simulate dual-stack
+ if ip.IsUnspecified() || splitLoopback {
+ specs = append(specs, spec)
+ specs[0].Proto = protocol + "4"
+ specs[1].Proto = protocol + "6"
+ if splitLoopback {
+ // Hacky, but we will only have one ipv4 loopback with WSL config
+ specs[0].ParentIP = "127.0.0.1"
+ }
+ if ip.IsUnspecified() {
+ specs[0].ParentIP = "0.0.0.0"
+ specs[1].ParentIP = "::"
+ }
+ }
+
+ return specs
+}
diff --git a/cmd/rootlessport/wsl_test.go b/cmd/rootlessport/wsl_test.go
new file mode 100644
index 000000000..83d7e3717
--- /dev/null
+++ b/cmd/rootlessport/wsl_test.go
@@ -0,0 +1,89 @@
+package main
+
+import (
+ "testing"
+
+ "github.com/containers/common/pkg/machine"
+ "github.com/rootless-containers/rootlesskit/pkg/port"
+ "github.com/stretchr/testify/assert"
+)
+
+type SpecData struct {
+ mach string
+ sourceProto string
+ sourceIP string
+ expectCount int
+ expectProto string
+ expectIP string
+ secondProto string
+ secondIP string
+}
+
+func TestDualStackSplit(t *testing.T) {
+ //nolint
+ const (
+ IP4_ALL = "0.0.0.0"
+ IP4__LO = "127.0.0.1"
+ IP6_ALL = "::"
+ IP6__LO = "::1"
+ TCP_ = "tcp"
+ TCP4 = "tcp4"
+ TCP6 = "tcp6"
+ WSL = "wsl"
+ ___ = ""
+ IP6_REG = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
+ IP4_REG = "10.0.0.1"
+ )
+
+ tests := []SpecData{
+ // Split cases
+ {WSL, TCP_, IP4_ALL, 2, TCP4, IP4_ALL, TCP6, IP6_ALL},
+ {WSL, TCP_, IP6_ALL, 2, TCP4, IP4_ALL, TCP6, IP6_ALL},
+ {WSL, TCP_, IP6__LO, 2, TCP4, IP4__LO, TCP6, IP6__LO},
+
+ // Non-Split
+ {WSL, TCP_, IP4__LO, 1, TCP_, IP4__LO, "", ""},
+ {WSL, TCP4, IP4_ALL, 1, TCP4, IP4_ALL, "", ""},
+ {WSL, TCP6, IP6__LO, 1, TCP6, IP6__LO, "", ""},
+ {WSL, TCP_, IP4_REG, 1, TCP_, IP4_REG, "", ""},
+ {WSL, TCP_, IP6_REG, 1, TCP_, IP6_REG, "", ""},
+ {___, TCP_, IP4_ALL, 1, TCP_, IP4_ALL, "", ""},
+ {___, TCP_, IP6_ALL, 1, TCP_, IP6_ALL, "", ""},
+ {___, TCP_, IP4__LO, 1, TCP_, IP4__LO, "", ""},
+ {___, TCP_, IP6__LO, 1, TCP_, IP6__LO, "", ""},
+ }
+
+ for _, data := range tests {
+ verifySplit(t, data)
+ }
+}
+
+func verifySplit(t *testing.T, data SpecData) {
+ machine := machine.GetMachineMarker()
+ oldEnable, oldType := machine.Enabled, machine.Type
+ machine.Enabled, machine.Type = len(data.mach) > 0, data.mach
+
+ source := port.Spec{
+ Proto: data.sourceProto,
+ ParentIP: data.sourceIP,
+ ParentPort: 100,
+ ChildIP: "1.1.1.1",
+ ChildPort: 200,
+ }
+ expect, second := source, source
+ specs := splitDualStackSpecIfWsl(source)
+
+ assert.Equal(t, data.expectCount, len(specs))
+
+ expect.Proto = data.expectProto
+ expect.ParentIP = data.expectIP
+ assert.Equal(t, expect, specs[0])
+
+ if data.expectCount > 1 {
+ second.Proto = data.secondProto
+ second.ParentIP = data.secondIP
+ assert.Equal(t, second, specs[1])
+ }
+
+ machine.Enabled, machine.Type = oldEnable, oldType
+}