update.go 2.8 KB

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