github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/cluster/executor/container/executor.go (about) 1 package container 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 "sync" 8 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/filters" 11 "github.com/docker/docker/api/types/network" 12 swarmtypes "github.com/docker/docker/api/types/swarm" 13 "github.com/docker/docker/daemon/cluster/controllers/plugin" 14 "github.com/docker/docker/daemon/cluster/convert" 15 executorpkg "github.com/docker/docker/daemon/cluster/executor" 16 clustertypes "github.com/docker/docker/daemon/cluster/provider" 17 networktypes "github.com/docker/libnetwork/types" 18 "github.com/docker/swarmkit/agent" 19 "github.com/docker/swarmkit/agent/exec" 20 "github.com/docker/swarmkit/api" 21 "github.com/docker/swarmkit/api/naming" 22 "github.com/sirupsen/logrus" 23 "golang.org/x/net/context" 24 ) 25 26 type executor struct { 27 backend executorpkg.Backend 28 pluginBackend plugin.Backend 29 dependencies exec.DependencyManager 30 mutex sync.Mutex // This mutex protects the following node field 31 node *api.NodeDescription 32 } 33 34 // NewExecutor returns an executor from the docker client. 35 func NewExecutor(b executorpkg.Backend, p plugin.Backend) exec.Executor { 36 return &executor{ 37 backend: b, 38 pluginBackend: p, 39 dependencies: agent.NewDependencyManager(), 40 } 41 } 42 43 // Describe returns the underlying node description from the docker client. 44 func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) { 45 info, err := e.backend.SystemInfo() 46 if err != nil { 47 return nil, err 48 } 49 50 plugins := map[api.PluginDescription]struct{}{} 51 addPlugins := func(typ string, names []string) { 52 for _, name := range names { 53 plugins[api.PluginDescription{ 54 Type: typ, 55 Name: name, 56 }] = struct{}{} 57 } 58 } 59 60 // add v1 plugins 61 addPlugins("Volume", info.Plugins.Volume) 62 // Add builtin driver "overlay" (the only builtin multi-host driver) to 63 // the plugin list by default. 64 addPlugins("Network", append([]string{"overlay"}, info.Plugins.Network...)) 65 addPlugins("Authorization", info.Plugins.Authorization) 66 addPlugins("Log", info.Plugins.Log) 67 68 // add v2 plugins 69 v2Plugins, err := e.backend.PluginManager().List(filters.NewArgs()) 70 if err == nil { 71 for _, plgn := range v2Plugins { 72 for _, typ := range plgn.Config.Interface.Types { 73 if typ.Prefix != "docker" || !plgn.Enabled { 74 continue 75 } 76 plgnTyp := typ.Capability 77 switch typ.Capability { 78 case "volumedriver": 79 plgnTyp = "Volume" 80 case "networkdriver": 81 plgnTyp = "Network" 82 case "logdriver": 83 plgnTyp = "Log" 84 } 85 86 plugins[api.PluginDescription{ 87 Type: plgnTyp, 88 Name: plgn.Name, 89 }] = struct{}{} 90 } 91 } 92 } 93 94 pluginFields := make([]api.PluginDescription, 0, len(plugins)) 95 for k := range plugins { 96 pluginFields = append(pluginFields, k) 97 } 98 99 sort.Sort(sortedPlugins(pluginFields)) 100 101 // parse []string labels into a map[string]string 102 labels := map[string]string{} 103 for _, l := range info.Labels { 104 stringSlice := strings.SplitN(l, "=", 2) 105 // this will take the last value in the list for a given key 106 // ideally, one shouldn't assign multiple values to the same key 107 if len(stringSlice) > 1 { 108 labels[stringSlice[0]] = stringSlice[1] 109 } 110 } 111 112 description := &api.NodeDescription{ 113 Hostname: info.Name, 114 Platform: &api.Platform{ 115 Architecture: info.Architecture, 116 OS: info.OSType, 117 }, 118 Engine: &api.EngineDescription{ 119 EngineVersion: info.ServerVersion, 120 Labels: labels, 121 Plugins: pluginFields, 122 }, 123 Resources: &api.Resources{ 124 NanoCPUs: int64(info.NCPU) * 1e9, 125 MemoryBytes: info.MemTotal, 126 Generic: convert.GenericResourcesToGRPC(info.GenericResources), 127 }, 128 } 129 130 // Save the node information in the executor field 131 e.mutex.Lock() 132 e.node = description 133 e.mutex.Unlock() 134 135 return description, nil 136 } 137 138 func (e *executor) Configure(ctx context.Context, node *api.Node) error { 139 var ingressNA *api.NetworkAttachment 140 attachments := make(map[string]string) 141 142 for _, na := range node.Attachments { 143 if na.Network.Spec.Ingress { 144 ingressNA = na 145 } 146 attachments[na.Network.ID] = na.Addresses[0] 147 } 148 149 if (ingressNA == nil) && (node.Attachment != nil) { 150 ingressNA = node.Attachment 151 attachments[ingressNA.Network.ID] = ingressNA.Addresses[0] 152 } 153 154 if ingressNA == nil { 155 e.backend.ReleaseIngress() 156 return e.backend.GetAttachmentStore().ResetAttachments(attachments) 157 } 158 159 options := types.NetworkCreate{ 160 Driver: ingressNA.Network.DriverState.Name, 161 IPAM: &network.IPAM{ 162 Driver: ingressNA.Network.IPAM.Driver.Name, 163 }, 164 Options: ingressNA.Network.DriverState.Options, 165 Ingress: true, 166 CheckDuplicate: true, 167 } 168 169 for _, ic := range ingressNA.Network.IPAM.Configs { 170 c := network.IPAMConfig{ 171 Subnet: ic.Subnet, 172 IPRange: ic.Range, 173 Gateway: ic.Gateway, 174 } 175 options.IPAM.Config = append(options.IPAM.Config, c) 176 } 177 178 _, err := e.backend.SetupIngress(clustertypes.NetworkCreateRequest{ 179 ID: ingressNA.Network.ID, 180 NetworkCreateRequest: types.NetworkCreateRequest{ 181 Name: ingressNA.Network.Spec.Annotations.Name, 182 NetworkCreate: options, 183 }, 184 }, ingressNA.Addresses[0]) 185 if err != nil { 186 return err 187 } 188 189 return e.backend.GetAttachmentStore().ResetAttachments(attachments) 190 } 191 192 // Controller returns a docker container runner. 193 func (e *executor) Controller(t *api.Task) (exec.Controller, error) { 194 dependencyGetter := agent.Restrict(e.dependencies, t) 195 196 // Get the node description from the executor field 197 e.mutex.Lock() 198 nodeDescription := e.node 199 e.mutex.Unlock() 200 201 if t.Spec.GetAttachment() != nil { 202 return newNetworkAttacherController(e.backend, t, nodeDescription, dependencyGetter) 203 } 204 205 var ctlr exec.Controller 206 switch r := t.Spec.GetRuntime().(type) { 207 case *api.TaskSpec_Generic: 208 logrus.WithFields(logrus.Fields{ 209 "kind": r.Generic.Kind, 210 "type_url": r.Generic.Payload.TypeUrl, 211 }).Debug("custom runtime requested") 212 runtimeKind, err := naming.Runtime(t.Spec) 213 if err != nil { 214 return ctlr, err 215 } 216 switch runtimeKind { 217 case string(swarmtypes.RuntimePlugin): 218 info, _ := e.backend.SystemInfo() 219 if !info.ExperimentalBuild { 220 return ctlr, fmt.Errorf("runtime type %q only supported in experimental", swarmtypes.RuntimePlugin) 221 } 222 c, err := plugin.NewController(e.pluginBackend, t) 223 if err != nil { 224 return ctlr, err 225 } 226 ctlr = c 227 default: 228 return ctlr, fmt.Errorf("unsupported runtime type: %q", runtimeKind) 229 } 230 case *api.TaskSpec_Container: 231 c, err := newController(e.backend, t, nodeDescription, dependencyGetter) 232 if err != nil { 233 return ctlr, err 234 } 235 ctlr = c 236 default: 237 return ctlr, fmt.Errorf("unsupported runtime: %q", r) 238 } 239 240 return ctlr, nil 241 } 242 243 func (e *executor) SetNetworkBootstrapKeys(keys []*api.EncryptionKey) error { 244 nwKeys := []*networktypes.EncryptionKey{} 245 for _, key := range keys { 246 nwKey := &networktypes.EncryptionKey{ 247 Subsystem: key.Subsystem, 248 Algorithm: int32(key.Algorithm), 249 Key: make([]byte, len(key.Key)), 250 LamportTime: key.LamportTime, 251 } 252 copy(nwKey.Key, key.Key) 253 nwKeys = append(nwKeys, nwKey) 254 } 255 e.backend.SetNetworkBootstrapKeys(nwKeys) 256 257 return nil 258 } 259 260 func (e *executor) Secrets() exec.SecretsManager { 261 return e.dependencies.Secrets() 262 } 263 264 func (e *executor) Configs() exec.ConfigsManager { 265 return e.dependencies.Configs() 266 } 267 268 type sortedPlugins []api.PluginDescription 269 270 func (sp sortedPlugins) Len() int { return len(sp) } 271 272 func (sp sortedPlugins) Swap(i, j int) { sp[i], sp[j] = sp[j], sp[i] } 273 274 func (sp sortedPlugins) Less(i, j int) bool { 275 if sp[i].Type != sp[j].Type { 276 return sp[i].Type < sp[j].Type 277 } 278 return sp[i].Name < sp[j].Name 279 }