container.go 18 KB

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