diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go index 6ccf4e1670..9622088d53 100644 --- a/cmd/podman/auto-update.go +++ b/cmd/podman/auto-update.go @@ -53,6 +53,8 @@ func init() { 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.BoolVar(&autoUpdateOptions.DryRun, "dry-run", false, "Check for pending updates") + flags.StringVar(&autoUpdateOptions.format, "format", "", "Change the output format to JSON or a Go template") _ = autoUpdateCommand.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(autoUpdateOutput{})) } diff --git a/docs/source/markdown/podman-auto-update.1.md b/docs/source/markdown/podman-auto-update.1.md index 4f2608be4a..106b9b00aa 100644 --- a/docs/source/markdown/podman-auto-update.1.md +++ b/docs/source/markdown/podman-auto-update.1.md @@ -41,6 +41,11 @@ 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_**. +#### **--dry-run**=*true|false* + +Check for the availability of new images but do not perform any pull operation or restart any service or container. +The `UPDATED` field indicates the availability of a new image with "pending". + #### **--format**=*format* Change the default output format. This can be of a supported type like 'json' or a Go template. @@ -64,7 +69,7 @@ Autoupdate with registry policy ### Start a container $ podman run --label "io.containers.autoupdate=registry" \ --label "io.containers.autoupdate.authfile=/some/authfile.json" \ - -d busybox:latest top + -d --name=test registry.fedoraproject.org/fedora:latest sleep infinity bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d ### Generate a systemd unit for this container @@ -72,18 +77,23 @@ $ podman generate systemd --new --files bc219740a210455fa27deacc96d50a9e20516492 /home/user/container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service ### Load the new systemd unit and start it -$ mv ./container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service ~/.config/systemd/user +$ mv ./container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service ~/.config/systemd/user/container-test.service $ systemctl --user daemon-reload ### If the previously created containers or pods are using shared resources, such as ports, make sure to remove them before starting the generated systemd units. $ podman stop bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d $ podman rm bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d -$ systemctl --user start container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service +$ systemctl --user start container-test.service -### Auto-update the container +### Check if a newer image is available +$ podman auto-update --dry-run --format "{{.Image}} {{.Updated}}" +registry.fedoraproject.org/fedora:latest pending + +### Autoupdate the services $ podman auto-update -[...] +UNIT CONTAINER IMAGE POLICY UPDATED +container-test.service 08fd34e533fd (test) registry.fedoraproject.org/fedora:latest registry false ``` Autoupdate with local policy diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index fd95c319c2..c51e2cd03a 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -75,12 +75,6 @@ func LookupPolicy(s string) (Policy, error) { return "", errors.Errorf("invalid auto-update policy %q: valid policies are %+q", s, keys) } -// Options include parameters for auto updates. -type Options struct { - // Authfile to use when contacting registries. - Authfile string -} - // ValidateImageReference checks if the specified imageName is a fully-qualified // image reference to the docker transport (without digest). Such a reference // includes a domain, name and tag (e.g., quay.io/podman/stable:latest). The @@ -120,7 +114,7 @@ func ValidateImageReference(imageName string) error { // // It returns a slice of successfully restarted systemd units and a slice of // errors encountered during auto update. -func AutoUpdate(ctx context.Context, runtime *libpod.Runtime, options Options) ([]*entities.AutoUpdateReport, []error) { +func AutoUpdate(ctx context.Context, runtime *libpod.Runtime, options entities.AutoUpdateOptions) ([]*entities.AutoUpdateReport, []error) { // Create a map from `image ID -> []*Container`. containerMap, errs := imageContainersMap(runtime) if len(containerMap) == 0 { @@ -183,7 +177,7 @@ func AutoUpdate(ctx context.Context, runtime *libpod.Runtime, options Options) ( } // autoUpdateRegistry updates the image/container according to the "registry" policy. -func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod.Container, updatedRawImages map[string]bool, options *Options, conn *dbus.Conn, runtime *libpod.Runtime) (*entities.AutoUpdateReport, error) { +func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod.Container, updatedRawImages map[string]bool, options *entities.AutoUpdateOptions, conn *dbus.Conn, runtime *libpod.Runtime) (*entities.AutoUpdateReport, error) { cid := ctr.ID() rawImageName := ctr.RawImageName() if rawImageName == "" { @@ -225,6 +219,11 @@ func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod. return report, nil } + if options.DryRun { + report.Updated = "pending" + return report, nil + } + if _, err := updateImage(ctx, runtime, rawImageName, options); err != nil { return report, errors.Wrapf(err, "error registry auto-updating container %q: image update for %q failed", cid, rawImageName) } @@ -240,7 +239,7 @@ func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod. } // autoUpdateRegistry updates the image/container according to the "local" policy. -func autoUpdateLocally(ctx context.Context, image *libimage.Image, ctr *libpod.Container, options *Options, conn *dbus.Conn, runtime *libpod.Runtime) (*entities.AutoUpdateReport, error) { +func autoUpdateLocally(ctx context.Context, image *libimage.Image, ctr *libpod.Container, options *entities.AutoUpdateOptions, conn *dbus.Conn, runtime *libpod.Runtime) (*entities.AutoUpdateReport, error) { cid := ctr.ID() rawImageName := ctr.RawImageName() if rawImageName == "" { @@ -272,6 +271,11 @@ func autoUpdateLocally(ctx context.Context, image *libimage.Image, ctr *libpod.C return report, nil } + if options.DryRun { + report.Updated = "pending" + return report, nil + } + logrus.Infof("Auto-updating container %q using local image %q", cid, rawImageName) if err := restartSystemdUnit(ctr, unit, conn); err != nil { return report, err @@ -346,7 +350,7 @@ func imageContainersMap(runtime *libpod.Runtime) (map[string]policyMapper, []err // getAuthfilePath returns an authfile path, if set. The authfile label in the // container, if set, as precedence over the one set in the options. -func getAuthfilePath(ctr *libpod.Container, options *Options) string { +func getAuthfilePath(ctr *libpod.Container, options *entities.AutoUpdateOptions) string { labels := ctr.Labels() authFilePath, exists := labels[AuthfileLabel] if exists { @@ -375,7 +379,7 @@ func newerLocalImageAvailable(runtime *libpod.Runtime, img *libimage.Image, rawI } // updateImage pulls the specified image. -func updateImage(ctx context.Context, runtime *libpod.Runtime, name string, options *Options) (*libimage.Image, error) { +func updateImage(ctx context.Context, runtime *libpod.Runtime, name string, options *entities.AutoUpdateOptions) (*libimage.Image, error) { pullOptions := &libimage.PullOptions{} pullOptions.AuthFilePath = options.Authfile pullOptions.Writer = os.Stderr diff --git a/pkg/domain/entities/auto-update.go b/pkg/domain/entities/auto-update.go index d74462b86c..eed617bf87 100644 --- a/pkg/domain/entities/auto-update.go +++ b/pkg/domain/entities/auto-update.go @@ -4,6 +4,10 @@ package entities type AutoUpdateOptions struct { // Authfile to use when contacting registries. Authfile string + // Only check for but do not perform any update. If an update is + // pending, it will be indicated in the Updated field of + // AutoUpdateReport. + DryRun bool } // AutoUpdateReport contains the results from running auto-update. @@ -18,7 +22,7 @@ type AutoUpdateReport struct { Policy string // SystemdUnit running a container configured for auto updates. SystemdUnit string - // Indicates whether the image was updated and the container (and - // systemd unit) restarted. + // Indicates the update status: true, false, failed, pending (see + // DryRun). Updated string } diff --git a/pkg/domain/infra/abi/auto-update.go b/pkg/domain/infra/abi/auto-update.go index daa882ecfd..b98ee1cb24 100644 --- a/pkg/domain/infra/abi/auto-update.go +++ b/pkg/domain/infra/abi/auto-update.go @@ -8,9 +8,5 @@ import ( ) func (ic *ContainerEngine) AutoUpdate(ctx context.Context, options entities.AutoUpdateOptions) ([]*entities.AutoUpdateReport, []error) { - // Convert the entities options to the autoupdate ones. We can't use - // them in the entities package as low-level packages must not leak - // into the remote client. - autoOpts := autoupdate.Options{Authfile: options.Authfile} - return autoupdate.AutoUpdate(ctx, ic.Libpod, autoOpts) + return autoupdate.AutoUpdate(ctx, ic.Libpod, options) } diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats index 4959bb6aa9..5e2d66af9d 100644 --- a/test/system/255-auto-update.bats +++ b/test/system/255-auto-update.bats @@ -121,6 +121,9 @@ function _confirm_update() { generate_service alpine image _wait_service_ready container-$cname.service + run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" + is "$output" ".*container-$cname.service,quay.io/libpod/alpine:latest,pending,registry.*" "Image update is pending." + run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" is "$output" "Trying to pull.*" "Image is updated." is "$output" ".*container-$cname.service,quay.io/libpod/alpine:latest,true,registry.*" "Image is updated." @@ -159,6 +162,9 @@ function _confirm_update() { imageID="$output" _wait_service_ready container-$cname.service + run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" + is "$output" ".*container-$cname.service,quay.io/libpod/localtest:latest,pending,local.*" "Image update is pending." + run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" is "$output" ".*container-$cname.service,quay.io/libpod/localtest:latest,true,local.*" "Image is updated."