github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/api/server/router/network/network_routes.go (about) 1 package network 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 8 "strings" 9 10 "golang.org/x/net/context" 11 12 "github.com/docker/docker/api/errors" 13 "github.com/docker/docker/api/server/httputils" 14 "github.com/docker/docker/api/types" 15 "github.com/docker/docker/api/types/filters" 16 "github.com/docker/docker/api/types/network" 17 "github.com/docker/docker/api/types/versions" 18 "github.com/docker/libnetwork" 19 "github.com/docker/libnetwork/networkdb" 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.FromParam(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 func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 86 if err := httputils.ParseForm(r); err != nil { 87 return err 88 } 89 90 term := vars["id"] 91 var ( 92 verbose bool 93 err error 94 ) 95 if v := r.URL.Query().Get("verbose"); v != "" { 96 if verbose, err = strconv.ParseBool(v); err != nil { 97 err = fmt.Errorf("invalid value for verbose: %s", v) 98 return errors.NewBadRequestError(err) 99 } 100 } 101 102 // In case multiple networks have duplicate names, return error. 103 // TODO (yongtang): should we wrap with version here for backward compatibility? 104 105 // First find based on full ID, return immediately once one is found. 106 // If a network appears both in swarm and local, assume it is in local first 107 108 // For full name and partial ID, save the result first, and process later 109 // in case multiple records was found based on the same term 110 listByFullName := map[string]types.NetworkResource{} 111 listByPartialID := map[string]types.NetworkResource{} 112 113 nw := n.backend.GetNetworks() 114 for _, network := range nw { 115 if network.ID() == term { 116 return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network, verbose)) 117 } 118 if network.Name() == term { 119 // No need to check the ID collision here as we are still in 120 // local scope and the network ID is unique in this scope. 121 listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, verbose) 122 } 123 if strings.HasPrefix(network.ID(), term) { 124 // No need to check the ID collision here as we are still in 125 // local scope and the network ID is unique in this scope. 126 listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, verbose) 127 } 128 } 129 130 nr, _ := n.cluster.GetNetworks() 131 for _, network := range nr { 132 if network.ID == term { 133 return httputils.WriteJSON(w, http.StatusOK, network) 134 } 135 if network.Name == term { 136 // Check the ID collision as we are in swarm scope here, and 137 // the map (of the listByFullName) may have already had a 138 // network with the same ID (from local scope previously) 139 if _, ok := listByFullName[network.ID]; !ok { 140 listByFullName[network.ID] = network 141 } 142 } 143 if strings.HasPrefix(network.ID, term) { 144 // Check the ID collision as we are in swarm scope here, and 145 // the map (of the listByPartialID) may have already had a 146 // network with the same ID (from local scope previously) 147 if _, ok := listByPartialID[network.ID]; !ok { 148 listByPartialID[network.ID] = network 149 } 150 } 151 } 152 153 // Find based on full name, returns true only if no duplicates 154 if len(listByFullName) == 1 { 155 for _, v := range listByFullName { 156 return httputils.WriteJSON(w, http.StatusOK, v) 157 } 158 } 159 if len(listByFullName) > 1 { 160 return fmt.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)) 161 } 162 163 // Find based on partial ID, returns true only if no duplicates 164 if len(listByPartialID) == 1 { 165 for _, v := range listByPartialID { 166 return httputils.WriteJSON(w, http.StatusOK, v) 167 } 168 } 169 if len(listByPartialID) > 1 { 170 return fmt.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)) 171 } 172 173 return libnetwork.ErrNoSuchNetwork(term) 174 } 175 176 func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 177 var create types.NetworkCreateRequest 178 179 if err := httputils.ParseForm(r); err != nil { 180 return err 181 } 182 183 if err := httputils.CheckForJSON(r); err != nil { 184 return err 185 } 186 187 if err := json.NewDecoder(r.Body).Decode(&create); err != nil { 188 return err 189 } 190 191 if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 { 192 return libnetwork.NetworkNameError(create.Name) 193 } 194 195 nw, err := n.backend.CreateNetwork(create) 196 if err != nil { 197 var warning string 198 if _, ok := err.(libnetwork.NetworkNameError); ok { 199 // check if user defined CheckDuplicate, if set true, return err 200 // otherwise prepare a warning message 201 if create.CheckDuplicate { 202 return libnetwork.NetworkNameError(create.Name) 203 } 204 warning = libnetwork.NetworkNameError(create.Name).Error() 205 } 206 207 if _, ok := err.(libnetwork.ManagerRedirectError); !ok { 208 return err 209 } 210 id, err := n.cluster.CreateNetwork(create) 211 if err != nil { 212 return err 213 } 214 nw = &types.NetworkCreateResponse{ 215 ID: id, 216 Warning: warning, 217 } 218 } 219 220 return httputils.WriteJSON(w, http.StatusCreated, nw) 221 } 222 223 func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 224 var connect types.NetworkConnect 225 if err := httputils.ParseForm(r); err != nil { 226 return err 227 } 228 229 if err := httputils.CheckForJSON(r); err != nil { 230 return err 231 } 232 233 if err := json.NewDecoder(r.Body).Decode(&connect); err != nil { 234 return err 235 } 236 237 return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig) 238 } 239 240 func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 241 var disconnect types.NetworkDisconnect 242 if err := httputils.ParseForm(r); err != nil { 243 return err 244 } 245 246 if err := httputils.CheckForJSON(r); err != nil { 247 return err 248 } 249 250 if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil { 251 return err 252 } 253 254 return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force) 255 } 256 257 func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 258 if err := httputils.ParseForm(r); err != nil { 259 return err 260 } 261 if _, err := n.cluster.GetNetwork(vars["id"]); err == nil { 262 if err = n.cluster.RemoveNetwork(vars["id"]); err != nil { 263 return err 264 } 265 w.WriteHeader(http.StatusNoContent) 266 return nil 267 } 268 if err := n.backend.DeleteNetwork(vars["id"]); err != nil { 269 return err 270 } 271 w.WriteHeader(http.StatusNoContent) 272 return nil 273 } 274 275 func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { 276 r := &types.NetworkResource{} 277 if nw == nil { 278 return r 279 } 280 281 info := nw.Info() 282 r.Name = nw.Name() 283 r.ID = nw.ID() 284 r.Created = info.Created() 285 r.Scope = info.Scope() 286 r.Driver = nw.Type() 287 r.EnableIPv6 = info.IPv6Enabled() 288 r.Internal = info.Internal() 289 r.Attachable = info.Attachable() 290 r.Ingress = info.Ingress() 291 r.Options = info.DriverOptions() 292 r.Containers = make(map[string]types.EndpointResource) 293 buildIpamResources(r, info) 294 r.Labels = info.Labels() 295 r.ConfigOnly = info.ConfigOnly() 296 297 if cn := info.ConfigFrom(); cn != "" { 298 r.ConfigFrom = network.ConfigReference{Network: cn} 299 } 300 301 peers := info.Peers() 302 if len(peers) != 0 { 303 r.Peers = buildPeerInfoResources(peers) 304 } 305 306 return r 307 } 308 309 func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network, verbose bool) *types.NetworkResource { 310 if nw == nil { 311 return &types.NetworkResource{} 312 } 313 314 r := n.buildNetworkResource(nw) 315 epl := nw.Endpoints() 316 for _, e := range epl { 317 ei := e.Info() 318 if ei == nil { 319 continue 320 } 321 sb := ei.Sandbox() 322 tmpID := e.ID() 323 key := "ep-" + tmpID 324 if sb != nil { 325 key = sb.ContainerID() 326 } 327 328 r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei) 329 } 330 if !verbose { 331 return r 332 } 333 services := nw.Info().Services() 334 r.Services = make(map[string]network.ServiceInfo) 335 for name, service := range services { 336 tasks := []network.Task{} 337 for _, t := range service.Tasks { 338 tasks = append(tasks, network.Task{ 339 Name: t.Name, 340 EndpointID: t.EndpointID, 341 EndpointIP: t.EndpointIP, 342 Info: t.Info, 343 }) 344 } 345 r.Services[name] = network.ServiceInfo{ 346 VIP: service.VIP, 347 Ports: service.Ports, 348 Tasks: tasks, 349 LocalLBIndex: service.LocalLBIndex, 350 } 351 } 352 return r 353 } 354 355 func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo { 356 peerInfo := make([]network.PeerInfo, 0, len(peers)) 357 for _, peer := range peers { 358 peerInfo = append(peerInfo, network.PeerInfo{ 359 Name: peer.Name, 360 IP: peer.IP, 361 }) 362 } 363 return peerInfo 364 } 365 366 func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) { 367 id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig() 368 369 ipv4Info, ipv6Info := nwInfo.IpamInfo() 370 371 r.IPAM.Driver = id 372 373 r.IPAM.Options = opts 374 375 r.IPAM.Config = []network.IPAMConfig{} 376 for _, ip4 := range ipv4conf { 377 if ip4.PreferredPool == "" { 378 continue 379 } 380 iData := network.IPAMConfig{} 381 iData.Subnet = ip4.PreferredPool 382 iData.IPRange = ip4.SubPool 383 iData.Gateway = ip4.Gateway 384 iData.AuxAddress = ip4.AuxAddresses 385 r.IPAM.Config = append(r.IPAM.Config, iData) 386 } 387 388 if len(r.IPAM.Config) == 0 { 389 for _, ip4Info := range ipv4Info { 390 iData := network.IPAMConfig{} 391 iData.Subnet = ip4Info.IPAMData.Pool.String() 392 iData.Gateway = ip4Info.IPAMData.Gateway.IP.String() 393 r.IPAM.Config = append(r.IPAM.Config, iData) 394 } 395 } 396 397 hasIpv6Conf := false 398 for _, ip6 := range ipv6conf { 399 if ip6.PreferredPool == "" { 400 continue 401 } 402 hasIpv6Conf = true 403 iData := network.IPAMConfig{} 404 iData.Subnet = ip6.PreferredPool 405 iData.IPRange = ip6.SubPool 406 iData.Gateway = ip6.Gateway 407 iData.AuxAddress = ip6.AuxAddresses 408 r.IPAM.Config = append(r.IPAM.Config, iData) 409 } 410 411 if !hasIpv6Conf { 412 for _, ip6Info := range ipv6Info { 413 iData := network.IPAMConfig{} 414 iData.Subnet = ip6Info.IPAMData.Pool.String() 415 iData.Gateway = ip6Info.IPAMData.Gateway.String() 416 r.IPAM.Config = append(r.IPAM.Config, iData) 417 } 418 } 419 } 420 421 func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource { 422 er := types.EndpointResource{} 423 424 er.EndpointID = id 425 er.Name = name 426 ei := info 427 if ei == nil { 428 return er 429 } 430 431 if iface := ei.Iface(); iface != nil { 432 if mac := iface.MacAddress(); mac != nil { 433 er.MacAddress = mac.String() 434 } 435 if ip := iface.Address(); ip != nil && len(ip.IP) > 0 { 436 er.IPv4Address = ip.String() 437 } 438 439 if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 { 440 er.IPv6Address = ipv6.String() 441 } 442 } 443 return er 444 } 445 446 func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 447 if err := httputils.ParseForm(r); err != nil { 448 return err 449 } 450 451 pruneFilters, err := filters.FromParam(r.Form.Get("filters")) 452 if err != nil { 453 return err 454 } 455 456 pruneReport, err := n.backend.NetworksPrune(ctx, pruneFilters) 457 if err != nil { 458 return err 459 } 460 return httputils.WriteJSON(w, http.StatusOK, pruneReport) 461 }