github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/daemon/create.go (about)

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