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(&params.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  }