podman-build/cmd/podman/containers/update.go
2025-10-11 12:30:35 +09:00

200 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
}