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