api.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. package api
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "strings"
  8. "github.com/docker/libnetwork"
  9. "github.com/docker/libnetwork/netlabel"
  10. "github.com/docker/libnetwork/types"
  11. "github.com/gorilla/mux"
  12. )
  13. var (
  14. successResponse = responseStatus{Status: "Success", StatusCode: http.StatusOK}
  15. createdResponse = responseStatus{Status: "Created", StatusCode: http.StatusCreated}
  16. mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest}
  17. badQueryResponse = responseStatus{Status: "Unsupported query", StatusCode: http.StatusBadRequest}
  18. )
  19. const (
  20. // Resource name regex
  21. // Gorilla mux encloses the passed pattern with '^' and '$'. So we need to do some tricks
  22. // to have mux eventually build a query regex which matches empty or word string (`^$|[\w]+`)
  23. regex = "[a-zA-Z_0-9-]+"
  24. qregx = "$|" + regex
  25. // Router URL variable definition
  26. nwName = "{" + urlNwName + ":" + regex + "}"
  27. nwNameQr = "{" + urlNwName + ":" + qregx + "}"
  28. nwID = "{" + urlNwID + ":" + regex + "}"
  29. nwPIDQr = "{" + urlNwPID + ":" + qregx + "}"
  30. epName = "{" + urlEpName + ":" + regex + "}"
  31. epNameQr = "{" + urlEpName + ":" + qregx + "}"
  32. epID = "{" + urlEpID + ":" + regex + "}"
  33. epPIDQr = "{" + urlEpPID + ":" + qregx + "}"
  34. cnID = "{" + urlCnID + ":" + regex + "}"
  35. // Internal URL variable name.They can be anything as
  36. // long as they do not collide with query fields.
  37. urlNwName = "network-name"
  38. urlNwID = "network-id"
  39. urlNwPID = "network-partial-id"
  40. urlEpName = "endpoint-name"
  41. urlEpID = "endpoint-id"
  42. urlEpPID = "endpoint-partial-id"
  43. urlCnID = "container-id"
  44. // BridgeNetworkDriver is the built-in default for Network Driver
  45. BridgeNetworkDriver = "bridge"
  46. )
  47. // NewHTTPHandler creates and initialize the HTTP handler to serve the requests for libnetwork
  48. func NewHTTPHandler(c libnetwork.NetworkController) func(w http.ResponseWriter, req *http.Request) {
  49. h := &httpHandler{c: c}
  50. h.initRouter()
  51. return h.handleRequest
  52. }
  53. type responseStatus struct {
  54. Status string
  55. StatusCode int
  56. }
  57. func (r *responseStatus) isOK() bool {
  58. return r.StatusCode == http.StatusOK || r.StatusCode == http.StatusCreated
  59. }
  60. type processor func(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus)
  61. type httpHandler struct {
  62. c libnetwork.NetworkController
  63. r *mux.Router
  64. }
  65. func (h *httpHandler) handleRequest(w http.ResponseWriter, req *http.Request) {
  66. // Make sure the service is there
  67. if h.c == nil {
  68. http.Error(w, "NetworkController is not available", http.StatusServiceUnavailable)
  69. return
  70. }
  71. // Get handler from router and execute it
  72. h.r.ServeHTTP(w, req)
  73. }
  74. func (h *httpHandler) initRouter() {
  75. m := map[string][]struct {
  76. url string
  77. qrs []string
  78. fct processor
  79. }{
  80. "GET": {
  81. // Order matters
  82. {"/networks", []string{"name", nwNameQr}, procGetNetworks},
  83. {"/networks", []string{"partial-id", nwPIDQr}, procGetNetworks},
  84. {"/networks", nil, procGetNetworks},
  85. {"/networks/" + nwID, nil, procGetNetwork},
  86. {"/networks/" + nwID + "/endpoints", []string{"name", epNameQr}, procGetEndpoints},
  87. {"/networks/" + nwID + "/endpoints", []string{"partial-id", epPIDQr}, procGetEndpoints},
  88. {"/networks/" + nwID + "/endpoints", nil, procGetEndpoints},
  89. {"/networks/" + nwID + "/endpoints/" + epID, nil, procGetEndpoint},
  90. {"/services", []string{"network", nwNameQr}, procGetServices},
  91. {"/services", []string{"name", epNameQr}, procGetServices},
  92. {"/services", []string{"partial-id", epPIDQr}, procGetServices},
  93. {"/services", nil, procGetServices},
  94. {"/services/" + epID, nil, procGetService},
  95. {"/services/" + epID + "/backend", nil, procGetContainers},
  96. },
  97. "POST": {
  98. {"/networks", nil, procCreateNetwork},
  99. {"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
  100. {"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint},
  101. {"/services", nil, procPublishService},
  102. {"/services/" + epID + "/backend", nil, procAttachBackend},
  103. },
  104. "DELETE": {
  105. {"/networks/" + nwID, nil, procDeleteNetwork},
  106. {"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint},
  107. {"/networks/" + nwID + "/endpoints/" + epID + "/containers/" + cnID, nil, procLeaveEndpoint},
  108. {"/services/" + epID, nil, procUnpublishService},
  109. {"/services/" + epID + "/backend/" + cnID, nil, procDetachBackend},
  110. },
  111. }
  112. h.r = mux.NewRouter()
  113. for method, routes := range m {
  114. for _, route := range routes {
  115. r := h.r.Path("/{.*}" + route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct))
  116. if route.qrs != nil {
  117. r.Queries(route.qrs...)
  118. }
  119. r = h.r.Path(route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct))
  120. if route.qrs != nil {
  121. r.Queries(route.qrs...)
  122. }
  123. }
  124. }
  125. }
  126. func makeHandler(ctrl libnetwork.NetworkController, fct processor) http.HandlerFunc {
  127. return func(w http.ResponseWriter, req *http.Request) {
  128. var (
  129. body []byte
  130. err error
  131. )
  132. if req.Body != nil {
  133. body, err = ioutil.ReadAll(req.Body)
  134. if err != nil {
  135. http.Error(w, "Invalid body: "+err.Error(), http.StatusBadRequest)
  136. return
  137. }
  138. }
  139. res, rsp := fct(ctrl, mux.Vars(req), body)
  140. if res != nil {
  141. writeJSON(w, rsp.StatusCode, res)
  142. }
  143. }
  144. }
  145. /*****************
  146. Resource Builders
  147. ******************/
  148. func buildNetworkResource(nw libnetwork.Network) *networkResource {
  149. r := &networkResource{}
  150. if nw != nil {
  151. r.Name = nw.Name()
  152. r.ID = nw.ID()
  153. r.Type = nw.Type()
  154. epl := nw.Endpoints()
  155. r.Endpoints = make([]*endpointResource, 0, len(epl))
  156. for _, e := range epl {
  157. epr := buildEndpointResource(e)
  158. r.Endpoints = append(r.Endpoints, epr)
  159. }
  160. }
  161. return r
  162. }
  163. func buildEndpointResource(ep libnetwork.Endpoint) *endpointResource {
  164. r := &endpointResource{}
  165. if ep != nil {
  166. r.Name = ep.Name()
  167. r.ID = ep.ID()
  168. r.Network = ep.Network()
  169. }
  170. return r
  171. }
  172. func buildContainerResource(ci libnetwork.ContainerInfo) *containerResource {
  173. r := &containerResource{}
  174. if ci != nil {
  175. r.ID = ci.ID()
  176. }
  177. return r
  178. }
  179. /****************
  180. Options Parsers
  181. *****************/
  182. func (nc *networkCreate) parseOptions() []libnetwork.NetworkOption {
  183. var setFctList []libnetwork.NetworkOption
  184. if nc.Options != nil {
  185. setFctList = append(setFctList, libnetwork.NetworkOptionGeneric(nc.Options))
  186. }
  187. return setFctList
  188. }
  189. func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
  190. var setFctList []libnetwork.EndpointOption
  191. if ej.HostName != "" {
  192. setFctList = append(setFctList, libnetwork.JoinOptionHostname(ej.HostName))
  193. }
  194. if ej.DomainName != "" {
  195. setFctList = append(setFctList, libnetwork.JoinOptionDomainname(ej.DomainName))
  196. }
  197. if ej.HostsPath != "" {
  198. setFctList = append(setFctList, libnetwork.JoinOptionHostsPath(ej.HostsPath))
  199. }
  200. if ej.ResolvConfPath != "" {
  201. setFctList = append(setFctList, libnetwork.JoinOptionResolvConfPath(ej.ResolvConfPath))
  202. }
  203. if ej.UseDefaultSandbox {
  204. setFctList = append(setFctList, libnetwork.JoinOptionUseDefaultSandbox())
  205. }
  206. if ej.DNS != nil {
  207. for _, d := range ej.DNS {
  208. setFctList = append(setFctList, libnetwork.JoinOptionDNS(d))
  209. }
  210. }
  211. if ej.ExtraHosts != nil {
  212. for _, e := range ej.ExtraHosts {
  213. setFctList = append(setFctList, libnetwork.JoinOptionExtraHost(e.Name, e.Address))
  214. }
  215. }
  216. if ej.ParentUpdates != nil {
  217. for _, p := range ej.ParentUpdates {
  218. setFctList = append(setFctList, libnetwork.JoinOptionParentUpdate(p.EndpointID, p.Name, p.Address))
  219. }
  220. }
  221. return setFctList
  222. }
  223. /******************
  224. Process functions
  225. *******************/
  226. func processCreateDefaults(c libnetwork.NetworkController, nc *networkCreate) {
  227. if nc.NetworkType == "" {
  228. nc.NetworkType = c.Config().Daemon.DefaultDriver
  229. }
  230. if nc.NetworkType == BridgeNetworkDriver {
  231. if nc.Options == nil {
  232. nc.Options = make(map[string]interface{})
  233. }
  234. genericData, ok := nc.Options[netlabel.GenericData]
  235. if !ok {
  236. genericData = make(map[string]interface{})
  237. }
  238. gData := genericData.(map[string]interface{})
  239. if _, ok := gData["BridgeName"]; !ok {
  240. gData["BridgeName"] = nc.Name
  241. }
  242. if _, ok := gData["AllowNonDefaultBridge"]; !ok {
  243. gData["AllowNonDefaultBridge"] = "true"
  244. }
  245. nc.Options[netlabel.GenericData] = genericData
  246. }
  247. }
  248. /***************************
  249. NetworkController interface
  250. ****************************/
  251. func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  252. var create networkCreate
  253. err := json.Unmarshal(body, &create)
  254. if err != nil {
  255. return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
  256. }
  257. processCreateDefaults(c, &create)
  258. nw, err := c.NewNetwork(create.NetworkType, create.Name, create.parseOptions()...)
  259. if err != nil {
  260. return "", convertNetworkError(err)
  261. }
  262. return nw.ID(), &createdResponse
  263. }
  264. func procGetNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  265. t, by := detectNetworkTarget(vars)
  266. nw, errRsp := findNetwork(c, t, by)
  267. if !errRsp.isOK() {
  268. return nil, errRsp
  269. }
  270. return buildNetworkResource(nw), &successResponse
  271. }
  272. func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  273. var list []*networkResource
  274. // Look for query filters and validate
  275. name, queryByName := vars[urlNwName]
  276. shortID, queryByPid := vars[urlNwPID]
  277. if queryByName && queryByPid {
  278. return nil, &badQueryResponse
  279. }
  280. if queryByName {
  281. if nw, errRsp := findNetwork(c, name, byName); errRsp.isOK() {
  282. list = append(list, buildNetworkResource(nw))
  283. }
  284. } else if queryByPid {
  285. // Return all the prefix-matching networks
  286. l := func(nw libnetwork.Network) bool {
  287. if strings.HasPrefix(nw.ID(), shortID) {
  288. list = append(list, buildNetworkResource(nw))
  289. }
  290. return false
  291. }
  292. c.WalkNetworks(l)
  293. } else {
  294. for _, nw := range c.Networks() {
  295. list = append(list, buildNetworkResource(nw))
  296. }
  297. }
  298. return list, &successResponse
  299. }
  300. /******************
  301. Network interface
  302. *******************/
  303. func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  304. var ec endpointCreate
  305. err := json.Unmarshal(body, &ec)
  306. if err != nil {
  307. return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
  308. }
  309. nwT, nwBy := detectNetworkTarget(vars)
  310. n, errRsp := findNetwork(c, nwT, nwBy)
  311. if !errRsp.isOK() {
  312. return "", errRsp
  313. }
  314. var setFctList []libnetwork.EndpointOption
  315. if ec.ExposedPorts != nil {
  316. setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(ec.ExposedPorts))
  317. }
  318. if ec.PortMapping != nil {
  319. setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(ec.PortMapping))
  320. }
  321. ep, err := n.CreateEndpoint(ec.Name, setFctList...)
  322. if err != nil {
  323. return "", convertNetworkError(err)
  324. }
  325. return ep.ID(), &createdResponse
  326. }
  327. func procGetEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  328. nwT, nwBy := detectNetworkTarget(vars)
  329. epT, epBy := detectEndpointTarget(vars)
  330. ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy)
  331. if !errRsp.isOK() {
  332. return nil, errRsp
  333. }
  334. return buildEndpointResource(ep), &successResponse
  335. }
  336. func procGetEndpoints(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  337. // Look for query filters and validate
  338. name, queryByName := vars[urlEpName]
  339. shortID, queryByPid := vars[urlEpPID]
  340. if queryByName && queryByPid {
  341. return nil, &badQueryResponse
  342. }
  343. nwT, nwBy := detectNetworkTarget(vars)
  344. nw, errRsp := findNetwork(c, nwT, nwBy)
  345. if !errRsp.isOK() {
  346. return nil, errRsp
  347. }
  348. var list []*endpointResource
  349. // If query parameter is specified, return a filtered collection
  350. if queryByName {
  351. if ep, errRsp := findEndpoint(c, nwT, name, nwBy, byName); errRsp.isOK() {
  352. list = append(list, buildEndpointResource(ep))
  353. }
  354. } else if queryByPid {
  355. // Return all the prefix-matching endpoints
  356. l := func(ep libnetwork.Endpoint) bool {
  357. if strings.HasPrefix(ep.ID(), shortID) {
  358. list = append(list, buildEndpointResource(ep))
  359. }
  360. return false
  361. }
  362. nw.WalkEndpoints(l)
  363. } else {
  364. for _, ep := range nw.Endpoints() {
  365. epr := buildEndpointResource(ep)
  366. list = append(list, epr)
  367. }
  368. }
  369. return list, &successResponse
  370. }
  371. func procDeleteNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  372. target, by := detectNetworkTarget(vars)
  373. nw, errRsp := findNetwork(c, target, by)
  374. if !errRsp.isOK() {
  375. return nil, errRsp
  376. }
  377. err := nw.Delete()
  378. if err != nil {
  379. return nil, convertNetworkError(err)
  380. }
  381. return nil, &successResponse
  382. }
  383. /******************
  384. Endpoint interface
  385. *******************/
  386. func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  387. var ej endpointJoin
  388. err := json.Unmarshal(body, &ej)
  389. if err != nil {
  390. return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
  391. }
  392. nwT, nwBy := detectNetworkTarget(vars)
  393. epT, epBy := detectEndpointTarget(vars)
  394. ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy)
  395. if !errRsp.isOK() {
  396. return nil, errRsp
  397. }
  398. err = ep.Join(ej.ContainerID, ej.parseOptions()...)
  399. if err != nil {
  400. return nil, convertNetworkError(err)
  401. }
  402. return ep.Info().SandboxKey(), &successResponse
  403. }
  404. func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  405. nwT, nwBy := detectNetworkTarget(vars)
  406. epT, epBy := detectEndpointTarget(vars)
  407. ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy)
  408. if !errRsp.isOK() {
  409. return nil, errRsp
  410. }
  411. err := ep.Leave(vars[urlCnID])
  412. if err != nil {
  413. return nil, convertNetworkError(err)
  414. }
  415. return nil, &successResponse
  416. }
  417. func procDeleteEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  418. nwT, nwBy := detectNetworkTarget(vars)
  419. epT, epBy := detectEndpointTarget(vars)
  420. ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy)
  421. if !errRsp.isOK() {
  422. return nil, errRsp
  423. }
  424. err := ep.Delete()
  425. if err != nil {
  426. return nil, convertNetworkError(err)
  427. }
  428. return nil, &successResponse
  429. }
  430. /******************
  431. Service interface
  432. *******************/
  433. func procGetServices(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  434. // Look for query filters and validate
  435. nwName, filterByNwName := vars[urlNwName]
  436. svName, queryBySvName := vars[urlEpName]
  437. shortID, queryBySvPID := vars[urlEpPID]
  438. if filterByNwName && queryBySvName || filterByNwName && queryBySvPID || queryBySvName && queryBySvPID {
  439. return nil, &badQueryResponse
  440. }
  441. var list []*endpointResource
  442. switch {
  443. case filterByNwName:
  444. // return all service present on the specified network
  445. nw, errRsp := findNetwork(c, nwName, byName)
  446. if !errRsp.isOK() {
  447. return list, &successResponse
  448. }
  449. for _, ep := range nw.Endpoints() {
  450. epr := buildEndpointResource(ep)
  451. list = append(list, epr)
  452. }
  453. case queryBySvName:
  454. // Look in each network for the service with the specified name
  455. l := func(ep libnetwork.Endpoint) bool {
  456. if ep.Name() == svName {
  457. list = append(list, buildEndpointResource(ep))
  458. return true
  459. }
  460. return false
  461. }
  462. for _, nw := range c.Networks() {
  463. nw.WalkEndpoints(l)
  464. }
  465. case queryBySvPID:
  466. // Return all the prefix-matching services
  467. l := func(ep libnetwork.Endpoint) bool {
  468. if strings.HasPrefix(ep.ID(), shortID) {
  469. list = append(list, buildEndpointResource(ep))
  470. }
  471. return false
  472. }
  473. for _, nw := range c.Networks() {
  474. nw.WalkEndpoints(l)
  475. }
  476. default:
  477. for _, nw := range c.Networks() {
  478. for _, ep := range nw.Endpoints() {
  479. epr := buildEndpointResource(ep)
  480. list = append(list, epr)
  481. }
  482. }
  483. }
  484. return list, &successResponse
  485. }
  486. func procGetService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  487. epT, epBy := detectEndpointTarget(vars)
  488. sv, errRsp := findService(c, epT, epBy)
  489. if !errRsp.isOK() {
  490. return nil, endpointToService(errRsp)
  491. }
  492. return buildEndpointResource(sv), &successResponse
  493. }
  494. func procGetContainers(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  495. epT, epBy := detectEndpointTarget(vars)
  496. sv, errRsp := findService(c, epT, epBy)
  497. if !errRsp.isOK() {
  498. return nil, endpointToService(errRsp)
  499. }
  500. var list []*containerResource
  501. if sv.ContainerInfo() != nil {
  502. list = append(list, buildContainerResource(sv.ContainerInfo()))
  503. }
  504. return list, &successResponse
  505. }
  506. func procPublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  507. var sp servicePublish
  508. err := json.Unmarshal(body, &sp)
  509. if err != nil {
  510. return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
  511. }
  512. n, errRsp := findNetwork(c, sp.Network, byName)
  513. if !errRsp.isOK() {
  514. return "", errRsp
  515. }
  516. var setFctList []libnetwork.EndpointOption
  517. if sp.ExposedPorts != nil {
  518. setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(sp.ExposedPorts))
  519. }
  520. if sp.PortMapping != nil {
  521. setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(sp.PortMapping))
  522. }
  523. ep, err := n.CreateEndpoint(sp.Name, setFctList...)
  524. if err != nil {
  525. return "", endpointToService(convertNetworkError(err))
  526. }
  527. return ep.ID(), &createdResponse
  528. }
  529. func procUnpublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  530. epT, epBy := detectEndpointTarget(vars)
  531. sv, errRsp := findService(c, epT, epBy)
  532. if !errRsp.isOK() {
  533. return nil, errRsp
  534. }
  535. err := sv.Delete()
  536. if err != nil {
  537. return nil, endpointToService(convertNetworkError(err))
  538. }
  539. return nil, &successResponse
  540. }
  541. func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  542. var bk endpointJoin
  543. err := json.Unmarshal(body, &bk)
  544. if err != nil {
  545. return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
  546. }
  547. epT, epBy := detectEndpointTarget(vars)
  548. sv, errRsp := findService(c, epT, epBy)
  549. if !errRsp.isOK() {
  550. return nil, errRsp
  551. }
  552. err = sv.Join(bk.ContainerID, bk.parseOptions()...)
  553. if err != nil {
  554. return nil, convertNetworkError(err)
  555. }
  556. return sv.Info().SandboxKey(), &successResponse
  557. }
  558. func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
  559. epT, epBy := detectEndpointTarget(vars)
  560. sv, errRsp := findService(c, epT, epBy)
  561. if !errRsp.isOK() {
  562. return nil, errRsp
  563. }
  564. err := sv.Leave(vars[urlCnID])
  565. if err != nil {
  566. return nil, convertNetworkError(err)
  567. }
  568. return nil, &successResponse
  569. }
  570. /***********
  571. Utilities
  572. ************/
  573. const (
  574. byID = iota
  575. byName
  576. )
  577. func detectNetworkTarget(vars map[string]string) (string, int) {
  578. if target, ok := vars[urlNwName]; ok {
  579. return target, byName
  580. }
  581. if target, ok := vars[urlNwID]; ok {
  582. return target, byID
  583. }
  584. // vars are populated from the URL, following cannot happen
  585. panic("Missing URL variable parameter for network")
  586. }
  587. func detectEndpointTarget(vars map[string]string) (string, int) {
  588. if target, ok := vars[urlEpName]; ok {
  589. return target, byName
  590. }
  591. if target, ok := vars[urlEpID]; ok {
  592. return target, byID
  593. }
  594. // vars are populated from the URL, following cannot happen
  595. panic("Missing URL variable parameter for endpoint")
  596. }
  597. func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.Network, *responseStatus) {
  598. var (
  599. nw libnetwork.Network
  600. err error
  601. )
  602. switch by {
  603. case byID:
  604. nw, err = c.NetworkByID(s)
  605. case byName:
  606. if s == "" {
  607. s = c.Config().Daemon.DefaultNetwork
  608. }
  609. nw, err = c.NetworkByName(s)
  610. default:
  611. panic(fmt.Sprintf("unexpected selector for network search: %d", by))
  612. }
  613. if err != nil {
  614. if _, ok := err.(types.NotFoundError); ok {
  615. return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
  616. }
  617. return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
  618. }
  619. return nw, &successResponse
  620. }
  621. func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) (libnetwork.Endpoint, *responseStatus) {
  622. nw, errRsp := findNetwork(c, ns, nwBy)
  623. if !errRsp.isOK() {
  624. return nil, errRsp
  625. }
  626. var (
  627. err error
  628. ep libnetwork.Endpoint
  629. )
  630. switch epBy {
  631. case byID:
  632. ep, err = nw.EndpointByID(es)
  633. case byName:
  634. ep, err = nw.EndpointByName(es)
  635. default:
  636. panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
  637. }
  638. if err != nil {
  639. if _, ok := err.(types.NotFoundError); ok {
  640. return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
  641. }
  642. return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
  643. }
  644. return ep, &successResponse
  645. }
  646. func findService(c libnetwork.NetworkController, svs string, svBy int) (libnetwork.Endpoint, *responseStatus) {
  647. for _, nw := range c.Networks() {
  648. var (
  649. ep libnetwork.Endpoint
  650. err error
  651. )
  652. switch svBy {
  653. case byID:
  654. ep, err = nw.EndpointByID(svs)
  655. case byName:
  656. ep, err = nw.EndpointByName(svs)
  657. default:
  658. panic(fmt.Sprintf("unexpected selector for service search: %d", svBy))
  659. }
  660. if err == nil {
  661. return ep, &successResponse
  662. } else if _, ok := err.(types.NotFoundError); !ok {
  663. return nil, convertNetworkError(err)
  664. }
  665. }
  666. return nil, &responseStatus{Status: "Service not found", StatusCode: http.StatusNotFound}
  667. }
  668. func endpointToService(rsp *responseStatus) *responseStatus {
  669. rsp.Status = strings.Replace(rsp.Status, "endpoint", "service", -1)
  670. return rsp
  671. }
  672. func convertNetworkError(err error) *responseStatus {
  673. var code int
  674. switch err.(type) {
  675. case types.BadRequestError:
  676. code = http.StatusBadRequest
  677. case types.ForbiddenError:
  678. code = http.StatusForbidden
  679. case types.NotFoundError:
  680. code = http.StatusNotFound
  681. case types.TimeoutError:
  682. code = http.StatusRequestTimeout
  683. case types.NotImplementedError:
  684. code = http.StatusNotImplemented
  685. case types.NoServiceError:
  686. code = http.StatusServiceUnavailable
  687. case types.InternalError:
  688. code = http.StatusInternalServerError
  689. default:
  690. code = http.StatusInternalServerError
  691. }
  692. return &responseStatus{Status: err.Error(), StatusCode: code}
  693. }
  694. func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
  695. w.Header().Set("Content-Type", "application/json")
  696. w.WriteHeader(code)
  697. return json.NewEncoder(w).Encode(v)
  698. }