2016-06-13 22:52:49 -04:00
|
|
|
package container
|
|
|
|
|
|
|
|
import (
|
2017-03-01 15:52:55 -05:00
|
|
|
"fmt"
|
2016-07-25 13:38:24 -04:00
|
|
|
"sort"
|
2016-06-13 22:52:49 -04:00
|
|
|
"strings"
|
2017-08-30 15:45:05 -04:00
|
|
|
"sync"
|
2016-06-13 22:52:49 -04:00
|
|
|
|
2016-09-06 14:46:37 -04:00
|
|
|
"github.com/docker/docker/api/types"
|
2016-11-23 07:58:15 -05:00
|
|
|
"github.com/docker/docker/api/types/filters"
|
2016-09-06 14:46:37 -04:00
|
|
|
"github.com/docker/docker/api/types/network"
|
2017-03-01 15:52:55 -05:00
|
|
|
swarmtypes "github.com/docker/docker/api/types/swarm"
|
|
|
|
"github.com/docker/docker/daemon/cluster/controllers/plugin"
|
2017-05-30 20:02:11 -04:00
|
|
|
"github.com/docker/docker/daemon/cluster/convert"
|
2016-06-13 22:52:49 -04:00
|
|
|
executorpkg "github.com/docker/docker/daemon/cluster/executor"
|
|
|
|
clustertypes "github.com/docker/docker/daemon/cluster/provider"
|
|
|
|
networktypes "github.com/docker/libnetwork/types"
|
2017-03-16 17:23:33 -04:00
|
|
|
"github.com/docker/swarmkit/agent"
|
2016-06-13 22:52:49 -04:00
|
|
|
"github.com/docker/swarmkit/agent/exec"
|
|
|
|
"github.com/docker/swarmkit/api"
|
2017-03-01 15:52:55 -05:00
|
|
|
"github.com/docker/swarmkit/api/naming"
|
2017-07-26 17:42:13 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2016-06-13 22:52:49 -04:00
|
|
|
"golang.org/x/net/context"
|
|
|
|
)
|
|
|
|
|
|
|
|
type executor struct {
|
2017-06-07 13:07:01 -04:00
|
|
|
backend executorpkg.Backend
|
|
|
|
pluginBackend plugin.Backend
|
|
|
|
dependencies exec.DependencyManager
|
2017-08-30 15:45:05 -04:00
|
|
|
mutex sync.Mutex // This mutex protects the following node field
|
|
|
|
node *api.NodeDescription
|
2016-06-13 22:52:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewExecutor returns an executor from the docker client.
|
2017-06-07 13:07:01 -04:00
|
|
|
func NewExecutor(b executorpkg.Backend, p plugin.Backend) exec.Executor {
|
2016-06-13 22:52:49 -04:00
|
|
|
return &executor{
|
2017-06-07 13:07:01 -04:00
|
|
|
backend: b,
|
|
|
|
pluginBackend: p,
|
|
|
|
dependencies: agent.NewDependencyManager(),
|
2016-06-13 22:52:49 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2016-07-25 20:16:31 -04:00
|
|
|
plugins := map[api.PluginDescription]struct{}{}
|
2016-06-13 22:52:49 -04:00
|
|
|
addPlugins := func(typ string, names []string) {
|
|
|
|
for _, name := range names {
|
2016-07-25 20:16:31 -04:00
|
|
|
plugins[api.PluginDescription{
|
2016-06-13 22:52:49 -04:00
|
|
|
Type: typ,
|
|
|
|
Name: name,
|
2016-07-25 20:16:31 -04:00
|
|
|
}] = struct{}{}
|
2016-06-13 22:52:49 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 20:20:37 -05:00
|
|
|
// add v1 plugins
|
2016-06-13 22:52:49 -04:00
|
|
|
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)
|
2017-04-11 17:21:21 -04:00
|
|
|
addPlugins("Log", info.Plugins.Log)
|
2016-06-13 22:52:49 -04:00
|
|
|
|
2016-12-13 20:20:37 -05:00
|
|
|
// add v2 plugins
|
2016-11-23 07:58:15 -05:00
|
|
|
v2Plugins, err := e.backend.PluginManager().List(filters.NewArgs())
|
2016-12-13 20:20:37 -05:00
|
|
|
if err == nil {
|
|
|
|
for _, plgn := range v2Plugins {
|
|
|
|
for _, typ := range plgn.Config.Interface.Types {
|
|
|
|
if typ.Prefix != "docker" || !plgn.Enabled {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
plgnTyp := typ.Capability
|
2017-04-11 17:21:21 -04:00
|
|
|
switch typ.Capability {
|
|
|
|
case "volumedriver":
|
2016-12-13 20:20:37 -05:00
|
|
|
plgnTyp = "Volume"
|
2017-04-11 17:21:21 -04:00
|
|
|
case "networkdriver":
|
2016-12-13 20:20:37 -05:00
|
|
|
plgnTyp = "Network"
|
2017-04-11 17:21:21 -04:00
|
|
|
case "logdriver":
|
|
|
|
plgnTyp = "Log"
|
2016-12-13 20:20:37 -05:00
|
|
|
}
|
2017-04-11 17:21:21 -04:00
|
|
|
|
2016-12-13 20:20:37 -05:00
|
|
|
plugins[api.PluginDescription{
|
|
|
|
Type: plgnTyp,
|
2016-12-12 18:05:53 -05:00
|
|
|
Name: plgn.Name,
|
2016-12-13 20:20:37 -05:00
|
|
|
}] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-25 20:16:31 -04:00
|
|
|
pluginFields := make([]api.PluginDescription, 0, len(plugins))
|
|
|
|
for k := range plugins {
|
|
|
|
pluginFields = append(pluginFields, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(sortedPlugins(pluginFields))
|
2016-07-25 13:38:24 -04:00
|
|
|
|
2016-06-13 22:52:49 -04:00
|
|
|
// 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,
|
2016-07-25 20:16:31 -04:00
|
|
|
Plugins: pluginFields,
|
2016-06-13 22:52:49 -04:00
|
|
|
},
|
|
|
|
Resources: &api.Resources{
|
|
|
|
NanoCPUs: int64(info.NCPU) * 1e9,
|
|
|
|
MemoryBytes: info.MemTotal,
|
2017-05-30 20:02:11 -04:00
|
|
|
Generic: convert.GenericResourcesToGRPC(info.GenericResources),
|
2016-06-13 22:52:49 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-08-30 15:45:05 -04:00
|
|
|
// Save the node information in the executor field
|
|
|
|
e.mutex.Lock()
|
|
|
|
e.node = description
|
|
|
|
e.mutex.Unlock()
|
|
|
|
|
2016-06-13 22:52:49 -04:00
|
|
|
return description, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *executor) Configure(ctx context.Context, node *api.Node) error {
|
2017-08-29 02:49:26 -04:00
|
|
|
var ingressNA *api.NetworkAttachment
|
2017-09-22 02:04:34 -04:00
|
|
|
attachments := make(map[string]string)
|
2017-08-29 02:49:26 -04:00
|
|
|
|
2017-09-22 02:04:34 -04:00
|
|
|
for _, na := range node.Attachments {
|
2017-08-29 02:49:26 -04:00
|
|
|
if na.Network.Spec.Ingress {
|
|
|
|
ingressNA = na
|
|
|
|
}
|
2017-09-22 02:04:34 -04:00
|
|
|
attachments[na.Network.ID] = na.Addresses[0]
|
2017-08-29 02:49:26 -04:00
|
|
|
}
|
|
|
|
|
2018-01-12 04:27:30 -05:00
|
|
|
if (ingressNA == nil) && (node.Attachment != nil) {
|
|
|
|
ingressNA = node.Attachment
|
|
|
|
attachments[ingressNA.Network.ID] = ingressNA.Addresses[0]
|
|
|
|
}
|
|
|
|
|
2017-08-29 02:49:26 -04:00
|
|
|
if ingressNA == nil {
|
2017-03-09 14:52:25 -05:00
|
|
|
e.backend.ReleaseIngress()
|
2017-09-22 02:04:34 -04:00
|
|
|
return e.backend.GetAttachmentStore().ResetAttachments(attachments)
|
2016-06-13 22:52:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
options := types.NetworkCreate{
|
2017-08-29 02:49:26 -04:00
|
|
|
Driver: ingressNA.Network.DriverState.Name,
|
2016-08-31 11:25:14 -04:00
|
|
|
IPAM: &network.IPAM{
|
2017-08-29 02:49:26 -04:00
|
|
|
Driver: ingressNA.Network.IPAM.Driver.Name,
|
2016-06-13 22:52:49 -04:00
|
|
|
},
|
2017-08-29 02:49:26 -04:00
|
|
|
Options: ingressNA.Network.DriverState.Options,
|
2017-03-09 14:52:25 -05:00
|
|
|
Ingress: true,
|
2016-06-13 22:52:49 -04:00
|
|
|
CheckDuplicate: true,
|
|
|
|
}
|
|
|
|
|
2017-08-29 02:49:26 -04:00
|
|
|
for _, ic := range ingressNA.Network.IPAM.Configs {
|
2016-06-13 22:52:49 -04:00
|
|
|
c := network.IPAMConfig{
|
|
|
|
Subnet: ic.Subnet,
|
|
|
|
IPRange: ic.Range,
|
|
|
|
Gateway: ic.Gateway,
|
|
|
|
}
|
|
|
|
options.IPAM.Config = append(options.IPAM.Config, c)
|
|
|
|
}
|
|
|
|
|
2017-03-31 17:07:55 -04:00
|
|
|
_, err := e.backend.SetupIngress(clustertypes.NetworkCreateRequest{
|
2017-08-29 02:49:26 -04:00
|
|
|
ID: ingressNA.Network.ID,
|
2016-11-29 06:36:56 -05:00
|
|
|
NetworkCreateRequest: types.NetworkCreateRequest{
|
2017-08-29 02:49:26 -04:00
|
|
|
Name: ingressNA.Network.Spec.Annotations.Name,
|
2016-06-13 22:52:49 -04:00
|
|
|
NetworkCreate: options,
|
|
|
|
},
|
2017-08-29 02:49:26 -04:00
|
|
|
}, ingressNA.Addresses[0])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-03-31 17:07:55 -04:00
|
|
|
|
2017-09-22 02:04:34 -04:00
|
|
|
return e.backend.GetAttachmentStore().ResetAttachments(attachments)
|
2016-06-13 22:52:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Controller returns a docker container runner.
|
2016-10-27 13:34:58 -04:00
|
|
|
func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
|
2017-03-16 17:23:33 -04:00
|
|
|
dependencyGetter := agent.Restrict(e.dependencies, t)
|
|
|
|
|
2017-08-30 15:45:05 -04:00
|
|
|
// Get the node description from the executor field
|
|
|
|
e.mutex.Lock()
|
|
|
|
nodeDescription := e.node
|
|
|
|
e.mutex.Unlock()
|
|
|
|
|
2016-08-23 19:50:15 -04:00
|
|
|
if t.Spec.GetAttachment() != nil {
|
2017-08-30 15:45:05 -04:00
|
|
|
return newNetworkAttacherController(e.backend, t, nodeDescription, dependencyGetter)
|
2016-08-23 19:50:15 -04:00
|
|
|
}
|
|
|
|
|
2017-03-01 15:52:55 -05:00
|
|
|
var ctlr exec.Controller
|
|
|
|
switch r := t.Spec.GetRuntime().(type) {
|
|
|
|
case *api.TaskSpec_Generic:
|
|
|
|
logrus.WithFields(logrus.Fields{
|
2017-03-24 15:19:59 -04:00
|
|
|
"kind": r.Generic.Kind,
|
|
|
|
"type_url": r.Generic.Payload.TypeUrl,
|
2017-03-01 15:52:55 -05:00
|
|
|
}).Debug("custom runtime requested")
|
|
|
|
runtimeKind, err := naming.Runtime(t.Spec)
|
|
|
|
if err != nil {
|
|
|
|
return ctlr, err
|
|
|
|
}
|
|
|
|
switch runtimeKind {
|
|
|
|
case string(swarmtypes.RuntimePlugin):
|
2017-08-08 21:33:25 -04:00
|
|
|
info, _ := e.backend.SystemInfo()
|
|
|
|
if !info.ExperimentalBuild {
|
|
|
|
return ctlr, fmt.Errorf("runtime type %q only supported in experimental", swarmtypes.RuntimePlugin)
|
|
|
|
}
|
2017-06-07 13:07:01 -04:00
|
|
|
c, err := plugin.NewController(e.pluginBackend, t)
|
2017-03-01 15:52:55 -05:00
|
|
|
if err != nil {
|
|
|
|
return ctlr, err
|
|
|
|
}
|
|
|
|
ctlr = c
|
|
|
|
default:
|
2017-08-08 21:33:25 -04:00
|
|
|
return ctlr, fmt.Errorf("unsupported runtime type: %q", runtimeKind)
|
2017-03-01 15:52:55 -05:00
|
|
|
}
|
|
|
|
case *api.TaskSpec_Container:
|
2017-08-30 15:45:05 -04:00
|
|
|
c, err := newController(e.backend, t, nodeDescription, dependencyGetter)
|
2017-03-01 15:52:55 -05:00
|
|
|
if err != nil {
|
2017-03-27 10:51:42 -04:00
|
|
|
return ctlr, err
|
2017-03-01 15:52:55 -05:00
|
|
|
}
|
|
|
|
ctlr = c
|
|
|
|
default:
|
2017-03-27 10:51:42 -04:00
|
|
|
return ctlr, fmt.Errorf("unsupported runtime: %q", r)
|
2016-06-13 22:52:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2016-07-25 13:38:24 -04:00
|
|
|
|
2016-10-27 13:34:58 -04:00
|
|
|
func (e *executor) Secrets() exec.SecretsManager {
|
2017-03-16 17:23:33 -04:00
|
|
|
return e.dependencies.Secrets()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *executor) Configs() exec.ConfigsManager {
|
|
|
|
return e.dependencies.Configs()
|
2016-10-27 13:34:58 -04:00
|
|
|
}
|
|
|
|
|
2016-07-25 13:38:24 -04:00
|
|
|
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
|
|
|
|
}
|