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