github.com/kim0/docker@v0.6.2-0.20161130212042-4addda3f07e7/daemon/create.go (about)

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