github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/api/server/router/network/network_routes.go (about) 1 package network // import "github.com/docker/docker/api/server/router/network" 2 3 import ( 4 "encoding/json" 5 "net/http" 6 "strconv" 7 "strings" 8 9 "golang.org/x/net/context" 10 11 "github.com/docker/docker/api/server/httputils" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/api/types/filters" 14 "github.com/docker/docker/api/types/network" 15 "github.com/docker/docker/api/types/versions" 16 "github.com/docker/docker/errdefs" 17 "github.com/docker/libnetwork" 18 netconst "github.com/docker/libnetwork/datastore" 19 "github.com/docker/libnetwork/networkdb" 20 "github.com/pkg/errors" 21 ) 22 23 var ( 24 // acceptedNetworkFilters is a list of acceptable filters 25 acceptedNetworkFilters = map[string]bool{ 26 "driver": true, 27 "type": true, 28 "name": true, 29 "id": true, 30 "label": true, 31 "scope": true, 32 } 33 ) 34 35 func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 36 if err := httputils.ParseForm(r); err != nil { 37 return err 38 } 39 40 filter := r.Form.Get("filters") 41 netFilters, err := filters.FromJSON(filter) 42 if err != nil { 43 return err 44 } 45 46 if err := netFilters.Validate(acceptedNetworkFilters); err != nil { 47 return err 48 } 49 50 list := []types.NetworkResource{} 51 52 if nr, err := n.cluster.GetNetworks(); err == nil { 53 list = append(list, nr...) 54 } 55 56 // Combine the network list returned by Docker daemon if it is not already 57 // returned by the cluster manager 58 SKIP: 59 for _, nw := range n.backend.GetNetworks() { 60 for _, nl := range list { 61 if nl.ID == nw.ID() { 62 continue SKIP 63 } 64 } 65 66 var nr *types.NetworkResource 67 // Versions < 1.28 fetches all the containers attached to a network 68 // in a network list api call. It is a heavy weight operation when 69 // run across all the networks. Starting API version 1.28, this detailed 70 // info is available for network specific GET API (equivalent to inspect) 71 if versions.LessThan(httputils.VersionFromContext(ctx), "1.28") { 72 nr = n.buildDetailedNetworkResources(nw, false) 73 } else { 74 nr = n.buildNetworkResource(nw) 75 } 76 list = append(list, *nr) 77 } 78 79 list, err = filterNetworks(list, netFilters) 80 if err != nil { 81 return err 82 } 83 return httputils.WriteJSON(w, http.StatusOK, list) 84 } 85 86 type invalidRequestError struct { 87 cause error 88 } 89 90 func (e invalidRequestError) Error() string { 91 return e.cause.Error() 92 } 93 94 func (e invalidRequestError) InvalidParameter() {} 95 96 type ambigousResultsError string 97 98 func (e ambigousResultsError) Error() string { 99 return "network " + string(e) + " is ambiguous" 100 } 101 102 func (ambigousResultsError) InvalidParameter() {} 103 104 func nameConflict(name string) error { 105 return errdefs.Conflict(libnetwork.NetworkNameError(name)) 106 } 107 108 func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 109 if err := httputils.ParseForm(r); err != nil { 110 return err 111 } 112 113 term := vars["id"] 114 var ( 115 verbose bool 116 err error 117 ) 118 if v := r.URL.Query().Get("verbose"); v != "" { 119 if verbose, err = strconv.ParseBool(v); err != nil { 120 return errors.Wrapf(invalidRequestError{err}, "invalid value for verbose: %s", v) 121 } 122 } 123 scope := r.URL.Query().Get("scope") 124 125 isMatchingScope := func(scope, term string) bool { 126 if term != "" { 127 return scope == term 128 } 129 return true 130 } 131 132 // In case multiple networks have duplicate names, return error. 133 // TODO (yongtang): should we wrap with version here for backward compatibility? 134 135 // First find based on full ID, return immediately once one is found. 136 // If a network appears both in swarm and local, assume it is in local first 137 138 // For full name and partial ID, save the result first, and process later 139 // in case multiple records was found based on the same term 140 listByFullName := map[string]types.NetworkResource{} 141 listByPartialID := map[string]types.NetworkResource{} 142 143 nw := n.backend.GetNetworks() 144 for _, network := range nw { 145 if network.ID() == term && isMatchingScope(network.Info().Scope(), scope) { 146 return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network, verbose)) 147 } 148 if network.Name() == term && isMatchingScope(network.Info().Scope(), scope) { 149 // No need to check the ID collision here as we are still in 150 // local scope and the network ID is unique in this scope. 151 listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, verbose) 152 } 153 if strings.HasPrefix(network.ID(), term) && isMatchingScope(network.Info().Scope(), scope) { 154 // No need to check the ID collision here as we are still in 155 // local scope and the network ID is unique in this scope. 156 listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, verbose) 157 } 158 } 159 160 nwk, err := n.cluster.GetNetwork(term) 161 if err == nil { 162 // If the get network is passed with a specific network ID / partial network ID 163 // or if the get network was passed with a network name and scope as swarm 164 // return the network. Skipped using isMatchingScope because it is true if the scope 165 // is not set which would be case if the client API v1.30 166 if strings.HasPrefix(nwk.ID, term) || (netconst.SwarmScope == scope) { 167 // If we have a previous match "backend", return it, we need verbose when enabled 168 // ex: overlay/partial_ID or name/swarm_scope 169 if nwv, ok := listByPartialID[nwk.ID]; ok { 170 nwk = nwv 171 } else if nwv, ok := listByFullName[nwk.ID]; ok { 172 nwk = nwv 173 } 174 return httputils.WriteJSON(w, http.StatusOK, nwk) 175 } 176 } 177 178 nr, _ := n.cluster.GetNetworks() 179 for _, network := range nr { 180 if network.ID == term && isMatchingScope(network.Scope, scope) { 181 return httputils.WriteJSON(w, http.StatusOK, network) 182 } 183 if network.Name == term && isMatchingScope(network.Scope, scope) { 184 // Check the ID collision as we are in swarm scope here, and 185 // the map (of the listByFullName) may have already had a 186 // network with the same ID (from local scope previously) 187 if _, ok := listByFullName[network.ID]; !ok { 188 listByFullName[network.ID] = network 189 } 190 } 191 if strings.HasPrefix(network.ID, term) && isMatchingScope(network.Scope, scope) { 192 // Check the ID collision as we are in swarm scope here, and 193 // the map (of the listByPartialID) may have already had a 194 // network with the same ID (from local scope previously) 195 if _, ok := listByPartialID[network.ID]; !ok { 196 listByPartialID[network.ID] = network 197 } 198 } 199 } 200 201 // Find based on full name, returns true only if no duplicates 202 if len(listByFullName) == 1 { 203 for _, v := range listByFullName { 204 return httputils.WriteJSON(w, http.StatusOK, v) 205 } 206 } 207 if len(listByFullName) > 1 { 208 return errors.Wrapf(ambigousResultsError(term), "%d matches found based on name", len(listByFullName)) 209 } 210 211 // Find based on partial ID, returns true only if no duplicates 212 if len(listByPartialID) == 1 { 213 for _, v := range listByPartialID { 214 return httputils.WriteJSON(w, http.StatusOK, v) 215 } 216 } 217 if len(listByPartialID) > 1 { 218 return errors.Wrapf(ambigousResultsError(term), "%d matches found based on ID prefix", len(listByPartialID)) 219 } 220 221 return libnetwork.ErrNoSuchNetwork(term) 222 } 223 224 func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 225 var create types.NetworkCreateRequest 226 227 if err := httputils.ParseForm(r); err != nil { 228 return err 229 } 230 231 if err := httputils.CheckForJSON(r); err != nil { 232 return err 233 } 234 235 if err := json.NewDecoder(r.Body).Decode(&create); err != nil { 236 return err 237 } 238 239 if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 { 240 return nameConflict(create.Name) 241 } 242 243 nw, err := n.backend.CreateNetwork(create) 244 if err != nil { 245 var warning string 246 if _, ok := err.(libnetwork.NetworkNameError); ok { 247 // check if user defined CheckDuplicate, if set true, return err 248 // otherwise prepare a warning message 249 if create.CheckDuplicate { 250 return nameConflict(create.Name) 251 } 252 warning = libnetwork.NetworkNameError(create.Name).Error() 253 } 254 255 if _, ok := err.(libnetwork.ManagerRedirectError); !ok { 256 return err 257 } 258 id, err := n.cluster.CreateNetwork(create) 259 if err != nil { 260 return err 261 } 262 nw = &types.NetworkCreateResponse{ 263 ID: id, 264 Warning: warning, 265 } 266 } 267 268 return httputils.WriteJSON(w, http.StatusCreated, nw) 269 } 270 271 func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 272 var connect types.NetworkConnect 273 if err := httputils.ParseForm(r); err != nil { 274 return err 275 } 276 277 if err := httputils.CheckForJSON(r); err != nil { 278 return err 279 } 280 281 if err := json.NewDecoder(r.Body).Decode(&connect); err != nil { 282 return err 283 } 284 285 // Unlike other operations, we does not check ambiguity of the name/ID here. 286 // The reason is that, In case of attachable network in swarm scope, the actual local network 287 // may not be available at the time. At the same time, inside daemon `ConnectContainerToNetwork` 288 // does the ambiguity check anyway. Therefore, passing the name to daemon would be enough. 289 return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig) 290 } 291 292 func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 293 var disconnect types.NetworkDisconnect 294 if err := httputils.ParseForm(r); err != nil { 295 return err 296 } 297 298 if err := httputils.CheckForJSON(r); err != nil { 299 return err 300 } 301 302 if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil { 303 return err 304 } 305 306 return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force) 307 } 308 309 func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 310 if err := httputils.ParseForm(r); err != nil { 311 return err 312 } 313 314 nw, err := n.findUniqueNetwork(vars["id"]) 315 if err != nil { 316 return err 317 } 318 if nw.Scope == "swarm" { 319 if err = n.cluster.RemoveNetwork(nw.ID); err != nil { 320 return err 321 } 322 } else { 323 if err := n.backend.DeleteNetwork(nw.ID); err != nil { 324 return err 325 } 326 } 327 w.WriteHeader(http.StatusNoContent) 328 return nil 329 } 330 331 func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { 332 r := &types.NetworkResource{} 333 if nw == nil { 334 return r 335 } 336 337 info := nw.Info() 338 r.Name = nw.Name() 339 r.ID = nw.ID() 340 r.Created = info.Created() 341 r.Scope = info.Scope() 342 r.Driver = nw.Type() 343 r.EnableIPv6 = info.IPv6Enabled() 344 r.Internal = info.Internal() 345 r.Attachable = info.Attachable() 346 r.Ingress = info.Ingress() 347 r.Options = info.DriverOptions() 348 r.Containers = make(map[string]types.EndpointResource) 349 buildIpamResources(r, info) 350 r.Labels = info.Labels() 351 r.ConfigOnly = info.ConfigOnly() 352 353 if cn := info.ConfigFrom(); cn != "" { 354 r.ConfigFrom = network.ConfigReference{Network: cn} 355 } 356 357 peers := info.Peers() 358 if len(peers) != 0 { 359 r.Peers = buildPeerInfoResources(peers) 360 } 361 362 return r 363 } 364 365 func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network, verbose bool) *types.NetworkResource { 366 if nw == nil { 367 return &types.NetworkResource{} 368 } 369 370 r := n.buildNetworkResource(nw) 371 epl := nw.Endpoints() 372 for _, e := range epl { 373 ei := e.Info() 374 if ei == nil { 375 continue 376 } 377 sb := ei.Sandbox() 378 tmpID := e.ID() 379 key := "ep-" + tmpID 380 if sb != nil { 381 key = sb.ContainerID() 382 } 383 384 r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei) 385 } 386 if !verbose { 387 return r 388 } 389 services := nw.Info().Services() 390 r.Services = make(map[string]network.ServiceInfo) 391 for name, service := range services { 392 tasks := []network.Task{} 393 for _, t := range service.Tasks { 394 tasks = append(tasks, network.Task{ 395 Name: t.Name, 396 EndpointID: t.EndpointID, 397 EndpointIP: t.EndpointIP, 398 Info: t.Info, 399 }) 400 } 401 r.Services[name] = network.ServiceInfo{ 402 VIP: service.VIP, 403 Ports: service.Ports, 404 Tasks: tasks, 405 LocalLBIndex: service.LocalLBIndex, 406 } 407 } 408 return r 409 } 410 411 func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo { 412 peerInfo := make([]network.PeerInfo, 0, len(peers)) 413 for _, peer := range peers { 414 peerInfo = append(peerInfo, network.PeerInfo{ 415 Name: peer.Name, 416 IP: peer.IP, 417 }) 418 } 419 return peerInfo 420 } 421 422 func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) { 423 id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig() 424 425 ipv4Info, ipv6Info := nwInfo.IpamInfo() 426 427 r.IPAM.Driver = id 428 429 r.IPAM.Options = opts 430 431 r.IPAM.Config = []network.IPAMConfig{} 432 for _, ip4 := range ipv4conf { 433 if ip4.PreferredPool == "" { 434 continue 435 } 436 iData := network.IPAMConfig{} 437 iData.Subnet = ip4.PreferredPool 438 iData.IPRange = ip4.SubPool 439 iData.Gateway = ip4.Gateway 440 iData.AuxAddress = ip4.AuxAddresses 441 r.IPAM.Config = append(r.IPAM.Config, iData) 442 } 443 444 if len(r.IPAM.Config) == 0 { 445 for _, ip4Info := range ipv4Info { 446 iData := network.IPAMConfig{} 447 iData.Subnet = ip4Info.IPAMData.Pool.String() 448 if ip4Info.IPAMData.Gateway != nil { 449 iData.Gateway = ip4Info.IPAMData.Gateway.IP.String() 450 } 451 r.IPAM.Config = append(r.IPAM.Config, iData) 452 } 453 } 454 455 hasIpv6Conf := false 456 for _, ip6 := range ipv6conf { 457 if ip6.PreferredPool == "" { 458 continue 459 } 460 hasIpv6Conf = true 461 iData := network.IPAMConfig{} 462 iData.Subnet = ip6.PreferredPool 463 iData.IPRange = ip6.SubPool 464 iData.Gateway = ip6.Gateway 465 iData.AuxAddress = ip6.AuxAddresses 466 r.IPAM.Config = append(r.IPAM.Config, iData) 467 } 468 469 if !hasIpv6Conf { 470 for _, ip6Info := range ipv6Info { 471 if ip6Info.IPAMData.Pool == nil { 472 continue 473 } 474 iData := network.IPAMConfig{} 475 iData.Subnet = ip6Info.IPAMData.Pool.String() 476 iData.Gateway = ip6Info.IPAMData.Gateway.String() 477 r.IPAM.Config = append(r.IPAM.Config, iData) 478 } 479 } 480 } 481 482 func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource { 483 er := types.EndpointResource{} 484 485 er.EndpointID = id 486 er.Name = name 487 ei := info 488 if ei == nil { 489 return er 490 } 491 492 if iface := ei.Iface(); iface != nil { 493 if mac := iface.MacAddress(); mac != nil { 494 er.MacAddress = mac.String() 495 } 496 if ip := iface.Address(); ip != nil && len(ip.IP) > 0 { 497 er.IPv4Address = ip.String() 498 } 499 500 if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 { 501 er.IPv6Address = ipv6.String() 502 } 503 } 504 return er 505 } 506 507 func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 508 if err := httputils.ParseForm(r); err != nil { 509 return err 510 } 511 512 pruneFilters, err := filters.FromJSON(r.Form.Get("filters")) 513 if err != nil { 514 return err 515 } 516 517 pruneReport, err := n.backend.NetworksPrune(ctx, pruneFilters) 518 if err != nil { 519 return err 520 } 521 return httputils.WriteJSON(w, http.StatusOK, pruneReport) 522 } 523 524 // findUniqueNetwork will search network across different scopes (both local and swarm). 525 // NOTE: This findUniqueNetwork is different from FindNetwork in the daemon. 526 // In case multiple networks have duplicate names, return error. 527 // First find based on full ID, return immediately once one is found. 528 // If a network appears both in swarm and local, assume it is in local first 529 // For full name and partial ID, save the result first, and process later 530 // in case multiple records was found based on the same term 531 // TODO (yongtang): should we wrap with version here for backward compatibility? 532 func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, error) { 533 listByFullName := map[string]types.NetworkResource{} 534 listByPartialID := map[string]types.NetworkResource{} 535 536 nw := n.backend.GetNetworks() 537 for _, network := range nw { 538 if network.ID() == term { 539 return *n.buildDetailedNetworkResources(network, false), nil 540 541 } 542 if network.Name() == term && !network.Info().Ingress() { 543 // No need to check the ID collision here as we are still in 544 // local scope and the network ID is unique in this scope. 545 listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, false) 546 } 547 if strings.HasPrefix(network.ID(), term) { 548 // No need to check the ID collision here as we are still in 549 // local scope and the network ID is unique in this scope. 550 listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, false) 551 } 552 } 553 554 nr, _ := n.cluster.GetNetworks() 555 for _, network := range nr { 556 if network.ID == term { 557 return network, nil 558 } 559 if network.Name == term { 560 // Check the ID collision as we are in swarm scope here, and 561 // the map (of the listByFullName) may have already had a 562 // network with the same ID (from local scope previously) 563 if _, ok := listByFullName[network.ID]; !ok { 564 listByFullName[network.ID] = network 565 } 566 } 567 if strings.HasPrefix(network.ID, term) { 568 // Check the ID collision as we are in swarm scope here, and 569 // the map (of the listByPartialID) may have already had a 570 // network with the same ID (from local scope previously) 571 if _, ok := listByPartialID[network.ID]; !ok { 572 listByPartialID[network.ID] = network 573 } 574 } 575 } 576 577 // Find based on full name, returns true only if no duplicates 578 if len(listByFullName) == 1 { 579 for _, v := range listByFullName { 580 return v, nil 581 } 582 } 583 if len(listByFullName) > 1 { 584 return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName))) 585 } 586 587 // Find based on partial ID, returns true only if no duplicates 588 if len(listByPartialID) == 1 { 589 for _, v := range listByPartialID { 590 return v, nil 591 } 592 } 593 if len(listByPartialID) > 1 { 594 return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID))) 595 } 596 597 return types.NetworkResource{}, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term)) 598 }