github.com/moby/docker@v26.1.3+incompatible/daemon/update.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/docker/docker/api/types/container" 8 "github.com/docker/docker/api/types/events" 9 "github.com/docker/docker/errdefs" 10 "github.com/pkg/errors" 11 ) 12 13 // ContainerUpdate updates configuration of the container 14 func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error) { 15 var warnings []string 16 17 daemonCfg := daemon.config() 18 warnings, err := daemon.verifyContainerSettings(daemonCfg, hostConfig, nil, true) 19 if err != nil { 20 return container.ContainerUpdateOKBody{Warnings: warnings}, errdefs.InvalidParameter(err) 21 } 22 23 if err := daemon.update(name, hostConfig); err != nil { 24 return container.ContainerUpdateOKBody{Warnings: warnings}, err 25 } 26 27 return container.ContainerUpdateOKBody{Warnings: warnings}, nil 28 } 29 30 func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) error { 31 if hostConfig == nil { 32 return nil 33 } 34 35 ctr, err := daemon.GetContainer(name) 36 if err != nil { 37 return err 38 } 39 40 restoreConfig := false 41 backupHostConfig := *ctr.HostConfig 42 43 defer func() { 44 if restoreConfig { 45 ctr.Lock() 46 if !ctr.RemovalInProgress && !ctr.Dead { 47 ctr.HostConfig = &backupHostConfig 48 ctr.CheckpointTo(daemon.containersReplica) 49 } 50 ctr.Unlock() 51 } 52 }() 53 54 ctr.Lock() 55 56 if ctr.RemovalInProgress || ctr.Dead { 57 ctr.Unlock() 58 return errCannotUpdate(ctr.ID, fmt.Errorf(`container is marked for removal and cannot be "update"`)) 59 } 60 61 if err := ctr.UpdateContainer(hostConfig); err != nil { 62 restoreConfig = true 63 ctr.Unlock() 64 return errCannotUpdate(ctr.ID, err) 65 } 66 if err := ctr.CheckpointTo(daemon.containersReplica); err != nil { 67 restoreConfig = true 68 ctr.Unlock() 69 return errCannotUpdate(ctr.ID, err) 70 } 71 72 ctr.Unlock() 73 74 // if Restart Policy changed, we need to update container monitor 75 if hostConfig.RestartPolicy.Name != "" { 76 ctr.UpdateMonitor(hostConfig.RestartPolicy) 77 } 78 79 defer daemon.LogContainerEvent(ctr, events.ActionUpdate) 80 81 // If container is not running, update hostConfig struct is enough, 82 // resources will be updated when the container is started again. 83 // If container is running (including paused), we need to update configs 84 // to the real world. 85 ctr.Lock() 86 isRestarting := ctr.Restarting 87 tsk, err := ctr.GetRunningTask() 88 ctr.Unlock() 89 if errdefs.IsConflict(err) || isRestarting { 90 return nil 91 } 92 if err != nil { 93 return err 94 } 95 96 if err := tsk.UpdateResources(context.TODO(), toContainerdResources(hostConfig.Resources)); err != nil { 97 restoreConfig = true 98 // TODO: it would be nice if containerd responded with better errors here so we can classify this better. 99 return errCannotUpdate(ctr.ID, errdefs.System(err)) 100 } 101 102 return nil 103 } 104 105 func errCannotUpdate(containerID string, err error) error { 106 return errors.Wrap(err, "Cannot update container "+containerID) 107 }