api.go 22 KB

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