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