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