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
} |