github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/update.go (about)

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