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