github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/api/api.go (about) 1 package api 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "strconv" 9 "strings" 10 11 "github.com/docker/libnetwork" 12 "github.com/docker/libnetwork/netlabel" 13 "github.com/docker/libnetwork/netutils" 14 "github.com/docker/libnetwork/types" 15 "github.com/gorilla/mux" 16 ) 17 18 var ( 19 successResponse = responseStatus{Status: "Success", StatusCode: http.StatusOK} 20 createdResponse = responseStatus{Status: "Created", StatusCode: http.StatusCreated} 21 mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest} 22 badQueryResponse = responseStatus{Status: "Unsupported query", StatusCode: http.StatusBadRequest} 23 ) 24 25 const ( 26 // Resource name regex 27 // Gorilla mux encloses the passed pattern with '^' and '$'. So we need to do some tricks 28 // to have mux eventually build a query regex which matches empty or word string (`^$|[\w]+`) 29 regex = "[a-zA-Z_0-9-]+" 30 qregx = "$|" + regex 31 // Router URL variable definition 32 nwName = "{" + urlNwName + ":" + regex + "}" 33 nwNameQr = "{" + urlNwName + ":" + qregx + "}" 34 nwID = "{" + urlNwID + ":" + regex + "}" 35 nwPIDQr = "{" + urlNwPID + ":" + qregx + "}" 36 epName = "{" + urlEpName + ":" + regex + "}" 37 epNameQr = "{" + urlEpName + ":" + qregx + "}" 38 epID = "{" + urlEpID + ":" + regex + "}" 39 epPIDQr = "{" + urlEpPID + ":" + qregx + "}" 40 sbID = "{" + urlSbID + ":" + regex + "}" 41 sbPIDQr = "{" + urlSbPID + ":" + qregx + "}" 42 cnIDQr = "{" + urlCnID + ":" + qregx + "}" 43 cnPIDQr = "{" + urlCnPID + ":" + qregx + "}" 44 45 // Internal URL variable name.They can be anything as 46 // long as they do not collide with query fields. 47 urlNwName = "network-name" 48 urlNwID = "network-id" 49 urlNwPID = "network-partial-id" 50 urlEpName = "endpoint-name" 51 urlEpID = "endpoint-id" 52 urlEpPID = "endpoint-partial-id" 53 urlSbID = "sandbox-id" 54 urlSbPID = "sandbox-partial-id" 55 urlCnID = "container-id" 56 urlCnPID = "container-partial-id" 57 ) 58 59 // NewHTTPHandler creates and initialize the HTTP handler to serve the requests for libnetwork 60 func NewHTTPHandler(c libnetwork.NetworkController) func(w http.ResponseWriter, req *http.Request) { 61 h := &httpHandler{c: c} 62 h.initRouter() 63 return h.handleRequest 64 } 65 66 type responseStatus struct { 67 Status string 68 StatusCode int 69 } 70 71 func (r *responseStatus) isOK() bool { 72 return r.StatusCode == http.StatusOK || r.StatusCode == http.StatusCreated 73 } 74 75 type processor func(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) 76 77 type httpHandler struct { 78 c libnetwork.NetworkController 79 r *mux.Router 80 } 81 82 func (h *httpHandler) handleRequest(w http.ResponseWriter, req *http.Request) { 83 // Make sure the service is there 84 if h.c == nil { 85 http.Error(w, "NetworkController is not available", http.StatusServiceUnavailable) 86 return 87 } 88 89 // Get handler from router and execute it 90 h.r.ServeHTTP(w, req) 91 } 92 93 func (h *httpHandler) initRouter() { 94 m := map[string][]struct { 95 url string 96 qrs []string 97 fct processor 98 }{ 99 "GET": { 100 // Order matters 101 {"/networks", []string{"name", nwNameQr}, procGetNetworks}, 102 {"/networks", []string{"partial-id", nwPIDQr}, procGetNetworks}, 103 {"/networks", nil, procGetNetworks}, 104 {"/networks/" + nwID, nil, procGetNetwork}, 105 {"/networks/" + nwID + "/endpoints", []string{"name", epNameQr}, procGetEndpoints}, 106 {"/networks/" + nwID + "/endpoints", []string{"partial-id", epPIDQr}, procGetEndpoints}, 107 {"/networks/" + nwID + "/endpoints", nil, procGetEndpoints}, 108 {"/networks/" + nwID + "/endpoints/" + epID, nil, procGetEndpoint}, 109 {"/services", []string{"network", nwNameQr}, procGetServices}, 110 {"/services", []string{"name", epNameQr}, procGetServices}, 111 {"/services", []string{"partial-id", epPIDQr}, procGetServices}, 112 {"/services", nil, procGetServices}, 113 {"/services/" + epID, nil, procGetService}, 114 {"/services/" + epID + "/backend", nil, procGetSandbox}, 115 {"/sandboxes", []string{"partial-container-id", cnPIDQr}, procGetSandboxes}, 116 {"/sandboxes", []string{"container-id", cnIDQr}, procGetSandboxes}, 117 {"/sandboxes", []string{"partial-id", sbPIDQr}, procGetSandboxes}, 118 {"/sandboxes", nil, procGetSandboxes}, 119 {"/sandboxes/" + sbID, nil, procGetSandbox}, 120 }, 121 "POST": { 122 {"/networks", nil, procCreateNetwork}, 123 {"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint}, 124 {"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes", nil, procJoinEndpoint}, 125 {"/services", nil, procPublishService}, 126 {"/services/" + epID + "/backend", nil, procAttachBackend}, 127 {"/sandboxes", nil, procCreateSandbox}, 128 }, 129 "DELETE": { 130 {"/networks/" + nwID, nil, procDeleteNetwork}, 131 {"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint}, 132 {"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes/" + sbID, nil, procLeaveEndpoint}, 133 {"/services/" + epID, nil, procUnpublishService}, 134 {"/services/" + epID + "/backend/" + sbID, nil, procDetachBackend}, 135 {"/sandboxes/" + sbID, nil, procDeleteSandbox}, 136 }, 137 } 138 139 h.r = mux.NewRouter() 140 for method, routes := range m { 141 for _, route := range routes { 142 r := h.r.Path("/{.*}" + route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct)) 143 if route.qrs != nil { 144 r.Queries(route.qrs...) 145 } 146 147 r = h.r.Path(route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct)) 148 if route.qrs != nil { 149 r.Queries(route.qrs...) 150 } 151 } 152 } 153 } 154 155 func makeHandler(ctrl libnetwork.NetworkController, fct processor) http.HandlerFunc { 156 return func(w http.ResponseWriter, req *http.Request) { 157 var ( 158 body []byte 159 err error 160 ) 161 if req.Body != nil { 162 body, err = ioutil.ReadAll(req.Body) 163 if err != nil { 164 http.Error(w, "Invalid body: "+err.Error(), http.StatusBadRequest) 165 return 166 } 167 } 168 169 res, rsp := fct(ctrl, mux.Vars(req), body) 170 if !rsp.isOK() { 171 http.Error(w, rsp.Status, rsp.StatusCode) 172 return 173 } 174 if res != nil { 175 writeJSON(w, rsp.StatusCode, res) 176 } 177 } 178 } 179 180 /***************** 181 Resource Builders 182 ******************/ 183 184 func buildNetworkResource(nw libnetwork.Network) *networkResource { 185 r := &networkResource{} 186 if nw != nil { 187 r.Name = nw.Name() 188 r.ID = nw.ID() 189 r.Type = nw.Type() 190 epl := nw.Endpoints() 191 r.Endpoints = make([]*endpointResource, 0, len(epl)) 192 for _, e := range epl { 193 epr := buildEndpointResource(e) 194 r.Endpoints = append(r.Endpoints, epr) 195 } 196 } 197 return r 198 } 199 200 func buildEndpointResource(ep libnetwork.Endpoint) *endpointResource { 201 r := &endpointResource{} 202 if ep != nil { 203 r.Name = ep.Name() 204 r.ID = ep.ID() 205 r.Network = ep.Network() 206 } 207 return r 208 } 209 210 func buildSandboxResource(sb libnetwork.Sandbox) *sandboxResource { 211 r := &sandboxResource{} 212 if sb != nil { 213 r.ID = sb.ID() 214 r.Key = sb.Key() 215 r.ContainerID = sb.ContainerID() 216 } 217 return r 218 } 219 220 /**************** 221 Options Parsers 222 *****************/ 223 224 func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption { 225 var setFctList []libnetwork.SandboxOption 226 if sc.HostName != "" { 227 setFctList = append(setFctList, libnetwork.OptionHostname(sc.HostName)) 228 } 229 if sc.DomainName != "" { 230 setFctList = append(setFctList, libnetwork.OptionDomainname(sc.DomainName)) 231 } 232 if sc.HostsPath != "" { 233 setFctList = append(setFctList, libnetwork.OptionHostsPath(sc.HostsPath)) 234 } 235 if sc.ResolvConfPath != "" { 236 setFctList = append(setFctList, libnetwork.OptionResolvConfPath(sc.ResolvConfPath)) 237 } 238 if sc.UseDefaultSandbox { 239 setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox()) 240 } 241 if sc.UseExternalKey { 242 setFctList = append(setFctList, libnetwork.OptionUseExternalKey()) 243 } 244 if sc.DNS != nil { 245 for _, d := range sc.DNS { 246 setFctList = append(setFctList, libnetwork.OptionDNS(d)) 247 } 248 } 249 if sc.ExtraHosts != nil { 250 for _, e := range sc.ExtraHosts { 251 setFctList = append(setFctList, libnetwork.OptionExtraHost(e.Name, e.Address)) 252 } 253 } 254 if sc.ExposedPorts != nil { 255 setFctList = append(setFctList, libnetwork.OptionExposedPorts(sc.ExposedPorts)) 256 } 257 if sc.PortMapping != nil { 258 setFctList = append(setFctList, libnetwork.OptionPortMapping(sc.PortMapping)) 259 } 260 return setFctList 261 } 262 263 func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption { 264 // priority will go here 265 return []libnetwork.EndpointOption{} 266 } 267 268 /****************** 269 Process functions 270 *******************/ 271 272 func processCreateDefaults(c libnetwork.NetworkController, nc *networkCreate) { 273 if nc.NetworkType == "" { 274 nc.NetworkType = c.Config().Daemon.DefaultDriver 275 } 276 } 277 278 /*************************** 279 NetworkController interface 280 ****************************/ 281 282 func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 283 var create networkCreate 284 285 err := json.Unmarshal(body, &create) 286 if err != nil { 287 return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} 288 } 289 processCreateDefaults(c, &create) 290 291 options := []libnetwork.NetworkOption{} 292 if val, ok := create.NetworkOpts[netlabel.Internal]; ok { 293 internal, err := strconv.ParseBool(val) 294 if err != nil { 295 return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} 296 } 297 if internal { 298 options = append(options, libnetwork.NetworkOptionInternalNetwork()) 299 } 300 } 301 if val, ok := create.NetworkOpts[netlabel.EnableIPv6]; ok { 302 enableIPv6, err := strconv.ParseBool(val) 303 if err != nil { 304 return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} 305 } 306 options = append(options, libnetwork.NetworkOptionEnableIPv6(enableIPv6)) 307 } 308 if len(create.DriverOpts) > 0 { 309 options = append(options, libnetwork.NetworkOptionDriverOpts(create.DriverOpts)) 310 } 311 312 if len(create.IPv4Conf) > 0 { 313 ipamV4Conf := &libnetwork.IpamConf{ 314 PreferredPool: create.IPv4Conf[0].PreferredPool, 315 SubPool: create.IPv4Conf[0].SubPool, 316 } 317 318 options = append(options, libnetwork.NetworkOptionIpam("default", "", []*libnetwork.IpamConf{ipamV4Conf}, nil, nil)) 319 } 320 321 nw, err := c.NewNetwork(create.NetworkType, create.Name, create.ID, options...) 322 if err != nil { 323 return nil, convertNetworkError(err) 324 } 325 326 return nw.ID(), &createdResponse 327 } 328 329 func procGetNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 330 t, by := detectNetworkTarget(vars) 331 nw, errRsp := findNetwork(c, t, by) 332 if !errRsp.isOK() { 333 return nil, errRsp 334 } 335 return buildNetworkResource(nw), &successResponse 336 } 337 338 func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 339 var list []*networkResource 340 341 // Look for query filters and validate 342 name, queryByName := vars[urlNwName] 343 shortID, queryByPid := vars[urlNwPID] 344 if queryByName && queryByPid { 345 return nil, &badQueryResponse 346 } 347 348 if queryByName { 349 if nw, errRsp := findNetwork(c, name, byName); errRsp.isOK() { 350 list = append(list, buildNetworkResource(nw)) 351 } 352 } else if queryByPid { 353 // Return all the prefix-matching networks 354 l := func(nw libnetwork.Network) bool { 355 if strings.HasPrefix(nw.ID(), shortID) { 356 list = append(list, buildNetworkResource(nw)) 357 } 358 return false 359 } 360 c.WalkNetworks(l) 361 } else { 362 for _, nw := range c.Networks() { 363 list = append(list, buildNetworkResource(nw)) 364 } 365 } 366 367 return list, &successResponse 368 } 369 370 func procCreateSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 371 var create sandboxCreate 372 373 err := json.Unmarshal(body, &create) 374 if err != nil { 375 return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} 376 } 377 378 sb, err := c.NewSandbox(create.ContainerID, create.parseOptions()...) 379 if err != nil { 380 return "", convertNetworkError(err) 381 } 382 383 return sb.ID(), &createdResponse 384 } 385 386 /****************** 387 Network interface 388 *******************/ 389 390 func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 391 var ec endpointCreate 392 393 err := json.Unmarshal(body, &ec) 394 if err != nil { 395 return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} 396 } 397 398 nwT, nwBy := detectNetworkTarget(vars) 399 n, errRsp := findNetwork(c, nwT, nwBy) 400 if !errRsp.isOK() { 401 return "", errRsp 402 } 403 404 var setFctList []libnetwork.EndpointOption 405 for _, str := range ec.MyAliases { 406 setFctList = append(setFctList, libnetwork.CreateOptionMyAlias(str)) 407 } 408 409 ep, err := n.CreateEndpoint(ec.Name, setFctList...) 410 if err != nil { 411 return "", convertNetworkError(err) 412 } 413 414 return ep.ID(), &createdResponse 415 } 416 417 func procGetEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 418 nwT, nwBy := detectNetworkTarget(vars) 419 epT, epBy := detectEndpointTarget(vars) 420 421 ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) 422 if !errRsp.isOK() { 423 return nil, errRsp 424 } 425 426 return buildEndpointResource(ep), &successResponse 427 } 428 429 func procGetEndpoints(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 430 // Look for query filters and validate 431 name, queryByName := vars[urlEpName] 432 shortID, queryByPid := vars[urlEpPID] 433 if queryByName && queryByPid { 434 return nil, &badQueryResponse 435 } 436 437 nwT, nwBy := detectNetworkTarget(vars) 438 nw, errRsp := findNetwork(c, nwT, nwBy) 439 if !errRsp.isOK() { 440 return nil, errRsp 441 } 442 443 var list []*endpointResource 444 445 // If query parameter is specified, return a filtered collection 446 if queryByName { 447 if ep, errRsp := findEndpoint(c, nwT, name, nwBy, byName); errRsp.isOK() { 448 list = append(list, buildEndpointResource(ep)) 449 } 450 } else if queryByPid { 451 // Return all the prefix-matching endpoints 452 l := func(ep libnetwork.Endpoint) bool { 453 if strings.HasPrefix(ep.ID(), shortID) { 454 list = append(list, buildEndpointResource(ep)) 455 } 456 return false 457 } 458 nw.WalkEndpoints(l) 459 } else { 460 for _, ep := range nw.Endpoints() { 461 epr := buildEndpointResource(ep) 462 list = append(list, epr) 463 } 464 } 465 466 return list, &successResponse 467 } 468 469 func procDeleteNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 470 target, by := detectNetworkTarget(vars) 471 472 nw, errRsp := findNetwork(c, target, by) 473 if !errRsp.isOK() { 474 return nil, errRsp 475 } 476 477 err := nw.Delete() 478 if err != nil { 479 return nil, convertNetworkError(err) 480 } 481 482 return nil, &successResponse 483 } 484 485 /****************** 486 Endpoint interface 487 *******************/ 488 489 func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 490 var ej endpointJoin 491 var setFctList []libnetwork.EndpointOption 492 err := json.Unmarshal(body, &ej) 493 if err != nil { 494 return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} 495 } 496 497 nwT, nwBy := detectNetworkTarget(vars) 498 epT, epBy := detectEndpointTarget(vars) 499 500 ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) 501 if !errRsp.isOK() { 502 return nil, errRsp 503 } 504 505 sb, errRsp := findSandbox(c, ej.SandboxID, byID) 506 if !errRsp.isOK() { 507 return nil, errRsp 508 } 509 510 for _, str := range ej.Aliases { 511 name, alias, err := netutils.ParseAlias(str) 512 if err != nil { 513 return "", convertNetworkError(err) 514 } 515 setFctList = append(setFctList, libnetwork.CreateOptionAlias(name, alias)) 516 } 517 518 err = ep.Join(sb, setFctList...) 519 if err != nil { 520 return nil, convertNetworkError(err) 521 } 522 return sb.Key(), &successResponse 523 } 524 525 func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 526 nwT, nwBy := detectNetworkTarget(vars) 527 epT, epBy := detectEndpointTarget(vars) 528 529 ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) 530 if !errRsp.isOK() { 531 return nil, errRsp 532 } 533 534 sb, errRsp := findSandbox(c, vars[urlSbID], byID) 535 if !errRsp.isOK() { 536 return nil, errRsp 537 } 538 539 err := ep.Leave(sb) 540 if err != nil { 541 return nil, convertNetworkError(err) 542 } 543 544 return nil, &successResponse 545 } 546 547 func procDeleteEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 548 nwT, nwBy := detectNetworkTarget(vars) 549 epT, epBy := detectEndpointTarget(vars) 550 551 ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) 552 if !errRsp.isOK() { 553 return nil, errRsp 554 } 555 556 err := ep.Delete(false) 557 if err != nil { 558 return nil, convertNetworkError(err) 559 } 560 561 return nil, &successResponse 562 } 563 564 /****************** 565 Service interface 566 *******************/ 567 568 func procGetServices(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 569 // Look for query filters and validate 570 nwName, filterByNwName := vars[urlNwName] 571 svName, queryBySvName := vars[urlEpName] 572 shortID, queryBySvPID := vars[urlEpPID] 573 574 if filterByNwName && queryBySvName || filterByNwName && queryBySvPID || queryBySvName && queryBySvPID { 575 return nil, &badQueryResponse 576 } 577 578 var list []*endpointResource 579 580 switch { 581 case filterByNwName: 582 // return all service present on the specified network 583 nw, errRsp := findNetwork(c, nwName, byName) 584 if !errRsp.isOK() { 585 return list, &successResponse 586 } 587 for _, ep := range nw.Endpoints() { 588 epr := buildEndpointResource(ep) 589 list = append(list, epr) 590 } 591 case queryBySvName: 592 // Look in each network for the service with the specified name 593 l := func(ep libnetwork.Endpoint) bool { 594 if ep.Name() == svName { 595 list = append(list, buildEndpointResource(ep)) 596 return true 597 } 598 return false 599 } 600 for _, nw := range c.Networks() { 601 nw.WalkEndpoints(l) 602 } 603 case queryBySvPID: 604 // Return all the prefix-matching services 605 l := func(ep libnetwork.Endpoint) bool { 606 if strings.HasPrefix(ep.ID(), shortID) { 607 list = append(list, buildEndpointResource(ep)) 608 } 609 return false 610 } 611 for _, nw := range c.Networks() { 612 nw.WalkEndpoints(l) 613 } 614 default: 615 for _, nw := range c.Networks() { 616 for _, ep := range nw.Endpoints() { 617 epr := buildEndpointResource(ep) 618 list = append(list, epr) 619 } 620 } 621 } 622 623 return list, &successResponse 624 } 625 626 func procGetService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 627 epT, epBy := detectEndpointTarget(vars) 628 sv, errRsp := findService(c, epT, epBy) 629 if !errRsp.isOK() { 630 return nil, endpointToService(errRsp) 631 } 632 return buildEndpointResource(sv), &successResponse 633 } 634 635 func procPublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 636 var sp servicePublish 637 638 err := json.Unmarshal(body, &sp) 639 if err != nil { 640 return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} 641 } 642 643 n, errRsp := findNetwork(c, sp.Network, byName) 644 if !errRsp.isOK() { 645 return "", errRsp 646 } 647 648 var setFctList []libnetwork.EndpointOption 649 for _, str := range sp.MyAliases { 650 setFctList = append(setFctList, libnetwork.CreateOptionMyAlias(str)) 651 } 652 653 ep, err := n.CreateEndpoint(sp.Name, setFctList...) 654 if err != nil { 655 return "", endpointToService(convertNetworkError(err)) 656 } 657 658 return ep.ID(), &createdResponse 659 } 660 661 func procUnpublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 662 var sd serviceDelete 663 664 if body != nil { 665 err := json.Unmarshal(body, &sd) 666 if err != nil { 667 return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} 668 } 669 } 670 671 epT, epBy := detectEndpointTarget(vars) 672 sv, errRsp := findService(c, epT, epBy) 673 if !errRsp.isOK() { 674 return nil, errRsp 675 } 676 677 if err := sv.Delete(sd.Force); err != nil { 678 return nil, endpointToService(convertNetworkError(err)) 679 } 680 return nil, &successResponse 681 } 682 683 func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 684 var bk endpointJoin 685 var setFctList []libnetwork.EndpointOption 686 err := json.Unmarshal(body, &bk) 687 if err != nil { 688 return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} 689 } 690 691 epT, epBy := detectEndpointTarget(vars) 692 sv, errRsp := findService(c, epT, epBy) 693 if !errRsp.isOK() { 694 return nil, errRsp 695 } 696 697 sb, errRsp := findSandbox(c, bk.SandboxID, byID) 698 if !errRsp.isOK() { 699 return nil, errRsp 700 } 701 702 for _, str := range bk.Aliases { 703 name, alias, err := netutils.ParseAlias(str) 704 if err != nil { 705 return "", convertNetworkError(err) 706 } 707 setFctList = append(setFctList, libnetwork.CreateOptionAlias(name, alias)) 708 } 709 710 err = sv.Join(sb, setFctList...) 711 if err != nil { 712 return nil, convertNetworkError(err) 713 } 714 715 return sb.Key(), &successResponse 716 } 717 718 func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 719 epT, epBy := detectEndpointTarget(vars) 720 sv, errRsp := findService(c, epT, epBy) 721 if !errRsp.isOK() { 722 return nil, errRsp 723 } 724 725 sb, errRsp := findSandbox(c, vars[urlSbID], byID) 726 if !errRsp.isOK() { 727 return nil, errRsp 728 } 729 730 err := sv.Leave(sb) 731 if err != nil { 732 return nil, convertNetworkError(err) 733 } 734 735 return nil, &successResponse 736 } 737 738 /****************** 739 Sandbox interface 740 *******************/ 741 742 func procGetSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 743 if epT, ok := vars[urlEpID]; ok { 744 sv, errRsp := findService(c, epT, byID) 745 if !errRsp.isOK() { 746 return nil, endpointToService(errRsp) 747 } 748 return buildSandboxResource(sv.Info().Sandbox()), &successResponse 749 } 750 751 sbT, by := detectSandboxTarget(vars) 752 sb, errRsp := findSandbox(c, sbT, by) 753 if !errRsp.isOK() { 754 return nil, errRsp 755 } 756 return buildSandboxResource(sb), &successResponse 757 } 758 759 type cndFnMkr func(string) cndFn 760 type cndFn func(libnetwork.Sandbox) bool 761 762 // list of (query type, condition function makers) couples 763 var cndMkrList = []struct { 764 identifier string 765 maker cndFnMkr 766 }{ 767 {urlSbPID, func(id string) cndFn { 768 return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ID(), id) } 769 }}, 770 {urlCnID, func(id string) cndFn { 771 return func(sb libnetwork.Sandbox) bool { return sb.ContainerID() == id } 772 }}, 773 {urlCnPID, func(id string) cndFn { 774 return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ContainerID(), id) } 775 }}, 776 } 777 778 func getQueryCondition(vars map[string]string) func(libnetwork.Sandbox) bool { 779 for _, im := range cndMkrList { 780 if val, ok := vars[im.identifier]; ok { 781 return im.maker(val) 782 } 783 } 784 return func(sb libnetwork.Sandbox) bool { return true } 785 } 786 787 func sandboxWalker(condition cndFn, list *[]*sandboxResource) libnetwork.SandboxWalker { 788 return func(sb libnetwork.Sandbox) bool { 789 if condition(sb) { 790 *list = append(*list, buildSandboxResource(sb)) 791 } 792 return false 793 } 794 } 795 796 func procGetSandboxes(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 797 var list []*sandboxResource 798 799 cnd := getQueryCondition(vars) 800 c.WalkSandboxes(sandboxWalker(cnd, &list)) 801 802 return list, &successResponse 803 } 804 805 func procDeleteSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { 806 sbT, by := detectSandboxTarget(vars) 807 808 sb, errRsp := findSandbox(c, sbT, by) 809 if !errRsp.isOK() { 810 return nil, errRsp 811 } 812 813 err := sb.Delete() 814 if err != nil { 815 return nil, convertNetworkError(err) 816 } 817 818 return nil, &successResponse 819 } 820 821 /*********** 822 Utilities 823 ************/ 824 825 const ( 826 byID = iota 827 byName 828 ) 829 830 func detectNetworkTarget(vars map[string]string) (string, int) { 831 if target, ok := vars[urlNwName]; ok { 832 return target, byName 833 } 834 if target, ok := vars[urlNwID]; ok { 835 return target, byID 836 } 837 // vars are populated from the URL, following cannot happen 838 panic("Missing URL variable parameter for network") 839 } 840 841 func detectSandboxTarget(vars map[string]string) (string, int) { 842 if target, ok := vars[urlSbID]; ok { 843 return target, byID 844 } 845 // vars are populated from the URL, following cannot happen 846 panic("Missing URL variable parameter for sandbox") 847 } 848 849 func detectEndpointTarget(vars map[string]string) (string, int) { 850 if target, ok := vars[urlEpName]; ok { 851 return target, byName 852 } 853 if target, ok := vars[urlEpID]; ok { 854 return target, byID 855 } 856 // vars are populated from the URL, following cannot happen 857 panic("Missing URL variable parameter for endpoint") 858 } 859 860 func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.Network, *responseStatus) { 861 var ( 862 nw libnetwork.Network 863 err error 864 ) 865 switch by { 866 case byID: 867 nw, err = c.NetworkByID(s) 868 case byName: 869 if s == "" { 870 s = c.Config().Daemon.DefaultNetwork 871 } 872 nw, err = c.NetworkByName(s) 873 default: 874 panic(fmt.Sprintf("unexpected selector for network search: %d", by)) 875 } 876 if err != nil { 877 if _, ok := err.(types.NotFoundError); ok { 878 return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound} 879 } 880 return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} 881 } 882 return nw, &successResponse 883 } 884 885 func findSandbox(c libnetwork.NetworkController, s string, by int) (libnetwork.Sandbox, *responseStatus) { 886 var ( 887 sb libnetwork.Sandbox 888 err error 889 ) 890 891 switch by { 892 case byID: 893 sb, err = c.SandboxByID(s) 894 default: 895 panic(fmt.Sprintf("unexpected selector for sandbox search: %d", by)) 896 } 897 if err != nil { 898 if _, ok := err.(types.NotFoundError); ok { 899 return nil, &responseStatus{Status: "Resource not found: Sandbox", StatusCode: http.StatusNotFound} 900 } 901 return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} 902 } 903 return sb, &successResponse 904 } 905 906 func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) (libnetwork.Endpoint, *responseStatus) { 907 nw, errRsp := findNetwork(c, ns, nwBy) 908 if !errRsp.isOK() { 909 return nil, errRsp 910 } 911 var ( 912 err error 913 ep libnetwork.Endpoint 914 ) 915 switch epBy { 916 case byID: 917 ep, err = nw.EndpointByID(es) 918 case byName: 919 ep, err = nw.EndpointByName(es) 920 default: 921 panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy)) 922 } 923 if err != nil { 924 if _, ok := err.(types.NotFoundError); ok { 925 return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound} 926 } 927 return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} 928 } 929 return ep, &successResponse 930 } 931 932 func findService(c libnetwork.NetworkController, svs string, svBy int) (libnetwork.Endpoint, *responseStatus) { 933 for _, nw := range c.Networks() { 934 var ( 935 ep libnetwork.Endpoint 936 err error 937 ) 938 switch svBy { 939 case byID: 940 ep, err = nw.EndpointByID(svs) 941 case byName: 942 ep, err = nw.EndpointByName(svs) 943 default: 944 panic(fmt.Sprintf("unexpected selector for service search: %d", svBy)) 945 } 946 if err == nil { 947 return ep, &successResponse 948 } else if _, ok := err.(types.NotFoundError); !ok { 949 return nil, convertNetworkError(err) 950 } 951 } 952 return nil, &responseStatus{Status: "Service not found", StatusCode: http.StatusNotFound} 953 } 954 955 func endpointToService(rsp *responseStatus) *responseStatus { 956 rsp.Status = strings.Replace(rsp.Status, "endpoint", "service", -1) 957 return rsp 958 } 959 960 func convertNetworkError(err error) *responseStatus { 961 var code int 962 switch err.(type) { 963 case types.BadRequestError: 964 code = http.StatusBadRequest 965 case types.ForbiddenError: 966 code = http.StatusForbidden 967 case types.NotFoundError: 968 code = http.StatusNotFound 969 case types.TimeoutError: 970 code = http.StatusRequestTimeout 971 case types.NotImplementedError: 972 code = http.StatusNotImplemented 973 case types.NoServiceError: 974 code = http.StatusServiceUnavailable 975 case types.InternalError: 976 code = http.StatusInternalServerError 977 default: 978 code = http.StatusInternalServerError 979 } 980 return &responseStatus{Status: err.Error(), StatusCode: code} 981 } 982 983 func writeJSON(w http.ResponseWriter, code int, v interface{}) error { 984 w.Header().Set("Content-Type", "application/json") 985 w.WriteHeader(code) 986 return json.NewEncoder(w).Encode(v) 987 }