summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/auto-update.go28
-rw-r--r--cmd/podman/common/netflags.go18
-rw-r--r--cmd/podman/containers/create.go2
-rw-r--r--cmd/podman/inspect/inspect.go33
-rw-r--r--cmd/podman/machine/info.go12
-rw-r--r--cmd/podman/machine/inspect.go20
-rw-r--r--cmd/podman/machine/list.go40
-rw-r--r--cmd/podman/networks/list.go31
-rw-r--r--cmd/podman/pods/create.go11
-rw-r--r--cmd/podman/registry/remote.go4
-rw-r--r--cmd/podman/root.go35
-rw-r--r--cmd/podman/secrets/inspect.go13
-rw-r--r--cmd/podman/secrets/list.go32
-rw-r--r--cmd/podman/system/connection/add.go84
-rw-r--r--cmd/podman/system/connection/default.go14
-rw-r--r--cmd/podman/system/connection/list.go56
-rw-r--r--cmd/podman/system/connection/remove.go8
-rw-r--r--cmd/podman/system/context.go28
-rw-r--r--cmd/podman/system/info.go13
-rw-r--r--cmd/podman/system/version.go19
-rw-r--r--cmd/podman/utils/alias.go2
-rw-r--r--cmd/podman/volumes/list.go30
22 files changed, 324 insertions, 209 deletions
diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go
index 88ef0ec88..6a0446422 100644
--- a/cmd/podman/auto-update.go
+++ b/cmd/podman/auto-update.go
@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"os"
- "strings"
"github.com/containers/common/pkg/auth"
"github.com/containers/common/pkg/completion"
@@ -104,15 +103,15 @@ func reportsToOutput(allReports []*entities.AutoUpdateReport) []autoUpdateOutput
}
func writeTemplate(allReports []*entities.AutoUpdateReport, inputFormat string) error {
- var format string
- var printHeader bool
+ rpt := report.New(os.Stdout, "auto-update")
+ defer rpt.Flush()
output := reportsToOutput(allReports)
+ var err error
switch inputFormat {
case "":
- rows := []string{"{{.Unit}}", "{{.Container}}", "{{.Image}}", "{{.Policy}}", "{{.Updated}}"}
- format = "{{range . }}" + strings.Join(rows, "\t") + "\n{{end -}}"
- printHeader = true
+ format := "{{range . }}\t{{.Unit}}\t{{.Container}}\t{{.Image}}\t{{.Policy}}\t{{.Updated}}\n{{end -}}"
+ rpt, err = rpt.Parse(report.OriginPodman, format)
case "json":
prettyJSON, err := json.MarshalIndent(output, "", " ")
if err != nil {
@@ -121,26 +120,17 @@ func writeTemplate(allReports []*entities.AutoUpdateReport, inputFormat string)
fmt.Println(string(prettyJSON))
return nil
default:
- format = "{{range . }}" + inputFormat + "\n{{end -}}"
+ rpt, err = rpt.Parse(report.OriginUser, inputFormat)
}
-
- tmpl, err := report.NewTemplate("auto-update").Parse(format)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
- if printHeader {
+ if rpt.RenderHeaders {
headers := report.Headers(autoUpdateOutput{}, nil)
- if err := tmpl.Execute(w, headers); err != nil {
+ if err := rpt.Execute(headers); err != nil {
return err
}
}
-
- return tmpl.Execute(w, output)
+ return rpt.Execute(output)
}
diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go
index 90f05ab15..081914017 100644
--- a/cmd/podman/common/netflags.go
+++ b/cmd/podman/common/netflags.go
@@ -33,18 +33,12 @@ func DefineNetFlags(cmd *cobra.Command) {
)
_ = cmd.RegisterFlagCompletionFunc(dnsFlagName, completion.AutocompleteNone)
- dnsOptFlagName := "dns-opt"
+ dnsOptFlagName := "dns-option"
netFlags.StringSlice(
dnsOptFlagName, containerConfig.DNSOptions(),
"Set custom DNS options",
)
_ = cmd.RegisterFlagCompletionFunc(dnsOptFlagName, completion.AutocompleteNone)
- netFlags.StringSlice(
- "dns-option", containerConfig.DNSOptions(),
- "Docker compatibility option== --dns-opt",
- )
- _ = netFlags.MarkHidden("dns-option")
-
dnsSearchFlagName := "dns-search"
netFlags.StringSlice(
dnsSearchFlagName, containerConfig.DNSSearches(),
@@ -143,20 +137,12 @@ func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet) (*enti
}
}
- if flags.Changed("dns-opt") {
- options, err := flags.GetStringSlice("dns-opt")
- if err != nil {
- return nil, err
- }
- opts.DNSOptions = options
- }
-
if flags.Changed("dns-option") {
options, err := flags.GetStringSlice("dns-option")
if err != nil {
return nil, err
}
- opts.DNSOptions = append(opts.DNSOptions, options...)
+ opts.DNSOptions = options
}
if flags.Changed("dns-search") {
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index b854ff4b2..f9e37178e 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -280,7 +280,7 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra
if c.Flag("shm-size").Changed {
vals.ShmSize = c.Flag("shm-size").Value.String()
}
- 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()) {
+ if (c.Flag("dns").Changed || c.Flag("dns-option").Changed || c.Flag("dns-search").Changed) && vals.Net != nil && (vals.Net.Network.NSMode == specgen.NoNetwork || vals.Net.Network.IsContainer()) {
return vals, fmt.Errorf("conflicting options: dns and the network mode: " + string(vals.Net.Network.NSMode))
}
noHosts, err := c.Flags().GetBool("no-hosts")
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
index ccabd7614..22b2c9055 100644
--- a/cmd/podman/inspect/inspect.go
+++ b/cmd/podman/inspect/inspect.go
@@ -8,7 +8,6 @@ import (
"os"
"regexp"
"strings"
- "text/template"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
@@ -16,7 +15,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/pkg/domain/entities"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -176,13 +174,18 @@ func (i *inspector) inspect(namesOrIDs []string) error {
}
default:
// Landing here implies user has given a custom --format
- row := inspectNormalize(i.options.Format, tmpType)
- row = report.NormalizeFormat(row)
- row = report.EnforceRange(row)
- err = printTmpl(tmpType, row, data)
+ var rpt *report.Formatter
+ format := inspectNormalize(i.options.Format, i.options.Type)
+ rpt, err = report.New(os.Stdout, "inspect").Parse(report.OriginUser, format)
+ if err != nil {
+ return err
+ }
+ defer rpt.Flush()
+
+ err = rpt.Execute(data)
}
if err != nil {
- logrus.Errorf("Printing inspect output: %v", err)
+ errs = append(errs, fmt.Errorf("printing inspect output: %w", err))
}
if len(errs) > 0 {
@@ -205,22 +208,6 @@ func printJSON(data interface{}) error {
return enc.Encode(data)
}
-func printTmpl(typ, row string, data []interface{}) error {
- // We cannot use c/common/reports here, too many levels of interface{}
- t, err := template.New(typ + " inspect").Funcs(template.FuncMap(report.DefaultFuncs)).Parse(row)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
- err = t.Execute(w, data)
- w.Flush()
- return err
-}
-
func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, []error, error) {
var data []interface{}
allErrs := []error{}
diff --git a/cmd/podman/machine/info.go b/cmd/podman/machine/info.go
index 1151f9e86..9c7454379 100644
--- a/cmd/podman/machine/info.go
+++ b/cmd/podman/machine/info.go
@@ -5,7 +5,6 @@ package machine
import (
"fmt"
- "html/template"
"os"
"runtime"
@@ -75,13 +74,16 @@ func info(cmd *cobra.Command, args []string) error {
}
fmt.Println(string(b))
case cmd.Flags().Changed("format"):
- tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs))
- inFormat = report.NormalizeFormat(inFormat)
- tmpl, err := tmpl.Parse(inFormat)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ // Use OriginUnknown so it does not add an extra range since it
+ // will only be called for a single element and not a slice.
+ rpt, err = rpt.Parse(report.OriginUnknown, inFormat)
if err != nil {
return err
}
- return tmpl.Execute(os.Stdout, info)
+ return rpt.Execute(info)
default:
b, err := yaml.Marshal(info)
if err != nil {
diff --git a/cmd/podman/machine/inspect.go b/cmd/podman/machine/inspect.go
index d69c382f2..410bb3889 100644
--- a/cmd/podman/machine/inspect.go
+++ b/cmd/podman/machine/inspect.go
@@ -11,7 +11,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/machine"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -66,28 +65,23 @@ func inspect(cmd *cobra.Command, args []string) error {
}
vms = append(vms, *ii)
}
+
switch {
case cmd.Flag("format").Changed:
- row := report.NormalizeFormat(inspectFlag.format)
- row = report.EnforceRange(row)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- tmpl, err := report.NewTemplate("Machine inspect").Parse(row)
+ rpt, err := rpt.Parse(report.OriginUser, inspectFlag.format)
if err != nil {
return err
}
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
-
- if err := tmpl.Execute(w, vms); err != nil {
- logrus.Error(err)
+ if err := rpt.Execute(vms); err != nil {
+ errs = append(errs, err)
}
- w.Flush()
default:
if err := printJSON(vms); err != nil {
- logrus.Error(err)
+ errs = append(errs, err)
}
}
return errs.PrintErrors()
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index dd4a86697..ddc9ce246 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -53,7 +53,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")
+ flags.StringVar(&listFlag.format, formatFlagName, "{{range .}}{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n{{end -}}", "Format volume output using JSON or a Go template")
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.ListReporter{}))
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Show only machine names")
@@ -66,10 +66,6 @@ func list(cmd *cobra.Command, args []string) error {
err error
)
- if listFlag.quiet {
- listFlag.format = "{{.Name}}\n"
- }
-
provider := GetSystemDefaultProvider()
listResponse, err = provider.List(opts)
if err != nil {
@@ -115,37 +111,29 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.ListReporter) erro
"Memory": "MEMORY",
"DiskSize": "DISK SIZE",
})
- printHeader := !listFlag.noHeading
- if listFlag.quiet {
- printHeader = false
- }
- var row string
+
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ var err error
switch {
- case cmd.Flags().Changed("format"):
- row = cmd.Flag("format").Value.String()
- printHeader = report.HasTable(row)
- row = report.NormalizeFormat(row)
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, listFlag.format)
+ case listFlag.quiet:
+ rpt, err = rpt.Parse(report.OriginUser, "{{.Name}}\n")
default:
- row = cmd.Flag("format").Value.String()
+ rpt, err = rpt.Parse(report.OriginPodman, listFlag.format)
}
- format := report.EnforceRange(row)
-
- tmpl, err := report.NewTemplate("list").Parse(format)
if err != nil {
return err
}
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
- defer w.Flush()
- if printHeader {
- if err := tmpl.Execute(w, headers); err != nil {
+ if rpt.RenderHeaders && !listFlag.noHeading {
+ if err := rpt.Execute(headers); err != nil {
return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, responses)
+ return rpt.Execute(responses)
}
func strTime(t time.Time) string {
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go
index 5d4be2a81..951583cfb 100644
--- a/cmd/podman/networks/list.go
+++ b/cmd/podman/networks/list.go
@@ -122,36 +122,27 @@ func templateOut(cmd *cobra.Command, responses []types.Network) error {
"ID": "network id",
})
- renderHeaders := report.HasTable(networkListOptions.Format)
- var row string
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ var err error
switch {
- case cmd.Flags().Changed("format"):
- row = report.NormalizeFormat(networkListOptions.Format)
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, networkListOptions.Format)
default:
- // 'podman network ls' equivalent to 'podman network ls --format="table {{.ID}} {{.Name}} {{.Version}} {{.Plugins}}" '
- row = "{{.ID}}\t{{.Name}}\t{{.Driver}}\n"
- renderHeaders = true
+ rpt, err = rpt.Parse(report.OriginPodman, "{{range .}}{{.ID}}\t{{.Name}}\t{{.Driver}}\n{{end -}}")
}
- format := report.EnforceRange(row)
-
- tmpl, err := report.NewTemplate("list").Parse(format)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
noHeading, _ := cmd.Flags().GetBool("noheading")
- if !noHeading && renderHeaders {
- if err := tmpl.Execute(w, headers); err != nil {
- return err
+ if rpt.RenderHeaders && !noHeading {
+ if err := rpt.Execute(headers); err != nil {
+ return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, nlprs)
+ return rpt.Execute(nlprs)
}
// ListPrintReports returns the network list report
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index d30f4782a..1f8152f32 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/containers"
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/errorhandling"
@@ -26,7 +27,6 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
- "github.com/spf13/pflag"
)
var (
@@ -99,14 +99,7 @@ func init() {
shareParentFlagName := "share-parent"
flags.BoolVar(&shareParent, shareParentFlagName, true, "Set the pod's cgroup as the cgroup parent for all containers joining the pod")
- flags.SetNormalizeFunc(aliasNetworkFlag)
-}
-
-func aliasNetworkFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName {
- if name == "net" {
- name = "network"
- }
- return pflag.NormalizedName(name)
+ flags.SetNormalizeFunc(utils.AliasFlags)
}
func create(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/registry/remote.go b/cmd/podman/registry/remote.go
index afe32e0b9..02aa31c58 100644
--- a/cmd/podman/registry/remote.go
+++ b/cmd/podman/registry/remote.go
@@ -32,6 +32,8 @@ func IsRemote() bool {
fs.BoolVarP(&remoteFromCLI.Value, "remote", "r", remote, "")
connectionFlagName := "connection"
fs.StringP(connectionFlagName, "c", "", "")
+ contextFlagName := "context"
+ fs.String(contextFlagName, "", "")
hostFlagName := "host"
fs.StringP(hostFlagName, "H", "", "")
urlFlagName := "url"
@@ -46,7 +48,7 @@ func IsRemote() bool {
}
_ = fs.Parse(os.Args[start:])
// --connection or --url implies --remote
- remoteFromCLI.Value = remoteFromCLI.Value || fs.Changed(connectionFlagName) || fs.Changed(urlFlagName) || fs.Changed(hostFlagName)
+ remoteFromCLI.Value = remoteFromCLI.Value || fs.Changed(connectionFlagName) || fs.Changed(urlFlagName) || fs.Changed(hostFlagName) || fs.Changed(contextFlagName)
})
return podmanOptions.EngineMode == entities.TunnelMode || remoteFromCLI.Value
}
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 2e00777a4..9e3ff48aa 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -174,11 +174,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
}
}
- // --connection is not as "special" as --remote so we can wait and process it here
- conn := cmd.Root().LocalFlags().Lookup("connection")
- if conn != nil && conn.Changed {
- cfg.Engine.ActiveService = conn.Value.String()
-
+ setupConnection := func() error {
var err error
cfg.URI, cfg.Identity, err = cfg.ActiveDestination()
if err != nil {
@@ -192,6 +188,29 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
if err := cmd.Root().LocalFlags().Set("identity", cfg.Identity); err != nil {
return fmt.Errorf("failed to override --identity flag: %w", err)
}
+ return nil
+ }
+
+ // --connection is not as "special" as --remote so we can wait and process it here
+ contextConn := cmd.Root().LocalFlags().Lookup("context")
+ conn := cmd.Root().LocalFlags().Lookup("connection")
+ if conn != nil && conn.Changed {
+ if contextConn != nil && contextConn.Changed {
+ return fmt.Errorf("use of --connection and --context at the same time is not allowed")
+ }
+ cfg.Engine.ActiveService = conn.Value.String()
+ if err := setupConnection(); err != nil {
+ return err
+ }
+ }
+ if contextConn != nil && contextConn.Changed {
+ service := contextConn.Value.String()
+ if service != "default" {
+ cfg.Engine.ActiveService = service
+ if err := setupConnection(); err != nil {
+ return err
+ }
+ }
}
// Special case if command is hidden completion command ("__complete","__completeNoDesc")
@@ -232,10 +251,6 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
}
}
- context := cmd.Root().LocalFlags().Lookup("context")
- if context.Value.String() != "default" {
- return errors.New("podman does not support swarm, the only --context value allowed is \"default\"")
- }
if !registry.IsRemote() {
if cmd.Flag("cpu-profile").Changed {
f, err := os.Create(cfg.CPUProfile)
@@ -362,7 +377,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
_ = cmd.RegisterFlagCompletionFunc(sshFlagName, common.AutocompleteSSH)
connectionFlagName := "connection"
- lFlags.StringVarP(&opts.Engine.ActiveService, connectionFlagName, "c", srv, "Connection to use for remote Podman service")
+ lFlags.StringP(connectionFlagName, "c", srv, "Connection to use for remote Podman service")
_ = cmd.RegisterFlagCompletionFunc(connectionFlagName, common.AutocompleteSystemConnections)
urlFlagName := "url"
diff --git a/cmd/podman/secrets/inspect.go b/cmd/podman/secrets/inspect.go
index c99e555ba..f4c395b0f 100644
--- a/cmd/podman/secrets/inspect.go
+++ b/cmd/podman/secrets/inspect.go
@@ -47,20 +47,15 @@ func inspect(cmd *cobra.Command, args []string) error {
}
if cmd.Flags().Changed("format") {
- row := report.NormalizeFormat(format)
- formatted := report.EnforceRange(row)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- tmpl, err := report.NewTemplate("inspect").Parse(formatted)
+ rpt, err := rpt.Parse(report.OriginUser, format)
if err != nil {
return err
}
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
- defer w.Flush()
- if err := tmpl.Execute(w, inspected); err != nil {
+ if err := rpt.Execute(inspected); err != nil {
return err
}
} else {
diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go
index afa9b8887..1833cc544 100644
--- a/cmd/podman/secrets/list.go
+++ b/cmd/podman/secrets/list.go
@@ -46,7 +46,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")
+ flags.StringVar(&listFlag.format, formatFlagName, "{{range .}}{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}\n{{end -}}", "Format volume output using Go template")
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.SecretInfoReport{}))
filterFlagName := "filter"
@@ -105,31 +105,25 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.SecretListReport)
"UpdatedAt": "UPDATED",
})
- row := cmd.Flag("format").Value.String()
- if cmd.Flags().Changed("format") {
- row = report.NormalizeFormat(row)
- }
- format := report.EnforceRange(row)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- tmpl, err := report.NewTemplate("list").Parse(format)
- if err != nil {
- return err
+ var err error
+ switch {
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, listFlag.format)
+ default:
+ rpt, err = rpt.Parse(report.OriginPodman, listFlag.format)
}
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
-
- if cmd.Flags().Changed("format") && !report.HasTable(listFlag.format) {
- listFlag.noHeading = true
- }
- if !listFlag.noHeading {
- if err := tmpl.Execute(w, headers); err != nil {
+ noHeading, _ := cmd.Flags().GetBool("noheading")
+ if rpt.RenderHeaders && !noHeading {
+ if err := rpt.Execute(headers); err != nil {
return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, responses)
+ return rpt.Execute(responses)
}
diff --git a/cmd/podman/system/connection/add.go b/cmd/podman/system/connection/add.go
index f3b61b254..2730ebfb7 100644
--- a/cmd/podman/system/connection/add.go
+++ b/cmd/podman/system/connection/add.go
@@ -6,6 +6,7 @@ import (
"net/url"
"os"
"regexp"
+ "strings"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
@@ -37,6 +38,17 @@ var (
`,
}
+ createCmd = &cobra.Command{
+ Use: "create [options] NAME DESTINATION",
+ Args: cobra.ExactArgs(1),
+ Short: addCmd.Short,
+ Long: addCmd.Long,
+ RunE: create,
+ ValidArgsFunction: completion.AutocompleteNone,
+ }
+
+ dockerPath string
+
cOpts = struct {
Identity string
Port int
@@ -50,7 +62,6 @@ func init() {
Command: addCmd,
Parent: system.ConnectionCmd,
})
-
flags := addCmd.Flags()
portFlagName := "port"
@@ -66,6 +77,21 @@ func init() {
_ = addCmd.RegisterFlagCompletionFunc(socketPathFlagName, completion.AutocompleteDefault)
flags.BoolVarP(&cOpts.Default, "default", "d", false, "Set connection to be default")
+
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: createCmd,
+ Parent: system.ContextCmd,
+ })
+
+ flags = createCmd.Flags()
+ dockerFlagName := "docker"
+ flags.StringVar(&dockerPath, dockerFlagName, "", "Description of the context")
+
+ _ = createCmd.RegisterFlagCompletionFunc(dockerFlagName, completion.AutocompleteNone)
+ flags.String("description", "", "Ignored. Just for script compatibility")
+ flags.String("from", "", "Ignored. Just for script compatibility")
+ flags.String("kubernetes", "", "Ignored. Just for script compatibility")
+ flags.String("default-stack-orchestrator", "", "Ignored. Just for script compatibility")
}
func add(cmd *cobra.Command, args []string) error {
@@ -171,3 +197,59 @@ func add(cmd *cobra.Command, args []string) error {
}
return cfg.Write()
}
+
+func create(cmd *cobra.Command, args []string) error {
+ dest, err := translateDest(dockerPath)
+ if err != nil {
+ return err
+ }
+ if match, err := regexp.Match("^[A-Za-z][A-Za-z0-9+.-]*://", []byte(dest)); err != nil {
+ return fmt.Errorf("invalid destination: %w", err)
+ } else if !match {
+ dest = "ssh://" + dest
+ }
+
+ uri, err := url.Parse(dest)
+ if err != nil {
+ return err
+ }
+
+ cfg, err := config.ReadCustomConfig()
+ if err != nil {
+ return err
+ }
+
+ dst := config.Destination{
+ URI: uri.String(),
+ }
+
+ if cfg.Engine.ServiceDestinations == nil {
+ cfg.Engine.ServiceDestinations = map[string]config.Destination{
+ args[0]: dst,
+ }
+ cfg.Engine.ActiveService = args[0]
+ } else {
+ cfg.Engine.ServiceDestinations[args[0]] = dst
+ }
+ return cfg.Write()
+}
+
+func translateDest(path string) (string, error) {
+ if path == "" {
+ return "", nil
+ }
+ split := strings.SplitN(path, "=", 2)
+ if len(split) == 1 {
+ return split[0], nil
+ }
+ if split[0] != "host" {
+ return "", fmt.Errorf("\"host\" is requited for --docker option")
+ }
+ // "host=tcp://myserver:2376,ca=~/ca-file,cert=~/cert-file,key=~/key-file"
+ vals := strings.Split(split[1], ",")
+ if len(vals) > 1 {
+ return "", fmt.Errorf("--docker additional options %q not supported", strings.Join(vals[1:], ","))
+ }
+ // for now we ignore other fields specified on command line
+ return vals[0], nil
+}
diff --git a/cmd/podman/system/connection/default.go b/cmd/podman/system/connection/default.go
index 81866df55..8d1709e9f 100644
--- a/cmd/podman/system/connection/default.go
+++ b/cmd/podman/system/connection/default.go
@@ -21,10 +21,24 @@ var (
RunE: defaultRunE,
Example: `podman system connection default testing`,
}
+
+ useCmd = &cobra.Command{
+ Use: "use NAME",
+ Args: cobra.ExactArgs(1),
+ Short: dfltCmd.Short,
+ Long: dfltCmd.Long,
+ ValidArgsFunction: dfltCmd.ValidArgsFunction,
+ RunE: dfltCmd.RunE,
+ Example: `podman context use testing`,
+ }
)
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: useCmd,
+ Parent: system.ContextCmd,
+ })
+ registry.Commands = append(registry.Commands, registry.CliCommand{
Command: dfltCmd,
Parent: system.ConnectionCmd,
})
diff --git a/cmd/podman/system/connection/list.go b/cmd/podman/system/connection/list.go
index 2c5f6a310..190a68d52 100644
--- a/cmd/podman/system/connection/list.go
+++ b/cmd/podman/system/connection/list.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/report"
+ "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/system"
@@ -29,16 +30,36 @@ var (
RunE: list,
TraverseChildren: false,
}
+ inspectCmd = &cobra.Command{
+ Use: "inspect [options] [CONTEXT] [CONTEXT...]",
+ Short: "Inspect destination for a Podman service(s)",
+ ValidArgsFunction: completion.AutocompleteNone,
+ RunE: inspect,
+ }
)
func init() {
+ initFlags := func(cmd *cobra.Command) {
+ cmd.Flags().StringP("format", "f", "", "Custom Go template for printing connections")
+ _ = cmd.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(&namedDestination{}))
+ cmd.Flags().BoolP("quiet", "q", false, "Custom Go template for printing connections")
+ }
+
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: listCmd,
+ Parent: system.ContextCmd,
+ })
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: listCmd,
Parent: system.ConnectionCmd,
})
+ initFlags(listCmd)
- listCmd.Flags().String("format", "", "Custom Go template for printing connections")
- _ = listCmd.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(&namedDestination{}))
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: inspectCmd,
+ Parent: system.ContextCmd,
+ })
+ initFlags(inspectCmd)
}
type namedDestination struct {
@@ -48,13 +69,34 @@ type namedDestination struct {
}
func list(cmd *cobra.Command, _ []string) error {
+ return inspect(cmd, nil)
+}
+
+func inspect(cmd *cobra.Command, args []string) error {
cfg, err := config.ReadCustomConfig()
if err != nil {
return err
}
+ format := cmd.Flag("format").Value.String()
+ if format == "" && args != nil {
+ format = "json"
+ }
+
+ quiet, err := cmd.Flags().GetBool("quiet")
+ if err != nil {
+ return err
+ }
rows := make([]namedDestination, 0)
for k, v := range cfg.Engine.ServiceDestinations {
+ if args != nil && !util.StringInSlice(k, args) {
+ continue
+ }
+
+ if quiet {
+ fmt.Println(k)
+ continue
+ }
def := false
if k == cfg.Engine.ActiveService {
def = true
@@ -71,6 +113,10 @@ func list(cmd *cobra.Command, _ []string) error {
rows = append(rows, r)
}
+ if quiet {
+ return nil
+ }
+
sort.Slice(rows, func(i, j int) bool {
return rows[i].Name < rows[j].Name
})
@@ -78,7 +124,7 @@ func list(cmd *cobra.Command, _ []string) error {
rpt := report.New(os.Stdout, cmd.Name())
defer rpt.Flush()
- if report.IsJSON(cmd.Flag("format").Value.String()) {
+ if report.IsJSON(format) {
buf, err := registry.JSONLibrary().MarshalIndent(rows, "", " ")
if err == nil {
fmt.Println(string(buf))
@@ -86,8 +132,8 @@ func list(cmd *cobra.Command, _ []string) error {
return err
}
- if cmd.Flag("format").Changed {
- rpt, err = rpt.Parse(report.OriginUser, cmd.Flag("format").Value.String())
+ if format != "" {
+ rpt, err = rpt.Parse(report.OriginUser, format)
} else {
rpt, err = rpt.Parse(report.OriginPodman,
"{{range .}}{{.Name}}\t{{.URI}}\t{{.Identity}}\t{{.Default}}\n{{end -}}")
diff --git a/cmd/podman/system/connection/remove.go b/cmd/podman/system/connection/remove.go
index 29bf98c43..5ff0000d6 100644
--- a/cmd/podman/system/connection/remove.go
+++ b/cmd/podman/system/connection/remove.go
@@ -31,11 +31,19 @@ var (
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: rmCmd,
+ Parent: system.ContextCmd,
+ })
+
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: rmCmd,
Parent: system.ConnectionCmd,
})
flags := rmCmd.Flags()
flags.BoolVarP(&rmOpts.All, "all", "a", false, "Remove all connections")
+
+ flags.BoolP("force", "f", false, "Ignored: for Docker compatibility")
+ _ = flags.MarkHidden("force")
}
func rm(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/system/context.go b/cmd/podman/system/context.go
new file mode 100644
index 000000000..926e4a443
--- /dev/null
+++ b/cmd/podman/system/context.go
@@ -0,0 +1,28 @@
+package system
+
+import (
+ "github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/cmd/podman/validate"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // ContextCmd skips creating engines (PersistentPreRunE/PersistentPostRunE are No-Op's) since
+ // sub-commands will obtain connection information to said engines
+ ContextCmd = &cobra.Command{
+ Use: "context",
+ Short: "Manage remote API service destinations",
+ Long: `Manage remote API service destination information in podman configuration`,
+ PersistentPreRunE: validate.NoOp,
+ RunE: validate.SubCommandExists,
+ PersistentPostRunE: validate.NoOp,
+ Hidden: true,
+ TraverseChildren: false,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: ContextCmd,
+ })
+}
diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go
index 296fa4def..9613d5e56 100644
--- a/cmd/podman/system/info.go
+++ b/cmd/podman/system/info.go
@@ -3,7 +3,6 @@ package system
import (
"fmt"
"os"
- "text/template"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
@@ -86,14 +85,16 @@ func info(cmd *cobra.Command, args []string) error {
}
fmt.Println(string(b))
case cmd.Flags().Changed("format"):
- // Cannot use report.New() as it enforces {{range .}} for OriginUser templates
- tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs))
- inFormat = report.NormalizeFormat(inFormat)
- tmpl, err := tmpl.Parse(inFormat)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ // Use OriginUnknown so it does not add an extra range since it
+ // will only be called for a single element and not a slice.
+ rpt, err = rpt.Parse(report.OriginUnknown, inFormat)
if err != nil {
return err
}
- return tmpl.Execute(os.Stdout, info)
+ return rpt.Execute(info)
default:
b, err := yaml.Marshal(info)
if err != nil {
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 7202b2c08..33ab0f757 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -4,7 +4,6 @@ import (
"fmt"
"os"
"strings"
- "text/template"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
@@ -12,6 +11,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -53,22 +53,25 @@ func version(cmd *cobra.Command, args []string) error {
}
if cmd.Flag("format").Changed {
- // Cannot use report.New() as it enforces {{range .}} for OriginUser templates
- tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs))
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- versionFormat = report.NormalizeFormat(versionFormat)
- tmpl, err := tmpl.Parse(versionFormat)
+ // Use OriginUnknown so it does not add an extra range since it
+ // will only be called for a single element and not a slice.
+ rpt, err = rpt.Parse(report.OriginUnknown, versionFormat)
if err != nil {
return err
}
- if err := tmpl.Execute(os.Stdout, versions); err != nil {
+ if err := rpt.Execute(versions); err != nil {
+ // only log at debug since we fall back to the client only template
+ logrus.Debugf("Failed to execute template: %v", err)
// On Failure, assume user is using older version of podman version --format and check client
versionFormat = strings.ReplaceAll(versionFormat, ".Server.", ".")
- tmpl, err := tmpl.Parse(versionFormat)
+ rpt, err := rpt.Parse(report.OriginUnknown, versionFormat)
if err != nil {
return err
}
- if err := tmpl.Execute(os.Stdout, versions.Client); err != nil {
+ if err := rpt.Execute(versions.Client); err != nil {
return err
}
}
diff --git a/cmd/podman/utils/alias.go b/cmd/podman/utils/alias.go
index b37d0f714..f6ea5110e 100644
--- a/cmd/podman/utils/alias.go
+++ b/cmd/podman/utils/alias.go
@@ -5,6 +5,8 @@ import "github.com/spf13/pflag"
// AliasFlags is a function to handle backwards compatibility with old flags
func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
switch name {
+ case "dns-opt":
+ name = "dns-option"
case "healthcheck-command":
name = "health-cmd"
case "healthcheck-interval":
diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go
index 06118513d..70041834b 100644
--- a/cmd/podman/volumes/list.go
+++ b/cmd/podman/volumes/list.go
@@ -55,7 +55,7 @@ func init() {
_ = lsCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteVolumeFilters)
formatFlagName := "format"
- flags.StringVar(&cliOpts.Format, formatFlagName, "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
+ flags.StringVar(&cliOpts.Format, formatFlagName, "{{range .}}{{.Driver}}\t{{.Name}}\n{{end -}}", "Format volume output using Go template")
_ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.VolumeListReport{}))
flags.Bool("noheading", false, "Do not print headers")
@@ -95,34 +95,28 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.VolumeListReport)
"Name": "VOLUME NAME",
})
- var row string
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ var err error
switch {
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, cliOpts.Format)
case cliOpts.Quiet:
- row = "{{.Name}}\n"
- case cmd.Flags().Changed("format"):
- row = report.NormalizeFormat(cliOpts.Format)
+ rpt, err = rpt.Parse(report.OriginUser, "{{.Name}}\n")
default:
- row = cmd.Flag("format").Value.String()
+ rpt, err = rpt.Parse(report.OriginPodman, cliOpts.Format)
}
- format := report.EnforceRange(row)
-
- tmpl, err := report.NewTemplate("list").Parse(format)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
- if !(noHeading || cliOpts.Quiet || cmd.Flag("format").Changed) {
- if err := tmpl.Execute(w, headers); err != nil {
+ if (rpt.RenderHeaders) && !noHeading {
+ if err := rpt.Execute(headers); err != nil {
return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, responses)
+ return rpt.Execute(responses)
}
func outputJSON(vols []*entities.VolumeListReport) error {