create.go 9.3 KB

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