network_routes.go 12 KB

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