fix: access backend service by specific region/zone (#15223)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2022-10-25 17:05:30 +08:00
committed by GitHub
co-authored by Qiu Jian
parent 85edf1a21b
commit 73aa71d7df
2 changed files with 76 additions and 7 deletions
+60 -1
View File
@@ -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
View File
@@ -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