mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix: access backend service by specific region/zone (#15223)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -16,6 +16,7 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -39,14 +40,40 @@ func NewBackendServiceProxyHandler(prefix string) *SBackendServiceProxyHandler {
|
||||
}
|
||||
}
|
||||
|
||||
func removeLeadingSlash(p string) string {
|
||||
for len(p) > 0 && p[0] == '/' {
|
||||
p = p[1:]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (h *SBackendServiceProxyHandler) requestManipulator(ctx context.Context, r *http.Request) (*http.Request, error) {
|
||||
// remove leading prefixes /api/s/<service>
|
||||
path := r.URL.Path[len("/api/s/"):]
|
||||
path = removeLeadingSlash(path)
|
||||
slashPos := strings.Index(path, "/")
|
||||
if slashPos <= 0 {
|
||||
return r, httperrors.NewBadRequestError("invalid request URL %s", r.URL.Path)
|
||||
}
|
||||
path = path[slashPos:]
|
||||
if strings.HasPrefix(path, "/r/") {
|
||||
path = path[len("/r/"):]
|
||||
path = removeLeadingSlash(path)
|
||||
slashPos := strings.Index(path, "/")
|
||||
if slashPos <= 0 {
|
||||
return r, httperrors.NewBadRequestError("invalid request URL %s", r.URL.Path)
|
||||
}
|
||||
path = path[slashPos:]
|
||||
if strings.HasPrefix(path, "/z/") {
|
||||
path = path[len("/z/"):]
|
||||
path = removeLeadingSlash(path)
|
||||
slashPos := strings.Index(path, "/")
|
||||
if slashPos <= 0 {
|
||||
return r, httperrors.NewBadRequestError("invalid request URL %s", r.URL.Path)
|
||||
}
|
||||
path = path[slashPos:]
|
||||
}
|
||||
}
|
||||
log.Debugf("Path: %s => %s", r.URL.Path, path)
|
||||
r.URL = &url.URL{
|
||||
Path: path,
|
||||
@@ -67,8 +94,40 @@ func (h *SBackendServiceProxyHandler) fetchReverseEndpoint() *proxy.SEndpointFac
|
||||
if len(serviceName) == 0 {
|
||||
return "", httperrors.NewBadRequestError("no service")
|
||||
}
|
||||
path := r.URL.Path
|
||||
serviceSeg := fmt.Sprintf("/api/s/%s/", serviceName)
|
||||
pos := strings.Index(path, serviceSeg)
|
||||
if pos < 0 {
|
||||
return "", httperrors.NewBadRequestError("malformed URL, expect service")
|
||||
}
|
||||
path = path[pos+len(serviceSeg):]
|
||||
path = removeLeadingSlash(path)
|
||||
region := FetchRegion(r)
|
||||
zone := ""
|
||||
if strings.HasPrefix(path, "r/") {
|
||||
path = path[len("r/"):]
|
||||
path = removeLeadingSlash(path)
|
||||
slashPos := strings.Index(path, "/")
|
||||
if slashPos <= 0 {
|
||||
return "", httperrors.NewBadRequestError("malformed URL, expect region")
|
||||
}
|
||||
region = path[:slashPos]
|
||||
path = path[slashPos+1:]
|
||||
if strings.HasPrefix(path, "z/") {
|
||||
path = path[len("z/"):]
|
||||
path = removeLeadingSlash(path)
|
||||
slashPos := strings.Index(path, "/")
|
||||
if slashPos <= 0 {
|
||||
return "", httperrors.NewBadRequestError("malformed URL, expect zone")
|
||||
}
|
||||
zone = path[:slashPos]
|
||||
}
|
||||
}
|
||||
endpointType := "internalURL"
|
||||
session := auth.GetAdminSession(ctx, FetchRegion(r))
|
||||
session := auth.GetAdminSession(ctx, region)
|
||||
if len(zone) > 0 {
|
||||
session.SetZone(zone)
|
||||
}
|
||||
ep, err := session.GetServiceURL(serviceName, endpointType, "")
|
||||
if err != nil {
|
||||
return "", httperrors.NewBadRequestError("invalid service %s: %s", serviceName, err)
|
||||
|
||||
+16
-6
@@ -107,6 +107,10 @@ func (this *ClientSession) GetClient() *Client {
|
||||
return this.client
|
||||
}
|
||||
|
||||
func (this *ClientSession) SetZone(zone string) {
|
||||
this.zone = zone
|
||||
}
|
||||
|
||||
func getApiVersionByServiceType(serviceType string) string {
|
||||
switch serviceType {
|
||||
case "compute":
|
||||
@@ -152,14 +156,14 @@ func (this *ClientSession) GetServiceVersionURLs(service, endpointType, apiVersi
|
||||
}
|
||||
service = this.getServiceName(service, apiVersion)
|
||||
if endpointType == api.EndpointInterfaceApigateway {
|
||||
return this.getApigatewayServiceURLs(service, endpointType)
|
||||
return this.getApigatewayServiceURLs(service, this.region, this.zone, endpointType)
|
||||
} else {
|
||||
return this.getServiceVersionURLs(service, endpointType)
|
||||
return this.getServiceVersionURLs(service, this.region, this.zone, endpointType)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ClientSession) getApigatewayServiceURLs(service, endpointType string) ([]string, error) {
|
||||
urls, err := this.getServiceVersionURLs(service, "")
|
||||
func (this *ClientSession) getApigatewayServiceURLs(service, region, zone, endpointType string) ([]string, error) {
|
||||
urls, err := this.getServiceVersionURLs(service, region, zone, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getServiceVersionURLs")
|
||||
}
|
||||
@@ -171,6 +175,12 @@ func (this *ClientSession) getApigatewayServiceURLs(service, endpointType string
|
||||
return nil, errors.Wrapf(err, "invalue auth_url %s", prefix)
|
||||
}
|
||||
prefix = httputils.JoinPath(prefix[:lastSlashPos], "api/s", service)
|
||||
if len(region) > 0 {
|
||||
prefix = httputils.JoinPath(prefix, "r", region)
|
||||
if len(zone) > 0 {
|
||||
prefix = httputils.JoinPath(prefix, "z", zone)
|
||||
}
|
||||
}
|
||||
rets := make([]string, len(urls))
|
||||
for i, url := range urls {
|
||||
if len(url) < 9 {
|
||||
@@ -189,12 +199,12 @@ func (this *ClientSession) getApigatewayServiceURLs(service, endpointType string
|
||||
return rets, nil
|
||||
}
|
||||
|
||||
func (this *ClientSession) getServiceVersionURLs(service, endpointType string) ([]string, error) {
|
||||
func (this *ClientSession) getServiceVersionURLs(service, region, zone, endpointType string) ([]string, error) {
|
||||
catalog := this.GetServiceCatalog()
|
||||
if gotypes.IsNil(catalog) {
|
||||
return []string{this.client.authUrl}, nil
|
||||
}
|
||||
urls, err := catalog.GetServiceURLs(service, this.region, this.zone, endpointType)
|
||||
urls, err := catalog.GetServiceURLs(service, region, zone, endpointType)
|
||||
// HACK! in case of fail to get kestone url or schema of keystone changed, always trust authUrl
|
||||
if service == api.SERVICE_TYPE && (err != nil || len(urls) == 0 || (len(this.client.authUrl) != 0 && this.client.authUrl[:5] != urls[0][:5])) {
|
||||
var msg string
|
||||
|
||||
Reference in New Issue
Block a user