network_routes.go 11 KB

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