daemon/cluster/executor/container/executor.go
534a90a9
 package container
 
 import (
e06e2ef1
 	"fmt"
227c7e4e
 	"sort"
534a90a9
 	"strings"
e2f09fa6
 	"sync"
534a90a9
 
7c36a1af
 	"github.com/docker/docker/api/types"
a66e0dc3
 	"github.com/docker/docker/api/types/filters"
7c36a1af
 	"github.com/docker/docker/api/types/network"
e06e2ef1
 	swarmtypes "github.com/docker/docker/api/types/swarm"
 	"github.com/docker/docker/daemon/cluster/controllers/plugin"
87e1464c
 	"github.com/docker/docker/daemon/cluster/convert"
534a90a9
 	executorpkg "github.com/docker/docker/daemon/cluster/executor"
 	clustertypes "github.com/docker/docker/daemon/cluster/provider"
 	networktypes "github.com/docker/libnetwork/types"
9e9fc7b5
 	"github.com/docker/swarmkit/agent"
534a90a9
 	"github.com/docker/swarmkit/agent/exec"
 	"github.com/docker/swarmkit/api"
e06e2ef1
 	"github.com/docker/swarmkit/api/naming"
1009e6a4
 	"github.com/sirupsen/logrus"
534a90a9
 	"golang.org/x/net/context"
 )
 
 type executor struct {
72c3bcf2
 	backend       executorpkg.Backend
 	pluginBackend plugin.Backend
 	dependencies  exec.DependencyManager
e2f09fa6
 	mutex         sync.Mutex // This mutex protects the following node field
 	node          *api.NodeDescription
534a90a9
 }
 
 // NewExecutor returns an executor from the docker client.
