Skip to content

Commit

Permalink
auto-update: support authfiles
Browse files Browse the repository at this point in the history
Support using custom authfiles for auto updates by adding a new
`--authfile` flag and passing it down into the backend.

Also do some minor fixes in the help text and the man page.

Fixes: containers#6159
Signed-off-by: Valentin Rothberg <[email protected]>
  • Loading branch information
vrothberg authored and snj33v committed May 31, 2020
1 parent 9d78546 commit eb89a16
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 22 deletions.
20 changes: 13 additions & 7 deletions cmd/podman/auto-update.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"

"github.com/containers/common/pkg/auth"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/errorhandling"
Expand All @@ -11,16 +12,18 @@ import (
)

var (
autoUpdateOptions = entities.AutoUpdateOptions{}
autoUpdateDescription = `Auto update containers according to their auto-update policy.
Auto-update policies are specified with the "io.containers.autoupdate" label.
Note that this command is experimental.`
Note that this command is experimental. Please refer to the podman-auto-update(1) man page for details.`
autoUpdateCommand = &cobra.Command{
Use: "auto-update [flags]",
Short: "Auto update containers according to their auto-update policy",
Long: autoUpdateDescription,
RunE: autoUpdate,
Example: `podman auto-update`,
Use: "auto-update [flags]",
Short: "Auto update containers according to their auto-update policy",
Long: autoUpdateDescription,
RunE: autoUpdate,
Example: `podman auto-update
podman auto-update --authfile ~/authfile.json`,
}
)

Expand All @@ -29,14 +32,17 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode},
Command: autoUpdateCommand,
})

flags := autoUpdateCommand.Flags()
flags.StringVar(&autoUpdateOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path to the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
}

func autoUpdate(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
// Backwards compat. System tests expext this error string.
return errors.Errorf("`%s` takes no arguments", cmd.CommandPath())
}
report, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext())
report, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext(), autoUpdateOptions)
if report != nil {
for _, unit := range report.Units {
fmt.Println(unit)
Expand Down
21 changes: 21 additions & 0 deletions completions/bash/podman
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,27 @@ __podman_images() {
__podman_q images $images_args | awk "$awk_script" | grep -v '<none>$'
}

_podman_auto_update() {
local options_with_args="
--authfile
"

local boolean_options="
--help
-h
"

_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
-*)
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
;;
*)
__podman_complete_volume_names
;;
esac
}

# __podman_complete_volumes applies completion of volumes based on the current
# value of `$cur` or the value of the optional first option `--cur`, if given.
__podman_complete_volumes() {
Expand Down
12 changes: 11 additions & 1 deletion docs/source/markdown/podman-auto-update.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,21 @@ Note that `podman auto-update` relies on systemd and requires a fully-qualified
This enforcement is necessary to know which image to actually check and pull.
If an image ID was used, Podman would not know which image to check/pull anymore.

## OPTIONS

**--authfile**=*path*

Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. (Not available for remote commands)

Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
environment variable. `export REGISTRY_AUTH_FILE=path`

## EXAMPLES

```
# Start a container
$ podman run -d busybox:latest top
$ podman run --label "io.containers.autoupdate=image" -d busybox:latest top
bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d
# Generate a systemd unit for this container
Expand Down
25 changes: 15 additions & 10 deletions pkg/autoupdate/autoupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ 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
Expand Down Expand Up @@ -96,7 +102,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(runtime *libpod.Runtime) ([]string, []error) {
func AutoUpdate(runtime *libpod.Runtime, options Options) ([]string, []error) {
// Create a map from `image ID -> []*Container`.
containerMap, errs := imageContainersMap(runtime)
if len(containerMap) == 0 {
Expand Down Expand Up @@ -138,7 +144,7 @@ func AutoUpdate(runtime *libpod.Runtime) ([]string, []error) {
if rawImageName == "" {
errs = append(errs, errors.Errorf("error auto-updating container %q: raw-image name is empty", ctr.ID()))
}
needsUpdate, err := newerImageAvailable(runtime, image, rawImageName)
needsUpdate, err := newerImageAvailable(runtime, image, rawImageName, options)
if err != nil {
errs = append(errs, errors.Wrapf(err, "error auto-updating container %q: image check for %q failed", ctr.ID(), rawImageName))
continue
Expand All @@ -148,7 +154,7 @@ func AutoUpdate(runtime *libpod.Runtime) ([]string, []error) {
}
logrus.Infof("Auto-updating container %q using image %q", ctr.ID(), rawImageName)
if _, updated := updatedRawImages[rawImageName]; !updated {
_, err = updateImage(runtime, rawImageName)
_, err = updateImage(runtime, rawImageName, options)
if err != nil {
errs = append(errs, errors.Wrapf(err, "error auto-updating container %q: image update for %q failed", ctr.ID(), rawImageName))
continue
Expand Down Expand Up @@ -230,13 +236,15 @@ func imageContainersMap(runtime *libpod.Runtime) (map[string][]*libpod.Container

// newerImageAvailable returns true if there corresponding image on the remote
// registry is newer.
func newerImageAvailable(runtime *libpod.Runtime, img *image.Image, origName string) (bool, error) {
func newerImageAvailable(runtime *libpod.Runtime, img *image.Image, origName string, options Options) (bool, error) {
remoteRef, err := docker.ParseReference("//" + origName)
if err != nil {
return false, err
}

remoteImg, err := remoteRef.NewImage(context.Background(), runtime.SystemContext())
sys := runtime.SystemContext()
sys.AuthFilePath = options.Authfile
remoteImg, err := remoteRef.NewImage(context.Background(), sys)
if err != nil {
return false, err
}
Expand All @@ -255,25 +263,22 @@ func newerImageAvailable(runtime *libpod.Runtime, img *image.Image, origName str
}

// updateImage pulls the specified image.
func updateImage(runtime *libpod.Runtime, name string) (*image.Image, error) {
func updateImage(runtime *libpod.Runtime, name string, options Options) (*image.Image, error) {
sys := runtime.SystemContext()
registryOpts := image.DockerRegistryOptions{}
signaturePolicyPath := ""
authFilePath := ""

if sys != nil {
registryOpts.OSChoice = sys.OSChoice
registryOpts.ArchitectureChoice = sys.OSChoice
registryOpts.DockerCertPath = sys.DockerCertPath

signaturePolicyPath = sys.SignaturePolicyPath
authFilePath = sys.AuthFilePath
}

newImage, err := runtime.ImageRuntime().New(context.Background(),
docker.Transport.Name()+"://"+name,
signaturePolicyPath,
authFilePath,
options.Authfile,
os.Stderr,
&registryOpts,
image.SigningOptions{},
Expand Down
6 changes: 6 additions & 0 deletions pkg/domain/entities/auto-update.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package entities

// AutoUpdateOptions are the options for running auto-update.
type AutoUpdateOptions struct {
// Authfile to use when contacting registries.
Authfile string
}

// AutoUpdateReport contains the results from running auto-update.
type AutoUpdateReport struct {
// Units - the restarted systemd units during auto-update.
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/entities/engine_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

type ContainerEngine interface {
AutoUpdate(ctx context.Context) (*AutoUpdateReport, []error)
AutoUpdate(ctx context.Context, options AutoUpdateOptions) (*AutoUpdateReport, []error)
Config(ctx context.Context) (*config.Config, error)
ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
Expand Down
8 changes: 6 additions & 2 deletions pkg/domain/infra/abi/auto-update.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
)

func (ic *ContainerEngine) AutoUpdate(ctx context.Context) (*entities.AutoUpdateReport, []error) {
units, failures := autoupdate.AutoUpdate(ic.Libpod)
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}
units, failures := autoupdate.AutoUpdate(ic.Libpod, autoOpts)
return &entities.AutoUpdateReport{Units: units}, failures
}
2 changes: 1 addition & 1 deletion pkg/domain/infra/tunnel/auto-update.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import (
"github.com/pkg/errors"
)

func (ic *ContainerEngine) AutoUpdate(ctx context.Context) (*entities.AutoUpdateReport, []error) {
func (ic *ContainerEngine) AutoUpdate(ctx context.Context, options entities.AutoUpdateOptions) (*entities.AutoUpdateReport, []error) {
return nil, []error{errors.New("not implemented")}
}

0 comments on commit eb89a16

Please sign in to comment.