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(¶ms.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 }