update.go 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package 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. c, err := daemon.GetContainer(name)
  13. if err != nil {
  14. return container.ContainerUpdateOKBody{Warnings: warnings}, err
  15. }
  16. warnings, err = daemon.verifyContainerSettings(c.OS, hostConfig, nil, true)
  17. if err != nil {
  18. return container.ContainerUpdateOKBody{Warnings: warnings}, errdefs.InvalidParameter(err)
  19. }
  20. if err := daemon.update(name, hostConfig); err != nil {
  21. return container.ContainerUpdateOKBody{Warnings: warnings}, err
  22. }
  23. return container.ContainerUpdateOKBody{Warnings: warnings}, nil
  24. }
  25. func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) error {
  26. if hostConfig == nil {
  27. return nil
  28. }
  29. container, err := daemon.GetContainer(name)
  30. if err != nil {
  31. return err
  32. }
  33. restoreConfig := false
  34. backupHostConfig := *container.HostConfig
  35. defer func() {
  36. if restoreConfig {
  37. container.Lock()
  38. container.HostConfig = &backupHostConfig
  39. container.CheckpointTo(daemon.containersReplica)
  40. container.Unlock()
  41. }
  42. }()
  43. if container.RemovalInProgress || container.Dead {
  44. return errCannotUpdate(container.ID, fmt.Errorf("container is marked for removal and cannot be \"update\""))
  45. }
  46. container.Lock()
  47. if err := container.UpdateContainer(hostConfig); err != nil {
  48. restoreConfig = true
  49. container.Unlock()
  50. return errCannotUpdate(container.ID, err)
  51. }
  52. if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  53. restoreConfig = true
  54. container.Unlock()
  55. return errCannotUpdate(container.ID, err)
  56. }
  57. container.Unlock()
  58. // if Restart Policy changed, we need to update container monitor
  59. if hostConfig.RestartPolicy.Name != "" {
  60. container.UpdateMonitor(hostConfig.RestartPolicy)
  61. }
  62. // If container is not running, update hostConfig struct is enough,
  63. // resources will be updated when the container is started again.
  64. // If container is running (including paused), we need to update configs
  65. // to the real world.
  66. if container.IsRunning() && !container.IsRestarting() {
  67. if err := daemon.containerd.UpdateResources(context.Background(), container.ID, toContainerdResources(hostConfig.Resources)); err != nil {
  68. restoreConfig = true
  69. // TODO: it would be nice if containerd responded with better errors here so we can classify this better.
  70. return errCannotUpdate(container.ID, errdefs.System(err))
  71. }
  72. }
  73. daemon.LogContainerEvent(container, "update")
  74. return nil
  75. }
  76. func errCannotUpdate(containerID string, err error) error {
  77. return errors.Wrap(err, "Cannot update container "+containerID)
  78. }