mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-10-11 08:27:36 +00:00
Merge pull request #27025 from StefanNienhuis/feat/api-autoupdate
feat: Implement autoupdate endpoint in libpod REST API
This commit is contained in:
commit
9de95641de
13 changed files with 325 additions and 4 deletions
|
|
@ -31,7 +31,6 @@ var (
|
|||
or similar units that create new containers in order to run the updated images.
|
||||
Please refer to the podman-auto-update(1) man page for details.`
|
||||
autoUpdateCommand = &cobra.Command{
|
||||
Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
|
||||
Use: "auto-update [options]",
|
||||
Short: "Auto update containers according to their auto-update policy",
|
||||
Long: autoUpdateDescription,
|
||||
|
|
|
|||
|
|
@ -424,6 +424,11 @@ sub operation_name {
|
|||
$main = 'image';
|
||||
$action = $1;
|
||||
}
|
||||
# Top-level autoupdate endpoint
|
||||
elsif ($main eq 'autoupdate') {
|
||||
$main = 'autoupdate';
|
||||
$action = '';
|
||||
}
|
||||
# Top-level system endpoints
|
||||
elsif ($main =~ /^(auth|event|info|version)$/) {
|
||||
$main = 'system';
|
||||
|
|
|
|||
81
pkg/api/handlers/libpod/autoupdate.go
Normal file
81
pkg/api/handlers/libpod/autoupdate.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//go:build !remote && (linux || freebsd)
|
||||
|
||||
package libpod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/schema"
|
||||
"go.podman.io/image/v5/types"
|
||||
"go.podman.io/podman/v6/libpod"
|
||||
"go.podman.io/podman/v6/pkg/api/handlers"
|
||||
"go.podman.io/podman/v6/pkg/api/handlers/utils"
|
||||
api "go.podman.io/podman/v6/pkg/api/types"
|
||||
"go.podman.io/podman/v6/pkg/auth"
|
||||
"go.podman.io/podman/v6/pkg/domain/entities"
|
||||
"go.podman.io/podman/v6/pkg/domain/infra/abi"
|
||||
"go.podman.io/podman/v6/pkg/errorhandling"
|
||||
)
|
||||
|
||||
func AutoUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||
|
||||
query := struct {
|
||||
DryRun bool `schema:"dryRun"`
|
||||
Rollback bool `schema:"rollback"`
|
||||
TLSVerify types.OptionalBool `schema:"tlsVerify"`
|
||||
}{
|
||||
Rollback: true,
|
||||
}
|
||||
|
||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
|
||||
return
|
||||
}
|
||||
|
||||
_, authfile, err := auth.GetCredentials(r)
|
||||
if err != nil {
|
||||
utils.Error(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
defer auth.RemoveAuthfile(authfile)
|
||||
|
||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||
|
||||
options := entities.AutoUpdateOptions{
|
||||
Authfile: authfile,
|
||||
DryRun: query.DryRun,
|
||||
Rollback: query.Rollback,
|
||||
InsecureSkipTLSVerify: types.OptionalBoolUndefined,
|
||||
}
|
||||
|
||||
// If TLS verification is explicitly specified (True or False) in the query,
|
||||
// set the InsecureSkipTLSVerify option accordingly.
|
||||
// If TLSVerify was not set in the query, OptionalBoolUndefined is used and
|
||||
// handled later based off the target registry configuration.
|
||||
switch query.TLSVerify {
|
||||
case types.OptionalBoolTrue:
|
||||
options.InsecureSkipTLSVerify = types.NewOptionalBool(false)
|
||||
case types.OptionalBoolFalse:
|
||||
options.InsecureSkipTLSVerify = types.NewOptionalBool(true)
|
||||
case types.OptionalBoolUndefined:
|
||||
// If the user doesn't define TLSVerify in the query, do nothing and pass
|
||||
// it to the backend code to handle.
|
||||
default: // Should never happen
|
||||
panic("Unexpected handling occurred for TLSVerify")
|
||||
}
|
||||
|
||||
autoUpdateReports, autoUpdateFailures := containerEngine.AutoUpdate(r.Context(), options)
|
||||
if autoUpdateReports == nil {
|
||||
if err := errorhandling.JoinErrors(autoUpdateFailures); err != nil {
|
||||
utils.Error(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
reports := handlers.LibpodAutoUpdateReports{Reports: autoUpdateReports, Errors: errorhandling.ErrorsToStrings(autoUpdateFailures)}
|
||||
|
||||
utils.WriteResponse(w, http.StatusOK, reports)
|
||||
}
|
||||
|
|
@ -532,3 +532,10 @@ type quadletRemoveResponse struct {
|
|||
// in:body
|
||||
Body entities.QuadletRemoveReport
|
||||
}
|
||||
|
||||
// Auto Update
|
||||
// swagger:response
|
||||
type autoupdateResponse struct {
|
||||
// in:body
|
||||
Body handlers.LibpodAutoUpdateReports
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,3 +249,10 @@ type ExecStartConfig struct {
|
|||
type ExecRemoveConfig struct {
|
||||
Force bool `json:"Force"`
|
||||
}
|
||||
|
||||
// LibpodAutoUpdateReport is the return type for auto update via the rest api.
|
||||
type LibpodAutoUpdateReports struct {
|
||||
Reports []*entities.AutoUpdateReport
|
||||
// Auto update returns data and possible errors.
|
||||
Errors []string
|
||||
}
|
||||
|
|
|
|||
52
pkg/api/server/register_autoupdate.go
Normal file
52
pkg/api/server/register_autoupdate.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//go:build !remote
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"go.podman.io/podman/v6/pkg/api/handlers/libpod"
|
||||
)
|
||||
|
||||
func (s *APIServer) registerAutoUpdateHandlers(r *mux.Router) error {
|
||||
// swagger:operation POST /libpod/autoupdate libpod AutoupdateLibpod
|
||||
// ---
|
||||
// tags:
|
||||
// - autoupdate
|
||||
// summary: Auto update
|
||||
// description: |
|
||||
// Auto update containers according to their auto-update policy.
|
||||
//
|
||||
// Auto-update policies are specified with the "io.containers.autoupdate" label.
|
||||
// Containers are expected to run in systemd units created with "podman-generate-systemd --new",
|
||||
// or similar units that create new containers in order to run the updated images.
|
||||
// Please refer to the podman-auto-update(1) man page for details.
|
||||
// parameters:
|
||||
// - in: query
|
||||
// name: authfile
|
||||
// type: string
|
||||
// description: Authfile to use when contacting registries.
|
||||
// - in: query
|
||||
// name: dryRun
|
||||
// type: boolean
|
||||
// description: Only check for but do not perform any update. If an update is pending, it will be indicated in the Updated field.
|
||||
// - in: query
|
||||
// name: rollback
|
||||
// type: boolean
|
||||
// description: If restarting the service with the new image failed, restart it another time with the previous image.
|
||||
// - in: query
|
||||
// name: tlsVerify
|
||||
// type: boolean
|
||||
// default: true
|
||||
// description: Require HTTPS and verify signatures when contacting registries.
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
// 200:
|
||||
// $ref: "#/responses/autoupdateResponse"
|
||||
// 500:
|
||||
// $ref: '#/responses/internalError'
|
||||
r.HandleFunc(VersionedPath("/libpod/autoupdate"), s.APIHandler(libpod.AutoUpdate)).Methods(http.MethodPost)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -148,6 +148,7 @@ func newServer(runtime *libpod.Runtime, listener net.Listener, opts entities.Ser
|
|||
server.registerAuthHandlers,
|
||||
server.registerArtifactHandlers,
|
||||
server.registerArchiveHandlers,
|
||||
server.registerAutoUpdateHandlers,
|
||||
server.registerContainersHandlers,
|
||||
server.registerDistributionHandlers,
|
||||
server.registerEventsHandlers,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
tags:
|
||||
- name: artifacts
|
||||
description: Actions related to artifacts
|
||||
- name: autoupdate
|
||||
description: Actions related to auto update
|
||||
- name: containers
|
||||
description: Actions related to containers
|
||||
- name: exec
|
||||
|
|
|
|||
54
pkg/bindings/auto-update/auto-update.go
Normal file
54
pkg/bindings/auto-update/auto-update.go
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package autoupdate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
imageTypes "go.podman.io/image/v5/types"
|
||||
"go.podman.io/podman/v6/pkg/api/handlers"
|
||||
"go.podman.io/podman/v6/pkg/auth"
|
||||
"go.podman.io/podman/v6/pkg/bindings"
|
||||
"go.podman.io/podman/v6/pkg/domain/entities"
|
||||
"go.podman.io/podman/v6/pkg/errorhandling"
|
||||
)
|
||||
|
||||
func AutoUpdate(ctx context.Context, options *AutoUpdateOptions) ([]*entities.AutoUpdateReport, []error) {
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
if options == nil {
|
||||
options = new(AutoUpdateOptions)
|
||||
}
|
||||
|
||||
params, err := options.ToParams()
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
// InsecureSkipTLSVerify is special. We need to delete the param added by
|
||||
// ToParams() and change the key and flip the bool
|
||||
if options.InsecureSkipTLSVerify != nil {
|
||||
params.Del("SkipTLSVerify")
|
||||
params.Set("tlsVerify", strconv.FormatBool(!options.GetInsecureSkipTLSVerify()))
|
||||
}
|
||||
|
||||
header, err := auth.MakeXRegistryAuthHeader(&imageTypes.SystemContext{AuthFilePath: options.GetAuthfile()}, "", "")
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
|
||||
response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/autoupdate", params, header)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
var reports handlers.LibpodAutoUpdateReports
|
||||
|
||||
if err := response.Process(&reports); err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
|
||||
return reports.Reports, errorhandling.StringsToErrors(reports.Errors)
|
||||
}
|
||||
19
pkg/bindings/auto-update/types.go
Normal file
19
pkg/bindings/auto-update/types.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package autoupdate
|
||||
|
||||
// AutoUpdateOptions are the options for running auto-update
|
||||
//
|
||||
//go:generate go run ../generator/generator.go AutoUpdateOptions
|
||||
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
|
||||
// If restarting the service with the new image failed, restart it
|
||||
// another time with the previous image.
|
||||
Rollback *bool
|
||||
// Allow contacting registries over HTTP, or HTTPS with failed TLS
|
||||
// verification. Note that this does not affect other TLS connections.
|
||||
InsecureSkipTLSVerify *bool
|
||||
}
|
||||
78
pkg/bindings/auto-update/types_autoupdate_options.go
Normal file
78
pkg/bindings/auto-update/types_autoupdate_options.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
package autoupdate
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"go.podman.io/podman/v6/pkg/bindings/internal/util"
|
||||
)
|
||||
|
||||
// Changed returns true if named field has been set
|
||||
func (o *AutoUpdateOptions) Changed(fieldName string) bool {
|
||||
return util.Changed(o, fieldName)
|
||||
}
|
||||
|
||||
// ToParams formats struct fields to be passed to API service
|
||||
func (o *AutoUpdateOptions) ToParams() (url.Values, error) {
|
||||
return util.ToParams(o)
|
||||
}
|
||||
|
||||
// WithAuthfile set field Authfile to given value
|
||||
func (o *AutoUpdateOptions) WithAuthfile(value string) *AutoUpdateOptions {
|
||||
o.Authfile = &value
|
||||
return o
|
||||
}
|
||||
|
||||
// GetAuthfile returns value of field Authfile
|
||||
func (o *AutoUpdateOptions) GetAuthfile() string {
|
||||
if o.Authfile == nil {
|
||||
var z string
|
||||
return z
|
||||
}
|
||||
return *o.Authfile
|
||||
}
|
||||
|
||||
// WithDryRun set field DryRun to given value
|
||||
func (o *AutoUpdateOptions) WithDryRun(value bool) *AutoUpdateOptions {
|
||||
o.DryRun = &value
|
||||
return o
|
||||
}
|
||||
|
||||
// GetDryRun returns value of field DryRun
|
||||
func (o *AutoUpdateOptions) GetDryRun() bool {
|
||||
if o.DryRun == nil {
|
||||
var z bool
|
||||
return z
|
||||
}
|
||||
return *o.DryRun
|
||||
}
|
||||
|
||||
// WithRollback set field Rollback to given value
|
||||
func (o *AutoUpdateOptions) WithRollback(value bool) *AutoUpdateOptions {
|
||||
o.Rollback = &value
|
||||
return o
|
||||
}
|
||||
|
||||
// GetRollback returns value of field Rollback
|
||||
func (o *AutoUpdateOptions) GetRollback() bool {
|
||||
if o.Rollback == nil {
|
||||
var z bool
|
||||
return z
|
||||
}
|
||||
return *o.Rollback
|
||||
}
|
||||
|
||||
// WithInsecureSkipTLSVerify set field InsecureSkipTLSVerify to given value
|
||||
func (o *AutoUpdateOptions) WithInsecureSkipTLSVerify(value bool) *AutoUpdateOptions {
|
||||
o.InsecureSkipTLSVerify = &value
|
||||
return o
|
||||
}
|
||||
|
||||
// GetInsecureSkipTLSVerify returns value of field InsecureSkipTLSVerify
|
||||
func (o *AutoUpdateOptions) GetInsecureSkipTLSVerify() bool {
|
||||
if o.InsecureSkipTLSVerify == nil {
|
||||
var z bool
|
||||
return z
|
||||
}
|
||||
return *o.InsecureSkipTLSVerify
|
||||
}
|
||||
|
|
@ -2,11 +2,21 @@ package tunnel
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"go.podman.io/image/v5/types"
|
||||
autoupdate "go.podman.io/podman/v6/pkg/bindings/auto-update"
|
||||
"go.podman.io/podman/v6/pkg/domain/entities"
|
||||
)
|
||||
|
||||
func (ic *ContainerEngine) AutoUpdate(_ context.Context, _ entities.AutoUpdateOptions) ([]*entities.AutoUpdateReport, []error) {
|
||||
return nil, []error{errors.New("not implemented")}
|
||||
func (ic *ContainerEngine) AutoUpdate(_ context.Context, opts entities.AutoUpdateOptions) ([]*entities.AutoUpdateReport, []error) {
|
||||
options := new(autoupdate.AutoUpdateOptions).WithAuthfile(opts.Authfile).WithDryRun(opts.DryRun).WithRollback(opts.Rollback)
|
||||
if s := opts.InsecureSkipTLSVerify; s != types.OptionalBoolUndefined {
|
||||
if s == types.OptionalBoolTrue {
|
||||
options.WithInsecureSkipTLSVerify(true)
|
||||
} else {
|
||||
options.WithInsecureSkipTLSVerify(false)
|
||||
}
|
||||
}
|
||||
|
||||
return autoupdate.AutoUpdate(ic.ClientCtx, options)
|
||||
}
|
||||
|
|
|
|||
6
test/apiv2/37-autoupdate.at
Normal file
6
test/apiv2/37-autoupdate.at
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# -*- sh -*-
|
||||
#
|
||||
# test 'autoupdate' endpoint
|
||||
#
|
||||
|
||||
t POST libpod/autoupdate 200
|
||||
Loading…
Add table
Reference in a new issue