container.go 19 KB

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