mirror of
https://github.com/containers/podman.git
synced 2025-06-25 20:26:51 +08:00
Merge pull request #6186 from vrothberg/auto-update
auto-update: support authfiles
This commit is contained in:
@ -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)
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
®istryOpts,
|
®istryOpts,
|
||||||
image.SigningOptions{},
|
image.SigningOptions{},
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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")}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user