network_routes.go 14 KB

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