Merge pull request #6186 from vrothberg/auto-update

auto-update: support authfiles
This commit is contained in:
OpenShift Merge Robot
2020-05-12 03:13:12 -07:00
committed by GitHub
8 changed files with 74 additions and 22 deletions

View File

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/containers/common/pkg/auth"
"github.com/containers/libpod/cmd/podman/registry" "github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/errorhandling" "github.com/containers/libpod/pkg/errorhandling"
@ -11,16 +12,18 @@ import (
) )
var ( var (
autoUpdateOptions = entities.AutoUpdateOptions{}
autoUpdateDescription = `Auto update containers according to their auto-update policy. autoUpdateDescription = `Auto update containers according to their auto-update policy.
Auto-update policies are specified with the "io.containers.autoupdate" label. 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{ autoUpdateCommand = &cobra.Command{
Use: "auto-update [flags]", Use: "auto-update [flags]",
Short: "Auto update containers according to their auto-update policy", Short: "Auto update containers according to their auto-update policy",
Long: autoUpdateDescription, Long: autoUpdateDescription,
RunE: autoUpdate, RunE: autoUpdate,
Example: `podman auto-update`, Example: `podman auto-update
podman auto-update --authfile ~/authfile.json`,
} }
) )
@ -29,6 +32,9 @@ func init() {
Mode: []entities.EngineMode{entities.ABIMode}, Mode: []entities.EngineMode{entities.ABIMode},
Command: autoUpdateCommand, 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 { func autoUpdate(cmd *cobra.Command, args []string) error {
@ -36,7 +42,7 @@ func autoUpdate(cmd *cobra.Command, args []string) error {
// Backwards compat. System tests expext this error string. // Backwards compat. System tests expext this error string.
return errors.Errorf("`%s` takes no arguments", cmd.CommandPath()) 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 { if report != nil {
for _, unit := range report.Units { for _, unit := range report.Units {
fmt.Println(unit) fmt.Println(unit)

View File

@ -702,6 +702,27 @@ __podman_images() {
__podman_q images $images_args | awk "$awk_script" | grep -v '<none>$' __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 # __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. # value of `$cur` or the value of the optional first option `--cur`, if given.
__podman_complete_volumes() { __podman_complete_volumes() {

View File

@ -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. 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. 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 ## EXAMPLES
``` ```
# Start a container # Start a container
$ podman run -d busybox:latest top $ podman run --label "io.containers.autoupdate=image" -d busybox:latest top
bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d
# Generate a systemd unit for this container # Generate a systemd unit for this container

View File

@ -63,6 +63,12 @@ func LookupPolicy(s string) (Policy, error) {
return "", errors.Errorf("invalid auto-update policy %q: valid policies are %+q", s, keys) 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 // ValidateImageReference checks if the specified imageName is a fully-qualified
// image reference to the docker transport (without digest). Such a reference // 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 // includes a domain, name and tag (e.g., quay.io/podman/stable:latest). The
@ -96,7 +102,7 @@ func ValidateImageReference(imageName string) error {
// //
// It returns a slice of successfully restarted systemd units and a slice of // It returns a slice of successfully restarted systemd units and a slice of
// errors encountered during auto update. // 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`. // Create a map from `image ID -> []*Container`.
containerMap, errs := imageContainersMap(runtime) containerMap, errs := imageContainersMap(runtime)
if len(containerMap) == 0 { if len(containerMap) == 0 {
@ -138,7 +144,7 @@ func AutoUpdate(runtime *libpod.Runtime) ([]string, []error) {
if rawImageName == "" { if rawImageName == "" {
errs = append(errs, errors.Errorf("error auto-updating container %q: raw-image name is empty", ctr.ID())) 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 { if err != nil {
errs = append(errs, errors.Wrapf(err, "error auto-updating container %q: image check for %q failed", ctr.ID(), rawImageName)) errs = append(errs, errors.Wrapf(err, "error auto-updating container %q: image check for %q failed", ctr.ID(), rawImageName))
continue continue
@ -148,7 +154,7 @@ func AutoUpdate(runtime *libpod.Runtime) ([]string, []error) {
} }
logrus.Infof("Auto-updating container %q using image %q", ctr.ID(), rawImageName) logrus.Infof("Auto-updating container %q using image %q", ctr.ID(), rawImageName)
if _, updated := updatedRawImages[rawImageName]; !updated { if _, updated := updatedRawImages[rawImageName]; !updated {
_, err = updateImage(runtime, rawImageName) _, err = updateImage(runtime, rawImageName, options)
if err != nil { if err != nil {
errs = append(errs, errors.Wrapf(err, "error auto-updating container %q: image update for %q failed", ctr.ID(), rawImageName)) errs = append(errs, errors.Wrapf(err, "error auto-updating container %q: image update for %q failed", ctr.ID(), rawImageName))
continue continue
@ -230,13 +236,15 @@ func imageContainersMap(runtime *libpod.Runtime) (map[string][]*libpod.Container
// newerImageAvailable returns true if there corresponding image on the remote // newerImageAvailable returns true if there corresponding image on the remote
// registry is newer. // 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) remoteRef, err := docker.ParseReference("//" + origName)
if err != nil { if err != nil {
return false, err 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 { if err != nil {
return false, err return false, err
} }
@ -255,25 +263,22 @@ func newerImageAvailable(runtime *libpod.Runtime, img *image.Image, origName str
} }
// updateImage pulls the specified image. // 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() sys := runtime.SystemContext()
registryOpts := image.DockerRegistryOptions{} registryOpts := image.DockerRegistryOptions{}
signaturePolicyPath := "" signaturePolicyPath := ""
authFilePath := ""
if sys != nil { if sys != nil {
registryOpts.OSChoice = sys.OSChoice registryOpts.OSChoice = sys.OSChoice
registryOpts.ArchitectureChoice = sys.OSChoice registryOpts.ArchitectureChoice = sys.OSChoice
registryOpts.DockerCertPath = sys.DockerCertPath registryOpts.DockerCertPath = sys.DockerCertPath
signaturePolicyPath = sys.SignaturePolicyPath signaturePolicyPath = sys.SignaturePolicyPath
authFilePath = sys.AuthFilePath
} }
newImage, err := runtime.ImageRuntime().New(context.Background(), newImage, err := runtime.ImageRuntime().New(context.Background(),
docker.Transport.Name()+"://"+name, docker.Transport.Name()+"://"+name,
signaturePolicyPath, signaturePolicyPath,
authFilePath, options.Authfile,
os.Stderr, os.Stderr,
&registryOpts, &registryOpts,
image.SigningOptions{}, image.SigningOptions{},

View File

@ -1,5 +1,11 @@
package entities 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. // AutoUpdateReport contains the results from running auto-update.
type AutoUpdateReport struct { type AutoUpdateReport struct {
// Units - the restarted systemd units during auto-update. // Units - the restarted systemd units during auto-update.

View File

@ -10,7 +10,7 @@ import (
) )
type ContainerEngine interface { type ContainerEngine interface {
AutoUpdate(ctx context.Context) (*AutoUpdateReport, []error) AutoUpdate(ctx context.Context, options AutoUpdateOptions) (*AutoUpdateReport, []error)
Config(ctx context.Context) (*config.Config, error) Config(ctx context.Context) (*config.Config, error)
ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)

View File

@ -7,7 +7,11 @@ import (
"github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/domain/entities"
) )
func (ic *ContainerEngine) AutoUpdate(ctx context.Context) (*entities.AutoUpdateReport, []error) { func (ic *ContainerEngine) AutoUpdate(ctx context.Context, options entities.AutoUpdateOptions) (*entities.AutoUpdateReport, []error) {
units, failures := autoupdate.AutoUpdate(ic.Libpod) // 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 return &entities.AutoUpdateReport{Units: units}, failures
} }

View File

@ -7,6 +7,6 @@ import (
"github.com/pkg/errors" "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")} return nil, []error{errors.New("not implemented")}
} }