github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/api/server/router/network/network_routes.go (about) 1 package network 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 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 "github.com/docker/libnetwork/networkdb" 18 ) 19 20 var ( 21 // acceptedNetworkFilters is a list of acceptable filters 22 acceptedNetworkFilters = map[string]bool{ 23 "driver": true, 24 "type": true, 25 "name": true, 26 "id": true, 27 "label": true, 28 } 29 ) 30 31 func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 32 if err := httputils.ParseForm(r); err != nil { 33 return err 34 } 35 36 filter := r.Form.Get("filters") 37 netFilters, err := filters.FromParam(filter) 38 if err != nil { 39 return err 40 } 41 42 if err := netFilters.Validate(acceptedNetworkFilters); err != nil { 43 return err 44 } 45 46 list := []types.NetworkResource{} 47 48 if nr, err := n.cluster.GetNetworks(); err == nil { 49 list = append(list, nr...) 50 } 51 52 // Combine the network list returned by Docker daemon if it is not already 53 // returned by the cluster manager 54 SKIP: 55 for _, nw := range n.backend.GetNetworks() { 56 for _, nl := range list { 57 if nl.ID == nw.ID() { 58 continue SKIP 59 } 60 } 61 62 var nr *types.NetworkResource 63 // Versions < 1.27 fetches all the containers attached to a network 64 // in a network list api call. It is a heavy weight operation when 65 // run across all the networks. Starting API version 1.27, this detailed 66 // info is available for network specific GET API (equivalent to inspect) 67 if versions.LessThan(httputils.VersionFromContext(ctx), "1.27") { 68 nr = n.buildDetailedNetworkResources(nw) 69 } else { 70 nr = n.buildNetworkResource(nw) 71 } 72 list = append(list, *nr) 73 } 74 75 list, err = filterNetworks(list, netFilters) 76 if err != nil { 77 return err 78 } 79 return httputils.WriteJSON(w, http.StatusOK, list) 80 } 81 82 func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 83 if err := httputils.ParseForm(r); err != nil { 84 return err 85 } 86 87 term := vars["id"] 88 89 // In case multiple networks have duplicate names, return error. 90 // TODO (yongtang): should we wrap with version here for backward compatibility? 91 92 // First find based on full ID, return immediately once one is found. 93 // If a network appears both in swarm and local, assume it is in local first 94 95 // For full name and partial ID, save the result first, and process later 96 // in case multiple records was found based on the same term 97 listByFullName := map[string]types.NetworkResource{} 98 listByPartialID := map[string]types.NetworkResource{} 99 100 nw := n.backend.GetNetworks() 101 for _, network := range nw { 102 if network.ID() == term { 103 return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network)) 104 } 105 if network.Name() == term { 106 // No need to check the ID collision here as we are still in 107 // local scope and the network ID is unique in this scope. 108 listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network) 109 } 110 if strings.HasPrefix(network.ID(), term) { 111 // No need to check the ID collision here as we are still in 112 // local scope and the network ID is unique in this scope. 113 listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network) 114 } 115 } 116 117 nr, _ := n.cluster.GetNetworks() 118 for _, network := range nr { 119 if network.ID == term { 120 return httputils.WriteJSON(w, http.StatusOK, network) 121 } 122 if network.Name == term { 123 // Check the ID collision as we are in swarm scope here, and 124 // the map (of the listByFullName) may have already had a 125 // network with the same ID (from local scope previously) 126 if _, ok := listByFullName[network.ID]; !ok { 127 listByFullName[network.ID] = network 128 } 129 } 130 if strings.HasPrefix(network.ID, term) { 131 // Check the ID collision as we are in swarm scope here, and 132 // the map (of the listByPartialID) may have already had a 133 // network with the same ID (from local scope previously) 134 if _, ok := listByPartialID[network.ID]; !ok { 135 listByPartialID[network.ID] = network 136 } 137 } 138 } 139 140 // Find based on full name, returns true only if no duplicates 141 if len(listByFullName) == 1 { 142 for _, v := range listByFullName { 143 return httputils.WriteJSON(w, http.StatusOK, v) 144 } 145 } 146 if len(listByFullName) > 1 { 147 return fmt.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)) 148 } 149 150 // Find based on partial ID, returns true only if no duplicates 151 if len(listByPartialID) == 1 { 152 for _, v := range listByPartialID { 153 return httputils.WriteJSON(w, http.StatusOK, v) 154 } 155 } 156 if len(listByPartialID) > 1 { 157 return fmt.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)) 158 } 159 160 return libnetwork.ErrNoSuchNetwork(term) 161 } 162 163 func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 164 var create types.NetworkCreateRequest 165 166 if err := httputils.ParseForm(r); err != nil { 167 return err 168 } 169 170 if err := httputils.CheckForJSON(r); err != nil { 171 return err 172 } 173 174 if err := json.NewDecoder(r.Body).Decode(&create); err != nil { 175 return err 176 } 177 178 if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 { 179 return libnetwork.NetworkNameError(create.Name) 180 } 181 182 nw, err := n.backend.CreateNetwork(create) 183 if err != nil { 184 if _, ok := err.(libnetwork.ManagerRedirectError); !ok { 185 return err 186 } 187 id, err := n.cluster.CreateNetwork(create) 188 if err != nil { 189 return err 190 } 191 nw = &types.NetworkCreateResponse{ID: id} 192 } 193 194 return httputils.WriteJSON(w, http.StatusCreated, nw) 195 } 196 197 func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 198 var connect types.NetworkConnect 199 if err := httputils.ParseForm(r); err != nil { 200 return err 201 } 202 203 if err := httputils.CheckForJSON(r); err != nil { 204 return err 205 } 206 207 if err := json.NewDecoder(r.Body).Decode(&connect); err != nil { 208 return err 209 } 210 211 return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig) 212 } 213 214 func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 215 var disconnect types.NetworkDisconnect 216 if err := httputils.ParseForm(r); err != nil { 217 return err 218 } 219 220 if err := httputils.CheckForJSON(r); err != nil { 221 return err 222 } 223 224 if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil { 225 return err 226 } 227 228 return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force) 229 } 230 231 func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 232 if err := httputils.ParseForm(r); err != nil { 233 return err 234 } 235 if _, err := n.cluster.GetNetwork(vars["id"]); err == nil { 236 if err = n.cluster.RemoveNetwork(vars["id"]); err != nil { 237 return err 238 } 239 w.WriteHeader(http.StatusNoContent) 240 return nil 241 } 242 if err := n.backend.DeleteNetwork(vars["id"]); err != nil { 243 return err 244 } 245 w.WriteHeader(http.StatusNoContent) 246 return nil 247 } 248 249 func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource { 250 r := &types.NetworkResource{} 251 if nw == nil { 252 return r 253 } 254 255 info := nw.Info() 256 r.Name = nw.Name() 257 r.ID = nw.ID() 258 r.Created = info.Created() 259 r.Scope = info.Scope() 260 if n.cluster.IsManager() { 261 if _, err := n.cluster.GetNetwork(nw.ID()); err == nil { 262 r.Scope = "swarm" 263 } 264 } else if info.Dynamic() { 265 r.Scope = "swarm" 266 } 267 r.Driver = nw.Type() 268 r.EnableIPv6 = info.IPv6Enabled() 269 r.Internal = info.Internal() 270 r.Attachable = info.Attachable() 271 r.Options = info.DriverOptions() 272 r.Containers = make(map[string]types.EndpointResource) 273 buildIpamResources(r, info) 274 r.Labels = info.Labels() 275 276 peers := info.Peers() 277 if len(peers) != 0 { 278 r.Peers = buildPeerInfoResources(peers) 279 } 280 281 return r 282 } 283 284 func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network) *types.NetworkResource { 285 if nw == nil { 286 return &types.NetworkResource{} 287 } 288 289 r := n.buildNetworkResource(nw) 290 epl := nw.Endpoints() 291 for _, e := range epl { 292 ei := e.Info() 293 if ei == nil { 294 continue 295 } 296 sb := ei.Sandbox() 297 tmpID := e.ID() 298 key := "ep-" + tmpID 299 if sb != nil { 300 key = sb.ContainerID() 301 } 302 303 r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei) 304 } 305 return r 306 } 307 308 func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo { 309 peerInfo := make([]network.PeerInfo, 0, len(peers)) 310 for _, peer := range peers { 311 peerInfo = append(peerInfo, network.PeerInfo{ 312 Name: peer.Name, 313 IP: peer.IP, 314 }) 315 } 316 return peerInfo 317 } 318 319 func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) { 320 id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig() 321 322 ipv4Info, ipv6Info := nwInfo.IpamInfo() 323 324 r.IPAM.Driver = id 325 326 r.IPAM.Options = opts 327 328 r.IPAM.Config = []network.IPAMConfig{} 329 for _, ip4 := range ipv4conf { 330 if ip4.PreferredPool == "" { 331 continue 332 } 333 iData := network.IPAMConfig{} 334 iData.Subnet = ip4.PreferredPool 335 iData.IPRange = ip4.SubPool 336 iData.Gateway = ip4.Gateway 337 iData.AuxAddress = ip4.AuxAddresses 338 r.IPAM.Config = append(r.IPAM.Config, iData) 339 } 340 341 if len(r.IPAM.Config) == 0 { 342 for _, ip4Info := range ipv4Info { 343 iData := network.IPAMConfig{} 344 iData.Subnet = ip4Info.IPAMData.Pool.String() 345 iData.Gateway = ip4Info.IPAMData.Gateway.IP.String() 346 r.IPAM.Config = append(r.IPAM.Config, iData) 347 } 348 } 349 350 hasIpv6Conf := false 351 for _, ip6 := range ipv6conf { 352 if ip6.PreferredPool == "" { 353 continue 354 } 355 hasIpv6Conf = true 356 iData := network.IPAMConfig{} 357 iData.Subnet = ip6.PreferredPool 358 iData.IPRange = ip6.SubPool 359 iData.Gateway = ip6.Gateway 360 iData.AuxAddress = ip6.AuxAddresses 361 r.IPAM.Config = append(r.IPAM.Config, iData) 362 } 363 364 if !hasIpv6Conf { 365 for _, ip6Info := range ipv6Info { 366 iData := network.IPAMConfig{} 367 iData.Subnet = ip6Info.IPAMData.Pool.String() 368 iData.Gateway = ip6Info.IPAMData.Gateway.String() 369 r.IPAM.Config = append(r.IPAM.Config, iData) 370 } 371 } 372 } 373 374 func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource { 375 er := types.EndpointResource{} 376 377 er.EndpointID = id 378 er.Name = name 379 ei := info 380 if ei == nil { 381 return er 382 } 383 384 if iface := ei.Iface(); iface != nil { 385 if mac := iface.MacAddress(); mac != nil { 386 er.MacAddress = mac.String() 387 } 388 if ip := iface.Address(); ip != nil && len(ip.IP) > 0 { 389 er.IPv4Address = ip.String() 390 } 391 392 if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 { 393 er.IPv6Address = ipv6.String() 394 } 395 } 396 return er 397 } 398 399 func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 400 if err := httputils.ParseForm(r); err != nil { 401 return err 402 } 403 404 pruneFilters, err := filters.FromParam(r.Form.Get("filters")) 405 if err != nil { 406 return err 407 } 408 409 pruneReport, err := n.backend.NetworksPrune(pruneFilters) 410 if err != nil { 411 return err 412 } 413 return httputils.WriteJSON(w, http.StatusOK, pruneReport) 414 }