diff options
author | Valentin Rothberg <rothberg@redhat.com> | 2021-06-25 15:58:39 +0200 |
---|---|---|
committer | Valentin Rothberg <rothberg@redhat.com> | 2021-07-14 16:23:51 +0200 |
commit | 01cfb51fe989f5b3d810961e6813653f10ea541a (patch) | |
tree | 04da3459b1f6617472138b7046bf97a6a3ad7a92 /cmd/podman | |
parent | 6fcf0b2f3238a6f1fc0131e14f3a8125a903e218 (diff) | |
download | podman-01cfb51fe989f5b3d810961e6813653f10ea541a.tar.gz podman-01cfb51fe989f5b3d810961e6813653f10ea541a.tar.bz2 podman-01cfb51fe989f5b3d810961e6813653f10ea541a.zip |
auto-update: make output more user friendly
The rather raw and scarce output of `podman auto-update` has been a
thorn in my eyes for a longer while. So far, Podman would only print
updated systemd units, one per line, without further formatting.
Motivated by issue #9949 which is asking for some more useful
information in combination with a dry-run feature, I sat down and
reflected which information may come in handy.
Running `podman auto-update` will now look as follows:
```
$ podman auto-update
Trying to pull [...]
UNIT CONTAINER IMAGE POLICY UPDATED
container-test.service 08fd34e533fd (test) localhost:5000/busybox registry false
```
Also refactor the spaghetti code in the backend a bit to make it easier
to digest and maintain.
For easier testing and for the sake of consistency with other commands
listing output, add a `--format` flag.
The man page will get an overhaul in a follow up commit.
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'cmd/podman')
-rw-r--r-- | cmd/podman/auto-update.go | 99 |
1 files changed, 91 insertions, 8 deletions
diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go index 34cc7d74b..6ccf4e167 100644 --- a/cmd/podman/auto-update.go +++ b/cmd/podman/auto-update.go @@ -1,10 +1,15 @@ package main import ( + "encoding/json" "fmt" + "os" + "strings" "github.com/containers/common/pkg/auth" "github.com/containers/common/pkg/completion" + "github.com/containers/common/pkg/report" + "github.com/containers/podman/v3/cmd/podman/common" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/errorhandling" @@ -12,8 +17,13 @@ import ( "github.com/spf13/cobra" ) +type cliAutoUpdateOptions struct { + entities.AutoUpdateOptions + format string +} + var ( - autoUpdateOptions = entities.AutoUpdateOptions{} + autoUpdateOptions = cliAutoUpdateOptions{} autoUpdateDescription = `Auto update containers according to their auto-update policy. Auto-update policies are specified with the "io.containers.autoupdate" label. @@ -42,6 +52,9 @@ func init() { authfileFlagName := "authfile" flags.StringVar(&autoUpdateOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path to the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") _ = autoUpdateCommand.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault) + + flags.StringVar(&autoUpdateOptions.format, "format", "", "Change the output format to JSON or a Go template") + _ = autoUpdateCommand.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(autoUpdateOutput{})) } func autoUpdate(cmd *cobra.Command, args []string) error { @@ -49,13 +62,83 @@ func autoUpdate(cmd *cobra.Command, args []string) error { // Backwards compat. System tests expect this error string. return errors.Errorf("`%s` takes no arguments", cmd.CommandPath()) } - report, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext(), autoUpdateOptions) - if report != nil && len(report.Units) > 0 { - // Make it more obvious to users what the output means. - fmt.Println("\nRestarted the following systemd units:") - for _, unit := range report.Units { - fmt.Println(unit) - } + + allReports, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext(), autoUpdateOptions.AutoUpdateOptions) + if allReports == nil { + return errorhandling.JoinErrors(failures) + } + + if err := writeTemplate(allReports, autoUpdateOptions.format); err != nil { + failures = append(failures, err) } + return errorhandling.JoinErrors(failures) } + +type autoUpdateOutput struct { + Unit string + Container string + ContainerName string + ContainerID string + Image string + Policy string + Updated string +} + +func reportsToOutput(allReports []*entities.AutoUpdateReport) []autoUpdateOutput { + output := make([]autoUpdateOutput, len(allReports)) + for i, r := range allReports { + output[i] = autoUpdateOutput{ + Unit: r.SystemdUnit, + Container: fmt.Sprintf("%s (%s)", r.ContainerID[:12], r.ContainerName), + ContainerName: r.ContainerName, + ContainerID: r.ContainerID, + Image: r.ImageName, + Policy: r.Policy, + Updated: r.Updated, + } + } + return output +} + +func writeTemplate(allReports []*entities.AutoUpdateReport, inputFormat string) error { + var format string + var printHeader bool + + output := reportsToOutput(allReports) + switch inputFormat { + case "": + rows := []string{"{{.Unit}}", "{{.Container}}", "{{.Image}}", "{{.Policy}}", "{{.Updated}}"} + format = "{{range . }}" + strings.Join(rows, "\t") + "\n{{end -}}" + printHeader = true + case "json": + prettyJSON, err := json.MarshalIndent(output, "", " ") + if err != nil { + return err + } + fmt.Println(string(prettyJSON)) + return nil + default: + format = "{{range . }}" + inputFormat + "\n{{end -}}" + } + + 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 { + headers := report.Headers(autoUpdateOutput{}, nil) + if err := tmpl.Execute(w, headers); err != nil { + return err + } + } + + return tmpl.Execute(w, output) +} |