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