github.com/dpiddy/docker@v1.12.2-rc1/daemon/create.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/Sirupsen/logrus"
     8  	"github.com/docker/docker/container"
     9  	"github.com/docker/docker/errors"
    10  	"github.com/docker/docker/image"
    11  	"github.com/docker/docker/layer"
    12  	"github.com/docker/docker/pkg/idtools"
    13  	"github.com/docker/docker/pkg/stringid"
    14  	"github.com/docker/docker/runconfig"
    15  	volumestore "github.com/docker/docker/volume/store"
    16  	"github.com/docker/engine-api/types"
    17  	containertypes "github.com/docker/engine-api/types/container"
    18  	networktypes "github.com/docker/engine-api/types/network"
    19  	"github.com/opencontainers/runc/libcontainer/label"
    20  )
    21  
    22  // CreateManagedContainer creates a container that is managed by a Service
    23  func (daemon *Daemon) CreateManagedContainer(params types.ContainerCreateConfig, validateHostname bool) (types.ContainerCreateResponse, error) {
    24  	return daemon.containerCreate(params, true, validateHostname)
    25  }
    26  
    27  // ContainerCreate creates a regular container
    28  func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig, validateHostname bool) (types.ContainerCreateResponse, error) {
    29  	return daemon.containerCreate(params, false, validateHostname)
    30  }
    31  
    32  func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, managed bool, validateHostname bool) (types.ContainerCreateResponse, error) {
    33  	if params.Config == nil {
    34  		return types.ContainerCreateResponse{}, fmt.Errorf("Config cannot be empty in order to create a container")
    35  	}
    36  
    37  	warnings, err := daemon.verifyContainerSettings(params.HostConfig, params.Config, false, validateHostname)
    38  	if err != nil {
    39  		return types.ContainerCreateResponse{Warnings: warnings}, err
    40  	}
    41  
    42  	err = daemon.verifyNetworkingConfig(params.NetworkingConfig)
    43  	if err != nil {
    44  		return types.ContainerCreateResponse{}, err
    45  	}
    46  
    47  	if params.HostConfig == nil {
    48  		params.HostConfig = &containertypes.HostConfig{}
    49  	}
    50  	err = daemon.adaptContainerSettings(params.HostConfig, params.AdjustCPUShares)
    51  	if err != nil {
    52  		return types.ContainerCreateResponse{Warnings: warnings}, err
    53  	}
    54  
    55  	container, err := daemon.create(params, managed)
    56  	if err != nil {
    57  		return types.ContainerCreateResponse{Warnings: warnings}, daemon.imageNotExistToErrcode(err)
    58  	}
    59  
    60  	return types.ContainerCreateResponse{ID: container.ID, Warnings: warnings}, nil
    61  }
    62  
    63  // Create creates a new container from the given configuration with a given name.
    64  func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (retC *container.Container, retErr error) {
    65  	var (
    66  		container *container.Container
    67  		img       *image.Image
    68  		imgID     image.ID
    69  		err       error
    70  	)
    71  
    72  	if params.Config.Image != "" {
    73  		img, err = daemon.GetImage(params.Config.Image)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		imgID = img.ID()
    78  	}
    79  
    80  	if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	if err := daemon.mergeAndVerifyLogConfig(&params.HostConfig.LogConfig); err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	if container, err = daemon.newContainer(params.Name, params.Config, imgID, managed); err != nil {
    89  		return nil, err
    90  	}
    91  	defer func() {
    92  		if retErr != nil {
    93  			if err := daemon.cleanupContainer(container, true); err != nil {
    94  				logrus.Errorf("failed to cleanup container on create error: %v", err)
    95  			}
    96  		}
    97  	}()
    98  
    99  	if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	container.HostConfig.StorageOpt = params.HostConfig.StorageOpt
   104  
   105  	// Set RWLayer for container after mount labels have been set
   106  	if err := daemon.setRWLayer(container); err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	if err := daemon.setHostConfig(container, params.HostConfig); err != nil {
   119  		return nil, err
   120  	}
   121  	defer func() {
   122  		if retErr != nil {
   123  			if err := daemon.removeMountPoints(container, true); err != nil {
   124  				logrus.Error(err)
   125  			}
   126  		}
   127  	}()
   128  
   129  	if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig); err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	var endpointsConfigs map[string]*networktypes.EndpointSettings
   134  	if params.NetworkingConfig != nil {
   135  		endpointsConfigs = params.NetworkingConfig.EndpointsConfig
   136  	}
   137  	// Make sure NetworkMode has an acceptable value. We do this to ensure
   138  	// backwards API compatibility.
   139  	container.HostConfig = runconfig.SetDefaultNetModeIfBlank(container.HostConfig)
   140  
   141  	if err := daemon.updateContainerNetworkSettings(container, endpointsConfigs); err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	if err := container.ToDisk(); err != nil {
   146  		logrus.Errorf("Error saving new container to disk: %v", err)
   147  		return nil, err
   148  	}
   149  	if err := daemon.Register(container); err != nil {
   150  		return nil, err
   151  	}
   152  	daemon.LogContainerEvent(container, "create")
   153  	return container, nil
   154  }
   155  
   156  func (daemon *Daemon) generateSecurityOpt(ipcMode containertypes.IpcMode, pidMode containertypes.PidMode, privileged bool) ([]string, error) {
   157  	if ipcMode.IsHost() || pidMode.IsHost() || privileged {
   158  		return label.DisableSecOpt(), nil
   159  	}
   160  
   161  	var ipcLabel []string
   162  	var pidLabel []string
   163  	ipcContainer := ipcMode.Container()
   164  	pidContainer := pidMode.Container()
   165  	if ipcContainer != "" {
   166  		c, err := daemon.GetContainer(ipcContainer)
   167  		if err != nil {
   168  			return nil, err
   169  		}
   170  		ipcLabel = label.DupSecOpt(c.ProcessLabel)
   171  		if pidContainer == "" {
   172  			return ipcLabel, err
   173  		}
   174  	}
   175  	if pidContainer != "" {
   176  		c, err := daemon.GetContainer(pidContainer)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  
   181  		pidLabel = label.DupSecOpt(c.ProcessLabel)
   182  		if ipcContainer == "" {
   183  			return pidLabel, err
   184  		}
   185  	}
   186  
   187  	if pidLabel != nil && ipcLabel != nil {
   188  		for i := 0; i < len(pidLabel); i++ {
   189  			if pidLabel[i] != ipcLabel[i] {
   190  				return nil, fmt.Errorf("--ipc and --pid containers SELinux labels aren't the same")
   191  			}
   192  		}
   193  		return pidLabel, nil
   194  	}
   195  	return nil, nil
   196  }
   197  
   198  func (daemon *Daemon) setRWLayer(container *container.Container) error {
   199  	var layerID layer.ChainID
   200  	if container.ImageID != "" {
   201  		img, err := daemon.imageStore.Get(container.ImageID)
   202  		if err != nil {
   203  			return err
   204  		}
   205  		layerID = img.RootFS.ChainID()
   206  	}
   207  	rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer, container.HostConfig.StorageOpt)
   208  	if err != nil {
   209  		return err
   210  	}
   211  	container.RWLayer = rwLayer
   212  
   213  	return nil
   214  }
   215  
   216  // VolumeCreate creates a volume with the specified name, driver, and opts
   217  // This is called directly from the remote API
   218  func (daemon *Daemon) VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error) {
   219  	if name == "" {
   220  		name = stringid.GenerateNonCryptoID()
   221  	}
   222  
   223  	v, err := daemon.volumes.Create(name, driverName, opts, labels)
   224  	if err != nil {
   225  		if volumestore.IsNameConflict(err) {
   226  			return nil, fmt.Errorf("A volume named %s already exists. Choose a different volume name.", name)
   227  		}
   228  		return nil, err
   229  	}
   230  
   231  	daemon.LogVolumeEvent(v.Name(), "create", map[string]string{"driver": v.DriverName()})
   232  	apiV := volumeToAPIType(v)
   233  	apiV.Mountpoint = v.Path()
   234  	return apiV, nil
   235  }
   236  
   237  func (daemon *Daemon) mergeAndVerifyConfig(config *containertypes.Config, img *image.Image) error {
   238  	if img != nil && img.Config != nil {
   239  		if err := merge(config, img.Config); err != nil {
   240  			return err
   241  		}
   242  	}
   243  	if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
   244  		return fmt.Errorf("No command specified")
   245  	}
   246  	return nil
   247  }
   248  
   249  // Checks if the client set configurations for more than one network while creating a container
   250  func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingConfig) error {
   251  	if nwConfig == nil || len(nwConfig.EndpointsConfig) <= 1 {
   252  		return nil
   253  	}
   254  	l := make([]string, 0, len(nwConfig.EndpointsConfig))
   255  	for k := range nwConfig.EndpointsConfig {
   256  		l = append(l, k)
   257  	}
   258  	err := fmt.Errorf("Container cannot be connected to network endpoints: %s", strings.Join(l, ", "))
   259  	return errors.NewBadRequestError(err)
   260  }