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  }