72c3bcf2
 func NewExecutor(b executorpkg.Backend, p plugin.Backend) exec.Executor {
534a90a9
 	return &executor{
72c3bcf2
 		backend:       b,
 		pluginBackend: p,
 		dependencies:  agent.NewDependencyManager(),
534a90a9
 	}
 }
 
 // Describe returns the underlying node description from the docker client.
 func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) {
 	info, err := e.backend.SystemInfo()
 	if err != nil {
 		return nil, err
 	}
 
feedb7ab
 	plugins := map[api.PluginDescription]struct{}{}
534a90a9
 	addPlugins := func(typ string, names []string) {
 		for _, name := range names {
feedb7ab
 			plugins[api.PluginDescription{
534a90a9
 				Type: typ,
 				Name: name,
feedb7ab
 			}] = struct{}{}
534a90a9
 		}
 	}
 
2a97ea9a
 	// add v1 plugins
534a90a9
 	addPlugins("Volume", info.Plugins.Volume)
 	// Add builtin driver "overlay" (the only builtin multi-host driver) to
 	// the plugin list by default.
 	addPlugins("Network", append([]string{"overlay"}, info.Plugins.Network...))
 	addPlugins("Authorization", info.Plugins.Authorization)
17abacb8
 	addPlugins("Log", info.Plugins.Log)
534a90a9
 
2a97ea9a
 	// add v2 plugins
a66e0dc3
 	v2Plugins, err := e.backend.PluginManager().List(filters.NewArgs())
2a97ea9a
 	if err == nil {
 		for _, plgn := range v2Plugins {
 			for _, typ := range plgn.Config.Interface.Types {
 				if typ.Prefix != "docker" || !plgn.Enabled {
 					continue
 				}
 				plgnTyp := typ.Capability
17abacb8
 				switch typ.Capability {
 				case "volumedriver":
2a97ea9a
 					plgnTyp = "Volume"
17abacb8
 				case "networkdriver":
2a97ea9a
 					plgnTyp = "Network"
17abacb8
 				case "logdriver":
 					plgnTyp = "Log"
2a97ea9a
 				}
17abacb8
 
2a97ea9a
 				plugins[api.PluginDescription{
 					Type: plgnTyp,
3d86b0c7
 					Name: plgn.Name,
2a97ea9a
 				}] = struct{}{}
 			}
 		}
 	}
 
feedb7ab
 	pluginFields := make([]api.PluginDescription, 0, len(plugins))
 	for k := range plugins {
 		pluginFields = append(pluginFields, k)
 	}
 
 	sort.Sort(sortedPlugins(pluginFields))
227c7e4e
 
534a90a9
 	// parse []string labels into a map[string]string
 	labels := map[string]string{}
 	for _, l := range info.Labels {
 		stringSlice := strings.SplitN(l, "=", 2)
 		// this will take the last value in the list for a given key
 		// ideally, one shouldn't assign multiple values to the same key
 		if len(stringSlice) > 1 {
 			labels[stringSlice[0]] = stringSlice[1]
 		}
 	}
 
 	description := &api.NodeDescription{
 		Hostname: info.Name,
 		Platform: &api.Platform{
 			Architecture: info.Architecture,
 			OS:           info.OSType,
 		},
 		Engine: &api.EngineDescription{
 			EngineVersion: info.ServerVersion,
 			Labels:        labels,
feedb7ab
 			Plugins:       pluginFields,
534a90a9
 		},
 		Resources: &api.Resources{
 			NanoCPUs:    int64(info.NCPU) * 1e9,
 			MemoryBytes: info.MemTotal,
87e1464c
 			Generic:     convert.GenericResourcesToGRPC(info.GenericResources),
534a90a9
 		},
 	}
 
e2f09fa6
 	// Save the node information in the executor field
 	e.mutex.Lock()
 	e.node = description
 	e.mutex.Unlock()
 
534a90a9
 	return description, nil
 }
 
 func (e *executor) Configure(ctx context.Context, node *api.Node) error {
9bed0883
 	var ingressNA *api.NetworkAttachment
d00a07b1
 	attachments := make(map[string]string)
9bed0883
 
d00a07b1
 	for _, na := range node.Attachments {
9bed0883
 		if na.Network.Spec.Ingress {
 			ingressNA = na
 		}
d00a07b1
 		attachments[na.Network.ID] = na.Addresses[0]
9bed0883
 	}
 
2d7a50e5
 	if (ingressNA == nil) && (node.Attachment != nil) {
 		ingressNA = node.Attachment
 		attachments[ingressNA.Network.ID] = ingressNA.Addresses[0]
 	}
 
9bed0883
 	if ingressNA == nil {
d59d19c3
 		e.backend.ReleaseIngress()
d00a07b1
 		return e.backend.GetAttachmentStore().ResetAttachments(attachments)
534a90a9
 	}
 
 	options := types.NetworkCreate{
9bed0883
 		Driver: ingressNA.Network.DriverState.Name,
8f7a8c75
 		IPAM: &network.IPAM{
9bed0883
 			Driver: ingressNA.Network.IPAM.Driver.Name,
534a90a9
 		},
9bed0883
 		Options:        ingressNA.Network.DriverState.Options,
d59d19c3
 		Ingress:        true,
534a90a9
 		CheckDuplicate: true,
 	}
 
9bed0883
 	for _, ic := range ingressNA.Network.IPAM.Configs {
534a90a9
 		c := network.IPAMConfig{
 			Subnet:  ic.Subnet,
 			IPRange: ic.Range,
 			Gateway: ic.Gateway,
 		}
 		options.IPAM.Config = append(options.IPAM.Config, c)
 	}
 
6f4bb796
 	_, err := e.backend.SetupIngress(clustertypes.NetworkCreateRequest{
9bed0883
 		ID: ingressNA.Network.ID,
da6944ec
 		NetworkCreateRequest: types.NetworkCreateRequest{
9bed0883
 			Name:          ingressNA.Network.Spec.Annotations.Name,
534a90a9
 			NetworkCreate: options,
 		},
9bed0883
 	}, ingressNA.Addresses[0])
 	if err != nil {
 		return err
 	}
6f4bb796
 
d00a07b1
 	return e.backend.GetAttachmentStore().ResetAttachments(attachments)
534a90a9
 }
 
 // Controller returns a docker container runner.
