create.go 8.7 KB

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