spiegel_podman/cmd/podman/containers/update.go
Hayato Kihara f21dacc4fb cmd/podman: add --latest option to update #26380
Allow users to target the most recently created container with
`podman update --latest` (short `-l`). The same option already exists
on many other commands, so this brings update in line with the rest of
the CLI and saves users from typing or looking up the newest container.

Fixes: #26380

Signed-off-by: Hayato Kihara <kai.21banana@gmail.com>
2025-06-24 22:06:26 +09:00

199 lines
6.3 KiB
Go

package containers
import (
"context"
"fmt"
"strings"
"github.com/containers/podman/v5/cmd/podman/common"
"github.com/containers/podman/v5/cmd/podman/registry"
"github.com/containers/podman/v5/cmd/podman/validate"
"github.com/containers/podman/v5/libpod/define"
"github.com/containers/podman/v5/pkg/domain/entities"
"github.com/containers/podman/v5/pkg/specgen"
"github.com/containers/podman/v5/pkg/specgenutil"
"github.com/containers/podman/v5/pkg/util"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/spf13/cobra"
)
var (
updateDescription = `Updates the configuration of an existing container, allowing changes to resource limits and healthchecks`
updateCommand = &cobra.Command{
Use: "update [options] CONTAINER",
Short: "Update an existing container",
Long: updateDescription,
RunE: update,
Args: validate.IDOrLatestArgs,
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman update --cpus=5 foobar_container`,
}
containerUpdateCommand = &cobra.Command{
Args: updateCommand.Args,
Use: updateCommand.Use,
Short: updateCommand.Short,
Long: updateCommand.Long,
RunE: updateCommand.RunE,
ValidArgsFunction: updateCommand.ValidArgsFunction,
Example: `podman container update --cpus=5 foobar_container`,
}
)
type ContainerUpdateOptions struct {
entities.ContainerCreateOptions
Latest bool
}
var updateOptions ContainerUpdateOptions
func updateFlags(cmd *cobra.Command) {
common.DefineCreateDefaults(&updateOptions.ContainerCreateOptions)
common.DefineCreateFlags(cmd, &updateOptions.ContainerCreateOptions, entities.UpdateMode)
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: updateCommand,
})
updateFlags(updateCommand)
validate.AddLatestFlag(updateCommand, &updateOptions.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: containerUpdateCommand,
Parent: containerCmd,
})
updateFlags(containerUpdateCommand)
validate.AddLatestFlag(containerUpdateCommand, &updateOptions.Latest)
}
func GetChangedHealthCheckConfiguration(cmd *cobra.Command, vals *entities.ContainerCreateOptions) define.UpdateHealthCheckConfig {
updateHealthCheckConfig := define.UpdateHealthCheckConfig{}
if cmd.Flags().Changed("health-log-destination") {
updateHealthCheckConfig.HealthLogDestination = &vals.HealthLogDestination
}
if cmd.Flags().Changed("health-max-log-size") {
updateHealthCheckConfig.HealthMaxLogSize = &vals.HealthMaxLogSize
}
if cmd.Flags().Changed("health-max-log-count") {
updateHealthCheckConfig.HealthMaxLogCount = &vals.HealthMaxLogCount
}
if cmd.Flags().Changed("health-on-failure") {
updateHealthCheckConfig.HealthOnFailure = &vals.HealthOnFailure
}
if cmd.Flags().Changed("no-healthcheck") {
updateHealthCheckConfig.NoHealthCheck = &vals.NoHealthCheck
}
if cmd.Flags().Changed("health-cmd") {
updateHealthCheckConfig.HealthCmd = &vals.HealthCmd
}
if cmd.Flags().Changed("health-interval") {
updateHealthCheckConfig.HealthInterval = &vals.HealthInterval
}
if cmd.Flags().Changed("health-retries") {
updateHealthCheckConfig.HealthRetries = &vals.HealthRetries
}
if cmd.Flags().Changed("health-timeout") {
updateHealthCheckConfig.HealthTimeout = &vals.HealthTimeout
}
if cmd.Flags().Changed("health-start-period") {
updateHealthCheckConfig.HealthStartPeriod = &vals.HealthStartPeriod
}
if cmd.Flags().Changed("health-startup-cmd") {
updateHealthCheckConfig.HealthStartupCmd = &vals.StartupHCCmd
}
if cmd.Flags().Changed("health-startup-interval") {
updateHealthCheckConfig.HealthStartupInterval = &vals.StartupHCInterval
}
if cmd.Flags().Changed("health-startup-retries") {
updateHealthCheckConfig.HealthStartupRetries = &vals.StartupHCRetries
}
if cmd.Flags().Changed("health-startup-timeout") {
updateHealthCheckConfig.HealthStartupTimeout = &vals.StartupHCTimeout
}
if cmd.Flags().Changed("health-startup-success") {
updateHealthCheckConfig.HealthStartupSuccess = &vals.StartupHCSuccesses
}
return updateHealthCheckConfig
}
func GetChangedDeviceLimits(s *specgen.SpecGenerator) *define.UpdateContainerDevicesLimits {
updateDevicesLimits := define.UpdateContainerDevicesLimits{}
updateDevicesLimits.SetBlkIOWeightDevice(s.WeightDevice)
updateDevicesLimits.SetDeviceReadBPs(s.ThrottleReadBpsDevice)
updateDevicesLimits.SetDeviceWriteBPs(s.ThrottleWriteBpsDevice)
updateDevicesLimits.SetDeviceReadIOPs(s.ThrottleReadIOPSDevice)
updateDevicesLimits.SetDeviceWriteIOPs(s.ThrottleWriteIOPSDevice)
return &updateDevicesLimits
}
func update(cmd *cobra.Command, args []string) error {
var err error
// use a specgen since this is the easiest way to hold resource info
s := &specgen.SpecGenerator{}
s.ResourceLimits = &specs.LinuxResources{}
err = createOrUpdateFlags(cmd, &updateOptions.ContainerCreateOptions)
if err != nil {
return err
}
s.ResourceLimits, err = specgenutil.GetResources(s, &updateOptions.ContainerCreateOptions)
if err != nil {
return err
}
if s.ResourceLimits == nil {
s.ResourceLimits = &specs.LinuxResources{}
}
healthCheckConfig := GetChangedHealthCheckConfiguration(cmd, &updateOptions.ContainerCreateOptions)
opts := &entities.ContainerUpdateOptions{
Resources: s.ResourceLimits,
ChangedHealthCheckConfiguration: &healthCheckConfig,
DevicesLimits: GetChangedDeviceLimits(s),
Latest: updateOptions.Latest,
}
if !updateOptions.Latest {
opts.NameOrID = strings.TrimPrefix(args[0], "/")
}
if cmd.Flags().Changed("restart") {
policy, retries, err := util.ParseRestartPolicy(updateOptions.Restart)
if err != nil {
return err
}
opts.RestartPolicy = &policy
if policy == define.RestartPolicyOnFailure {
opts.RestartRetries = &retries
}
}
if cmd.Flags().Changed("env") {
env, err := cmd.Flags().GetStringArray("env")
if err != nil {
return err
}
opts.Env = env
}
if cmd.Flags().Changed("unsetenv") {
env, err := cmd.Flags().GetStringArray("unsetenv")
if err != nil {
return err
}
opts.UnsetEnv = env
}
rep, err := registry.ContainerEngine().ContainerUpdate(context.Background(), opts)
if err != nil {
return err
}
fmt.Println(rep)
return nil
}