f50a65ff
 func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
9e9fc7b5
 	dependencyGetter := agent.Restrict(e.dependencies, t)
 
e2f09fa6
 	// Get the node description from the executor field
 	e.mutex.Lock()
 	nodeDescription := e.node
 	e.mutex.Unlock()
 
99a98ccc
 	if t.Spec.GetAttachment() != nil {
e2f09fa6
 		return newNetworkAttacherController(e.backend, t, nodeDescription, dependencyGetter)
99a98ccc
 	}
 
e06e2ef1
 	var ctlr exec.Controller
 	switch r := t.Spec.GetRuntime().(type) {
 	case *api.TaskSpec_Generic:
 		logrus.WithFields(logrus.Fields{
8c2c69d3
 			"kind":     r.Generic.Kind,
 			"type_url": r.Generic.Payload.TypeUrl,
e06e2ef1
 		}).Debug("custom runtime requested")
 		runtimeKind, err := naming.Runtime(t.Spec)
 		if err != nil {
 			return ctlr, err
 		}
 		switch runtimeKind {
 		case string(swarmtypes.RuntimePlugin):
49300202
 			info, _ := e.backend.SystemInfo()
 			if !info.ExperimentalBuild {
 				return ctlr, fmt.Errorf("runtime type %q only supported in experimental", swarmtypes.RuntimePlugin)
 			}
72c3bcf2
 			c, err := plugin.NewController(e.pluginBackend, t)
e06e2ef1
 			if err != nil {
 				return ctlr, err
 			}
 			ctlr = c
 		default:
49300202
 			return ctlr, fmt.Errorf("unsupported runtime type: %q", runtimeKind)
e06e2ef1
 		}
 	case *api.TaskSpec_Container:
e2f09fa6
 		c, err := newController(e.backend, t, nodeDescription, dependencyGetter)
e06e2ef1
 		if err != nil {
3a9be929
 			return ctlr, err
e06e2ef1
 		}
 		ctlr = c
 	default:
3a9be929
 		return ctlr, fmt.Errorf("unsupported runtime: %q", r)
534a90a9
 	}
 
 	return ctlr, nil
 }
 
 func (e *executor) SetNetworkBootstrapKeys(keys []*api.EncryptionKey) error {
 	nwKeys := []*networktypes.EncryptionKey{}
 	for _, key := range keys {
 		nwKey := &networktypes.EncryptionKey{
 			Subsystem:   key.Subsystem,
 			Algorithm:   int32(key.Algorithm),
 			Key:         make([]byte, len(key.Key)),
 			LamportTime: key.LamportTime,
 		}
 		copy(nwKey.Key, key.Key)
 		nwKeys = append(nwKeys, nwKey)
 	}
 	e.backend.SetNetworkBootstrapKeys(nwKeys)
 
 	return nil
 }
227c7e4e
 
f50a65ff
 func (e *executor) Secrets() exec.SecretsManager {
9e9fc7b5
 	return e.dependencies.Secrets()
 }
 
 func (e *executor) Configs() exec.ConfigsManager {
 	return e.dependencies.Configs()
f50a65ff
 }
 
227c7e4e
 type sortedPlugins []api.PluginDescription
 
 func (sp sortedPlugins) Len() int { return len(sp) }
 
 func (sp sortedPlugins) Swap(i, j int) { sp[i], sp[j] = sp[j], sp[i] }
 
 func (sp sortedPlugins) Less(i, j int) bool {
 	if sp[i].Type != sp[j].Type {
 		return sp[i].Type < sp[j].Type
 	}
 	return sp[i].Name < sp[j].Name
 }