container.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. package container // import "github.com/docker/docker/daemon/cluster/executor/container"
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "strconv"
  8. "strings"
  9. "github.com/containerd/log"
  10. "github.com/distribution/reference"
  11. "github.com/docker/docker/api/types"
  12. enginecontainer "github.com/docker/docker/api/types/container"
  13. "github.com/docker/docker/api/types/events"
  14. "github.com/docker/docker/api/types/filters"
  15. enginemount "github.com/docker/docker/api/types/mount"
  16. "github.com/docker/docker/api/types/network"
  17. "github.com/docker/docker/api/types/volume"
  18. "github.com/docker/docker/daemon/cluster/convert"
  19. executorpkg "github.com/docker/docker/daemon/cluster/executor"
  20. clustertypes "github.com/docker/docker/daemon/cluster/provider"
  21. "github.com/docker/docker/libnetwork/scope"
  22. "github.com/docker/go-connections/nat"
  23. "github.com/docker/go-units"
  24. gogotypes "github.com/gogo/protobuf/types"
  25. "github.com/moby/swarmkit/v2/agent/exec"
  26. "github.com/moby/swarmkit/v2/api"
  27. "github.com/moby/swarmkit/v2/api/genericresource"
  28. "github.com/moby/swarmkit/v2/template"
  29. )
  30. const (
  31. // systemLabelPrefix represents the reserved namespace for system labels.
  32. systemLabelPrefix = "com.docker.swarm"
  33. )
  34. // containerConfig converts task properties into docker container compatible
  35. // components.
  36. type containerConfig struct {
  37. task *api.Task
  38. networksAttachments map[string]*api.NetworkAttachment
  39. }
  40. // newContainerConfig returns a validated container config. No methods should
  41. // return an error if this function returns without error.
  42. func newContainerConfig(t *api.Task, node *api.NodeDescription) (*containerConfig, error) {
  43. var c containerConfig
  44. return &c, c.setTask(t, node)
  45. }
  46. func (c *containerConfig) setTask(t *api.Task, node *api.NodeDescription) error {
  47. if t.Spec.GetContainer() == nil && t.Spec.GetAttachment() == nil {
  48. return exec.ErrRuntimeUnsupported
  49. }
  50. container := t.Spec.GetContainer()
  51. if container != nil {
  52. if container.Image == "" {
  53. return ErrImageRequired
  54. }
  55. if err := validateMounts(container.Mounts); err != nil {
  56. return err
  57. }
  58. }
  59. // index the networks by name
  60. c.networksAttachments = make(map[string]*api.NetworkAttachment, len(t.Networks))
  61. for _, attachment := range t.Networks {
  62. c.networksAttachments[attachment.Network.Spec.Annotations.Name] = attachment
  63. }
  64. c.task = t
  65. if t.Spec.GetContainer() != nil {
  66. preparedSpec, err := template.ExpandContainerSpec(node, t)
  67. if err != nil {
  68. return err
  69. }
  70. c.task.Spec.Runtime = &api.TaskSpec_Container{
  71. Container: preparedSpec,
  72. }
  73. }
  74. return nil
  75. }
  76. func (c *containerConfig) networkAttachmentContainerID() string {
  77. attachment := c.task.Spec.GetAttachment()
  78. if attachment == nil {
  79. return ""
  80. }
  81. return attachment.ContainerID
  82. }
  83. func (c *containerConfig) taskID() string {
  84. return c.task.ID
  85. }
  86. func (c *containerConfig) spec() *api.ContainerSpec {
  87. return c.task.Spec.GetContainer()
  88. }
  89. func (c *containerConfig) nameOrID() string {
  90. if c.task.Spec.GetContainer() != nil {
  91. return c.name()
  92. }
  93. return c.networkAttachmentContainerID()
  94. }
  95. func (c *containerConfig) name() string {
  96. if c.task.Annotations.Name != "" {
  97. // if set, use the container Annotations.Name field, set in the orchestrator.
  98. return c.task.Annotations.Name
  99. }
  100. slot := fmt.Sprint(c.task.Slot)
  101. if slot == "" || c.task.Slot == 0 {
  102. slot = c.task.NodeID
  103. }
  104. // fallback to service.slot.id.
  105. return fmt.Sprintf("%s.%s.%s", c.task.ServiceAnnotations.Name, slot, c.task.ID)
  106. }
  107. func (c *containerConfig) image() string {
  108. raw := c.spec().Image
  109. ref, err := reference.ParseNormalizedNamed(raw)
  110. if err != nil {
  111. return raw
  112. }
  113. return reference.FamiliarString(reference.TagNameOnly(ref))
  114. }
  115. func (c *containerConfig) portBindings() nat.PortMap {
  116. portBindings := nat.PortMap{}
  117. if c.task.Endpoint == nil {
  118. return portBindings
  119. }
  120. for _, portConfig := range c.task.Endpoint.Ports {
  121. if portConfig.PublishMode != api.PublishModeHost {
  122. continue
  123. }
  124. port := nat.Port(fmt.Sprintf("%d/%s", portConfig.TargetPort, strings.ToLower(portConfig.Protocol.String())))
  125. binding := []nat.PortBinding{
  126. {},
  127. }
  128. if portConfig.PublishedPort != 0 {
  129. binding[0].HostPort = strconv.Itoa(int(portConfig.PublishedPort))
  130. }
  131. portBindings[port] = binding
  132. }
  133. return portBindings
  134. }
  135. func (c *containerConfig) isolation() enginecontainer.Isolation {
  136. return convert.IsolationFromGRPC(c.spec().Isolation)
  137. }
  138. func (c *containerConfig) init() *bool {
  139. if c.spec().Init == nil {
  140. return nil
  141. }
  142. init := c.spec().Init.GetValue()
  143. return &init
  144. }
  145. func (c *containerConfig) exposedPorts() map[nat.Port]struct{} {
  146. exposedPorts := make(map[nat.Port]struct{})
  147. if c.task.Endpoint == nil {
  148. return exposedPorts
  149. }
  150. for _, portConfig := range c.task.Endpoint.Ports {
  151. if portConfig.PublishMode != api.PublishModeHost {
  152. continue
  153. }
  154. port := nat.Port(fmt.Sprintf("%d/%s", portConfig.TargetPort, strings.ToLower(portConfig.Protocol.String())))
  155. exposedPorts[port] = struct{}{}
  156. }
  157. return exposedPorts
  158. }
  159. func (c *containerConfig) config() *enginecontainer.Config {
  160. genericEnvs := genericresource.EnvFormat(c.task.AssignedGenericResources, "DOCKER_RESOURCE")
  161. env := append(c.spec().Env, genericEnvs...)
  162. config := &enginecontainer.Config{
  163. Labels: c.labels(),
  164. StopSignal: c.spec().StopSignal,
  165. Tty: c.spec().TTY,
  166. OpenStdin: c.spec().OpenStdin,
  167. User: c.spec().User,
  168. Env: env,
  169. Hostname: c.spec().Hostname,
  170. WorkingDir: c.spec().Dir,
  171. Image: c.image(),
  172. ExposedPorts: c.exposedPorts(),
  173. Healthcheck: c.healthcheck(),
  174. }
  175. if len(c.spec().Command) > 0 {
  176. // If Command is provided, we replace the whole invocation with Command
  177. // by replacing Entrypoint and specifying Cmd. Args is ignored in this
  178. // case.
  179. config.Entrypoint = append(config.Entrypoint, c.spec().Command...)
  180. config.Cmd = append(config.Cmd, c.spec().Args...)
  181. } else if len(c.spec().Args) > 0 {
  182. // In this case, we assume the image has an Entrypoint and Args
  183. // specifies the arguments for that entrypoint.
  184. config.Cmd = c.spec().Args
  185. }
  186. return config
  187. }
  188. func (c *containerConfig) labels() map[string]string {
  189. var (
  190. system = map[string]string{
  191. "task": "", // mark as cluster task
  192. "task.id": c.task.ID,
  193. "task.name": c.name(),
  194. "node.id": c.task.NodeID,
  195. "service.id": c.task.ServiceID,
  196. "service.name": c.task.ServiceAnnotations.Name,
  197. }
  198. labels = make(map[string]string)
  199. )
  200. // base labels are those defined in the spec.
  201. for k, v := range c.spec().Labels {
  202. labels[k] = v
  203. }
  204. // we then apply the overrides from the task, which may be set via the
  205. // orchestrator.
  206. for k, v := range c.task.Annotations.Labels {
  207. labels[k] = v
  208. }
  209. // finally, we apply the system labels, which override all labels.
  210. for k, v := range system {
  211. labels[strings.Join([]string{systemLabelPrefix, k}, ".")] = v
  212. }
  213. return labels
  214. }
  215. func (c *containerConfig) mounts(deps exec.VolumeGetter) []enginemount.Mount {
  216. var r []enginemount.Mount
  217. for _, mount := range c.spec().Mounts {
  218. if mount.Type == api.MountTypeCluster {
  219. r = append(r, c.convertCSIMount(mount, deps))
  220. } else {
  221. r = append(r, convertMount(mount))
  222. }
  223. }
  224. return r
  225. }
  226. // convertCSIMount matches the CSI mount with the path of the CSI volume.
  227. //
  228. // technically quadratic with respect to the number of CSI mounts, but that
  229. // number shouldn't ever be large enough for quadratic to matter.
  230. //
  231. // TODO(dperny): figure out a scheme for errors? or maybe add code to
  232. // checkMounts?
  233. func (c *containerConfig) convertCSIMount(m api.Mount, deps exec.VolumeGetter) enginemount.Mount {
  234. var mount enginemount.Mount
  235. // these are actually bind mounts
  236. mount.Type = enginemount.TypeBind
  237. for _, attach := range c.task.Volumes {
  238. if attach.Source == m.Source && attach.Target == m.Target {
  239. // we should not get an error here, because we should have checked
  240. // already that the volume is ready
  241. path, _ := deps.Get(attach.ID)
  242. mount.Source = path
  243. mount.Target = m.Target
  244. }
  245. }
  246. return mount
  247. }
  248. func convertMount(m api.Mount) enginemount.Mount {
  249. mount := enginemount.Mount{
  250. Source: m.Source,
  251. Target: m.Target,
  252. ReadOnly: m.ReadOnly,
  253. }
  254. switch m.Type {
  255. case api.MountTypeBind:
  256. mount.Type = enginemount.TypeBind
  257. case api.MountTypeVolume:
  258. mount.Type = enginemount.TypeVolume
  259. case api.MountTypeTmpfs:
  260. mount.Type = enginemount.TypeTmpfs
  261. case api.MountTypeNamedPipe:
  262. mount.Type = enginemount.TypeNamedPipe
  263. case api.MountTypeCluster:
  264. mount.Type = enginemount.TypeCluster
  265. }
  266. if m.BindOptions != nil {
  267. mount.BindOptions = &enginemount.BindOptions{
  268. NonRecursive: m.BindOptions.NonRecursive,
  269. CreateMountpoint: m.BindOptions.CreateMountpoint,
  270. ReadOnlyNonRecursive: m.BindOptions.ReadOnlyNonRecursive,
  271. ReadOnlyForceRecursive: m.BindOptions.ReadOnlyForceRecursive,
  272. }
  273. switch m.BindOptions.Propagation {
  274. case api.MountPropagationRPrivate:
  275. mount.BindOptions.Propagation = enginemount.PropagationRPrivate
  276. case api.MountPropagationPrivate:
  277. mount.BindOptions.Propagation = enginemount.PropagationPrivate
  278. case api.MountPropagationRSlave:
  279. mount.BindOptions.Propagation = enginemount.PropagationRSlave
  280. case api.MountPropagationSlave:
  281. mount.BindOptions.Propagation = enginemount.PropagationSlave
  282. case api.MountPropagationRShared:
  283. mount.BindOptions.Propagation = enginemount.PropagationRShared
  284. case api.MountPropagationShared:
  285. mount.BindOptions.Propagation = enginemount.PropagationShared
  286. }
  287. }
  288. if m.VolumeOptions != nil {
  289. mount.VolumeOptions = &enginemount.VolumeOptions{
  290. NoCopy: m.VolumeOptions.NoCopy,
  291. }
  292. if m.VolumeOptions.Labels != nil {
  293. mount.VolumeOptions.Labels = make(map[string]string, len(m.VolumeOptions.Labels))
  294. for k, v := range m.VolumeOptions.Labels {
  295. mount.VolumeOptions.Labels[k] = v
  296. }
  297. }
  298. if m.VolumeOptions.DriverConfig != nil {
  299. mount.VolumeOptions.DriverConfig = &enginemount.Driver{
  300. Name: m.VolumeOptions.DriverConfig.Name,
  301. }
  302. if m.VolumeOptions.DriverConfig.Options != nil {
  303. mount.VolumeOptions.DriverConfig.Options = make(map[string]string, len(m.VolumeOptions.DriverConfig.Options))
  304. for k, v := range m.VolumeOptions.DriverConfig.Options {
  305. mount.VolumeOptions.DriverConfig.Options[k] = v
  306. }
  307. }
  308. }
  309. }
  310. if m.TmpfsOptions != nil {
  311. mount.TmpfsOptions = &enginemount.TmpfsOptions{
  312. SizeBytes: m.TmpfsOptions.SizeBytes,
  313. Mode: m.TmpfsOptions.Mode,
  314. }
  315. }
  316. return mount
  317. }
  318. func (c *containerConfig) healthcheck() *enginecontainer.HealthConfig {
  319. hcSpec := c.spec().Healthcheck
  320. if hcSpec == nil {
  321. return nil
  322. }
  323. interval, _ := gogotypes.DurationFromProto(hcSpec.Interval)
  324. timeout, _ := gogotypes.DurationFromProto(hcSpec.Timeout)
  325. startPeriod, _ := gogotypes.DurationFromProto(hcSpec.StartPeriod)
  326. return &enginecontainer.HealthConfig{
  327. Test: hcSpec.Test,
  328. Interval: interval,
  329. Timeout: timeout,
  330. Retries: int(hcSpec.Retries),
  331. StartPeriod: startPeriod,
  332. }
  333. }
  334. func (c *containerConfig) hostConfig(deps exec.VolumeGetter) *enginecontainer.HostConfig {
  335. hc := &enginecontainer.HostConfig{
  336. Resources: c.resources(),
  337. GroupAdd: c.spec().Groups,
  338. PortBindings: c.portBindings(),
  339. Mounts: c.mounts(deps),
  340. ReadonlyRootfs: c.spec().ReadOnly,
  341. Isolation: c.isolation(),
  342. Init: c.init(),
  343. Sysctls: c.spec().Sysctls,
  344. CapAdd: c.spec().CapabilityAdd,
  345. CapDrop: c.spec().CapabilityDrop,
  346. }
  347. if c.spec().DNSConfig != nil {
  348. hc.DNS = c.spec().DNSConfig.Nameservers
  349. hc.DNSSearch = c.spec().DNSConfig.Search
  350. hc.DNSOptions = c.spec().DNSConfig.Options
  351. }
  352. c.applyPrivileges(hc)
  353. // The format of extra hosts on swarmkit is specified in:
  354. // http://man7.org/linux/man-pages/man5/hosts.5.html
  355. // IP_address canonical_hostname [aliases...]
  356. // However, the format of ExtraHosts in HostConfig is
  357. // <host>:<ip>
  358. // We need to do the conversion here
  359. // (Alias is ignored for now)
  360. for _, entry := range c.spec().Hosts {
  361. parts := strings.Fields(entry)
  362. if len(parts) > 1 {
  363. hc.ExtraHosts = append(hc.ExtraHosts, fmt.Sprintf("%s:%s", parts[1], parts[0]))
  364. }
  365. }
  366. if c.task.LogDriver != nil {
  367. hc.LogConfig = enginecontainer.LogConfig{
  368. Type: c.task.LogDriver.Name,
  369. Config: c.task.LogDriver.Options,
  370. }
  371. }
  372. if len(c.task.Networks) > 0 {
  373. labels := c.task.Networks[0].Network.Spec.Annotations.Labels
  374. name := c.task.Networks[0].Network.Spec.Annotations.Name
  375. if v, ok := labels["com.docker.swarm.predefined"]; ok && v == "true" {
  376. hc.NetworkMode = enginecontainer.NetworkMode(name)
  377. }
  378. }
  379. return hc
  380. }
  381. // This handles the case of volumes that are defined inside a service Mount
  382. func (c *containerConfig) volumeCreateRequest(mount *api.Mount) *volume.CreateOptions {
  383. var (
  384. driverName string
  385. driverOpts map[string]string
  386. labels map[string]string
  387. )
  388. if mount.VolumeOptions != nil && mount.VolumeOptions.DriverConfig != nil {
  389. driverName = mount.VolumeOptions.DriverConfig.Name
  390. driverOpts = mount.VolumeOptions.DriverConfig.Options
  391. labels = mount.VolumeOptions.Labels
  392. }
  393. if mount.VolumeOptions != nil {
  394. return &volume.CreateOptions{
  395. Name: mount.Source,
  396. Driver: driverName,
  397. DriverOpts: driverOpts,
  398. Labels: labels,
  399. }
  400. }
  401. return nil
  402. }
  403. func (c *containerConfig) resources() enginecontainer.Resources {
  404. resources := enginecontainer.Resources{}
  405. // set pids limit
  406. pidsLimit := c.spec().PidsLimit
  407. if pidsLimit > 0 {
  408. resources.PidsLimit = &pidsLimit
  409. }
  410. resources.Ulimits = make([]*units.Ulimit, len(c.spec().Ulimits))
  411. for i, ulimit := range c.spec().Ulimits {
  412. resources.Ulimits[i] = &units.Ulimit{
  413. Name: ulimit.Name,
  414. Soft: ulimit.Soft,
  415. Hard: ulimit.Hard,
  416. }
  417. }
  418. // If no limits are specified let the engine use its defaults.
  419. //
  420. // TODO(aluzzardi): We might want to set some limits anyway otherwise
  421. // "unlimited" tasks will step over the reservation of other tasks.
  422. r := c.task.Spec.Resources
  423. if r == nil || r.Limits == nil {
  424. return resources
  425. }
  426. if r.Limits.MemoryBytes > 0 {
  427. resources.Memory = r.Limits.MemoryBytes
  428. }
  429. if r.Limits.NanoCPUs > 0 {
  430. resources.NanoCPUs = r.Limits.NanoCPUs
  431. }
  432. return resources
  433. }
  434. func (c *containerConfig) createNetworkingConfig(b executorpkg.Backend) *network.NetworkingConfig {
  435. var networks []*api.NetworkAttachment
  436. if c.task.Spec.GetContainer() != nil || c.task.Spec.GetAttachment() != nil {
  437. networks = c.task.Networks
  438. }
  439. epConfig := make(map[string]*network.EndpointSettings)
  440. for _, na := range networks {
  441. epConfig[na.Network.Spec.Annotations.Name] = getEndpointConfig(na, b)
  442. }
  443. return &network.NetworkingConfig{EndpointsConfig: epConfig}
  444. }
  445. func getEndpointConfig(na *api.NetworkAttachment, b executorpkg.Backend) *network.EndpointSettings {
  446. var ipv4, ipv6 string
  447. for _, addr := range na.Addresses {
  448. ip, _, err := net.ParseCIDR(addr)
  449. if err != nil {
  450. continue
  451. }
  452. if ip.To4() != nil {
  453. ipv4 = ip.String()
  454. continue
  455. }
  456. if ip.To16() != nil {
  457. ipv6 = ip.String()
  458. }
  459. }
  460. n := &network.EndpointSettings{
  461. NetworkID: na.Network.ID,
  462. IPAMConfig: &network.EndpointIPAMConfig{
  463. IPv4Address: ipv4,
  464. IPv6Address: ipv6,
  465. },
  466. DriverOpts: na.DriverAttachmentOpts,
  467. }
  468. if v, ok := na.Network.Spec.Annotations.Labels["com.docker.swarm.predefined"]; ok && v == "true" {
  469. if ln, err := b.FindNetwork(na.Network.Spec.Annotations.Name); err == nil {
  470. n.NetworkID = ln.ID()
  471. }
  472. }
  473. return n
  474. }
  475. func (c *containerConfig) virtualIP(networkID string) string {
  476. if c.task.Endpoint == nil {
  477. return ""
  478. }
  479. for _, eVip := range c.task.Endpoint.VirtualIPs {
  480. // We only support IPv4 VIPs for now.
  481. if eVip.NetworkID == networkID {
  482. vip, _, err := net.ParseCIDR(eVip.Addr)
  483. if err != nil {
  484. return ""
  485. }
  486. return vip.String()
  487. }
  488. }
  489. return ""
  490. }
  491. func (c *containerConfig) serviceConfig() *clustertypes.ServiceConfig {
  492. if len(c.task.Networks) == 0 {
  493. return nil
  494. }
  495. log.G(context.TODO()).Debugf("Creating service config in agent for t = %+v", c.task)
  496. svcCfg := &clustertypes.ServiceConfig{
  497. Name: c.task.ServiceAnnotations.Name,
  498. Aliases: make(map[string][]string),
  499. ID: c.task.ServiceID,
  500. VirtualAddresses: make(map[string]*clustertypes.VirtualAddress),
  501. }
  502. for _, na := range c.task.Networks {
  503. svcCfg.VirtualAddresses[na.Network.ID] = &clustertypes.VirtualAddress{
  504. // We support only IPv4 virtual IP for now.
  505. IPv4: c.virtualIP(na.Network.ID),
  506. }
  507. if len(na.Aliases) > 0 {
  508. svcCfg.Aliases[na.Network.ID] = na.Aliases
  509. }
  510. }
  511. if c.task.Endpoint != nil {
  512. for _, ePort := range c.task.Endpoint.Ports {
  513. if ePort.PublishMode != api.PublishModeIngress {
  514. continue
  515. }
  516. svcCfg.ExposedPorts = append(svcCfg.ExposedPorts, &clustertypes.PortConfig{
  517. Name: ePort.Name,
  518. Protocol: int32(ePort.Protocol),
  519. TargetPort: ePort.TargetPort,
  520. PublishedPort: ePort.PublishedPort,
  521. })
  522. }
  523. }
  524. return svcCfg
  525. }
  526. func (c *containerConfig) networkCreateRequest(name string) (clustertypes.NetworkCreateRequest, error) {
  527. na, ok := c.networksAttachments[name]
  528. if !ok {
  529. return clustertypes.NetworkCreateRequest{}, errors.New("container: unknown network referenced")
  530. }
  531. options := types.NetworkCreate{
  532. // ID: na.Network.ID,
  533. Labels: na.Network.Spec.Annotations.Labels,
  534. Internal: na.Network.Spec.Internal,
  535. Attachable: na.Network.Spec.Attachable,
  536. Ingress: convert.IsIngressNetwork(na.Network),
  537. EnableIPv6: na.Network.Spec.Ipv6Enabled,
  538. Scope: scope.Swarm,
  539. }
  540. if na.Network.Spec.GetNetwork() != "" {
  541. options.ConfigFrom = &network.ConfigReference{
  542. Network: na.Network.Spec.GetNetwork(),
  543. }
  544. }
  545. if na.Network.DriverState != nil {
  546. options.Driver = na.Network.DriverState.Name
  547. options.Options = na.Network.DriverState.Options
  548. }
  549. if na.Network.IPAM != nil {
  550. options.IPAM = &network.IPAM{
  551. Driver: na.Network.IPAM.Driver.Name,
  552. Options: na.Network.IPAM.Driver.Options,
  553. }
  554. for _, ic := range na.Network.IPAM.Configs {
  555. c := network.IPAMConfig{
  556. Subnet: ic.Subnet,
  557. IPRange: ic.Range,
  558. Gateway: ic.Gateway,
  559. }
  560. options.IPAM.Config = append(options.IPAM.Config, c)
  561. }
  562. }
  563. return clustertypes.NetworkCreateRequest{
  564. ID: na.Network.ID,
  565. NetworkCreateRequest: types.NetworkCreateRequest{
  566. Name: name,
  567. NetworkCreate: options,
  568. },
  569. }, nil
  570. }
  571. func (c *containerConfig) applyPrivileges(hc *enginecontainer.HostConfig) {
  572. privileges := c.spec().Privileges
  573. if privileges == nil {
  574. return
  575. }
  576. credentials := privileges.CredentialSpec
  577. if credentials != nil {
  578. switch credentials.Source.(type) {
  579. case *api.Privileges_CredentialSpec_File:
  580. hc.SecurityOpt = append(hc.SecurityOpt, "credentialspec=file://"+credentials.GetFile())
  581. case *api.Privileges_CredentialSpec_Registry:
  582. hc.SecurityOpt = append(hc.SecurityOpt, "credentialspec=registry://"+credentials.GetRegistry())
  583. case *api.Privileges_CredentialSpec_Config:
  584. hc.SecurityOpt = append(hc.SecurityOpt, "credentialspec=config://"+credentials.GetConfig())
  585. }
  586. }
  587. selinux := privileges.SELinuxContext
  588. if selinux != nil {
  589. if selinux.Disable {
  590. hc.SecurityOpt = append(hc.SecurityOpt, "label=disable")
  591. }
  592. if selinux.User != "" {
  593. hc.SecurityOpt = append(hc.SecurityOpt, "label=user:"+selinux.User)
  594. }
  595. if selinux.Role != "" {
  596. hc.SecurityOpt = append(hc.SecurityOpt, "label=role:"+selinux.Role)
  597. }
  598. if selinux.Level != "" {
  599. hc.SecurityOpt = append(hc.SecurityOpt, "label=level:"+selinux.Level)
  600. }
  601. if selinux.Type != "" {
  602. hc.SecurityOpt = append(hc.SecurityOpt, "label=type:"+selinux.Type)
  603. }
  604. }
  605. // variable to make the lines shorter and easier to read
  606. if seccomp := privileges.Seccomp; seccomp != nil {
  607. switch seccomp.Mode {
  608. // case api.Privileges_SeccompOpts_DEFAULT:
  609. // if the setting is default, nothing needs to be set here. we leave
  610. // the option empty.
  611. case api.Privileges_SeccompOpts_UNCONFINED:
  612. hc.SecurityOpt = append(hc.SecurityOpt, "seccomp=unconfined")
  613. case api.Privileges_SeccompOpts_CUSTOM:
  614. // Profile is bytes, but those bytes are actually a string. This is
  615. // basically verbatim what happens in the cli after a file is read.
  616. hc.SecurityOpt = append(hc.SecurityOpt, fmt.Sprintf("seccomp=%s", seccomp.Profile))
  617. }
  618. }
  619. // if the setting is DEFAULT, then nothing to be done. If it's DISABLED,
  620. // we set that. Custom not supported yet. When custom *is* supported, make
  621. // it look like the above.
  622. if apparmor := privileges.Apparmor; apparmor != nil && apparmor.Mode == api.Privileges_AppArmorOpts_DISABLED {
  623. hc.SecurityOpt = append(hc.SecurityOpt, "apparmor=unconfined")
  624. }
  625. if privileges.NoNewPrivileges {
  626. hc.SecurityOpt = append(hc.SecurityOpt, "no-new-privileges=true")
  627. }
  628. }
  629. func (c *containerConfig) eventFilter() filters.Args {
  630. return filters.NewArgs(
  631. filters.Arg("type", string(events.ContainerEventType)),
  632. filters.Arg("name", c.name()),
  633. filters.Arg("label", fmt.Sprintf("%v.task.id=%v", systemLabelPrefix, c.task.ID)),
  634. )
  635. }