Skip to content

Commit

Permalink
auto-update: make output more user friendly
Browse files Browse the repository at this point in the history
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 containers#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 <[email protected]>
  • Loading branch information
vrothberg committed Jul 14, 2021
1 parent 6fcf0b2 commit 01cfb51
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 84 deletions.
99 changes: 91 additions & 8 deletions cmd/podman/auto-update.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
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"
"github.com/pkg/errors"
"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.
Expand Down Expand Up @@ -42,20 +52,93 @@ 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 {
if len(args) > 0 {
// 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)
}
24 changes: 20 additions & 4 deletions docs/source/markdown/podman-auto-update.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ If the authorization state is not found there, `$HOME/.docker/config.json` is ch

Note: There is also the option to override the default path of the authentication file by setting the `REGISTRY_AUTH_FILE` environment variable. This can be done with **export REGISTRY_AUTH_FILE=_path_**.

#### **--format**=*format*

Change the default output format. This can be of a supported type like 'json' or a Go template.
Valid placeholders for the Go template are listed below:

| **Placeholder** | **Description** |
| --------------- | -------------------------------------- |
| .Unit | Name of the systemd unit |
| .ContainerName | Name of the container |
| .ContainerID | ID of the container |
| .Container | ID and name of the container |
| .Image | Name of the image |
| .Policy | Auto-update policy of the container |
| .Updated | Update status: true,false,failed |


## EXAMPLES
Autoupdate with registry policy

Expand All @@ -53,7 +69,7 @@ bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d
### Generate a systemd unit for this container
$ podman generate systemd --new --files bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d
/home/user/containers/libpod/container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service
/home/user/container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service
### Load the new systemd unit and start it
$ mv ./container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service ~/.config/systemd/user
Expand All @@ -67,7 +83,7 @@ $ systemctl --user start container-bc219740a210455fa27deacc96d50a9e20516492f1417
### Auto-update the container
$ podman auto-update
container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service
[...]
```

Autoupdate with local policy
Expand All @@ -80,7 +96,7 @@ be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338
### Generate a systemd unit for this container
$ podman generate systemd --new --files be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338
/home/user/containers/libpod/container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service
/home/user/container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service
### Load the new systemd unit and start it
$ mv ./container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service ~/.config/systemd/user
Expand All @@ -102,7 +118,7 @@ $ podman commit --change CMD=/bin/bash inspiring_galileo busybox:latest
### Auto-update the container
$ podman auto-update
container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service
[...]
```

## SEE ALSO
Expand Down
Loading

0 comments on commit 01cfb51

Please sign in to comment.