fix: proxy ListObjects request to one of the server based on hash(bucket) (#9881)

master
Krishna Srinivas 4 years ago committed by GitHub
parent abd999f64a
commit 4c266df863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 51
      cmd/bucket-listobjects-handlers.go
  2. 55
      cmd/endpoint.go
  3. 1
      cmd/globals.go
  4. 3
      cmd/server-main.go

@ -17,6 +17,8 @@
package cmd package cmd
import ( import (
"context"
"io"
"net/http" "net/http"
"strings" "strings"
@ -157,6 +159,10 @@ func (api objectAPIHandlers) ListObjectsV2MHandler(w http.ResponseWriter, r *htt
return return
} }
if proxyListRequest(ctx, w, r, bucket) {
return
}
listObjectsV2 := objectAPI.ListObjectsV2 listObjectsV2 := objectAPI.ListObjectsV2
// Inititate a list objects operation based on the input params. // Inititate a list objects operation based on the input params.
@ -231,6 +237,10 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
return return
} }
if proxyListRequest(ctx, w, r, bucket) {
return
}
listObjectsV2 := objectAPI.ListObjectsV2 listObjectsV2 := objectAPI.ListObjectsV2
// Inititate a list objects operation based on the input params. // Inititate a list objects operation based on the input params.
@ -262,6 +272,43 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
writeSuccessResponseXML(w, encodeResponse(response)) writeSuccessResponseXML(w, encodeResponse(response))
} }
func getListEndpoint(bucket string) ListEndpoint {
return globalListEndpoints[crcHashMod(bucket, len(globalListEndpoints))]
}
// Proxy the list request to the right server.
func proxyListRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, bucket string) (success bool) {
if len(globalListEndpoints) == 0 {
return false
}
ep := getListEndpoint(bucket)
if ep.isLocal {
return false
}
ctx = r.Context()
outreq := r.Clone(ctx)
outreq.URL.Scheme = "http"
outreq.URL.Host = ep.host
outreq.URL.Path = r.URL.Path
outreq.Header.Add("Host", r.Host)
if globalIsSSL {
outreq.URL.Scheme = "https"
}
outreq.Host = r.Host
res, err := ep.t.RoundTrip(outreq)
if err != nil {
return false
}
for k, vv := range res.Header {
for _, v := range vv {
w.Header().Set(k, v)
}
}
w.WriteHeader(res.StatusCode)
io.Copy(w, res.Body)
return true
}
// ListObjectsV1Handler - GET Bucket (List Objects) Version 1. // ListObjectsV1Handler - GET Bucket (List Objects) Version 1.
// -------------------------- // --------------------------
// This implementation of the GET operation returns some or all (up to 10000) // This implementation of the GET operation returns some or all (up to 10000)
@ -300,6 +347,10 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
return return
} }
if proxyListRequest(ctx, w, r, bucket) {
return
}
listObjects := objectAPI.ListObjects listObjects := objectAPI.ListObjects
// Inititate a list objects operation based on the input params. // Inititate a list objects operation based on the input params.

@ -17,8 +17,10 @@
package cmd package cmd
import ( import (
"crypto/tls"
"fmt" "fmt"
"net" "net"
"net/http"
"net/url" "net/url"
"path" "path"
"path/filepath" "path/filepath"
@ -31,6 +33,7 @@ import (
"github.com/minio/minio-go/v6/pkg/set" "github.com/minio/minio-go/v6/pkg/set"
"github.com/minio/minio/cmd/config" "github.com/minio/minio/cmd/config"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/cmd/rest"
"github.com/minio/minio/pkg/env" "github.com/minio/minio/pkg/env"
"github.com/minio/minio/pkg/mountinfo" "github.com/minio/minio/pkg/mountinfo"
) )
@ -46,6 +49,14 @@ const (
URLEndpointType URLEndpointType
) )
// ListEndpoint - endpoint used for list redirects
// See proxyListRequest() for details.
type ListEndpoint struct {
host string
t *http.Transport
isLocal bool
}
// Endpoint - any type of endpoint. // Endpoint - any type of endpoint.
type Endpoint struct { type Endpoint struct {
*url.URL *url.URL
@ -708,6 +719,50 @@ func GetRemotePeers(endpointZones EndpointZones) []string {
return peerSet.ToSlice() return peerSet.ToSlice()
} }
// GetListEndpoints - get all endpoints that can be used to proxy list request.
func GetListEndpoints(endpointZones EndpointZones) ([]ListEndpoint, error) {
var listeps []ListEndpoint
listepExists := func(host string) bool {
for _, listep := range listeps {
if listep.host == host {
return true
}
}
return false
}
for _, ep := range endpointZones {
for _, endpoint := range ep.Endpoints {
if endpoint.Type() != URLEndpointType {
continue
}
host := endpoint.Host
if listepExists(host) {
continue
}
hostName, _, err := net.SplitHostPort(host)
if err != nil {
return nil, err
}
var tlsConfig *tls.Config
if globalIsSSL {
tlsConfig = &tls.Config{
ServerName: hostName,
RootCAs: globalRootCAs,
}
}
listeps = append(listeps, ListEndpoint{
host,
newCustomHTTPTransport(tlsConfig, rest.DefaultRESTTimeout)(),
endpoint.IsLocal,
})
}
}
return listeps, nil
}
func updateDomainIPs(endPoints set.StringSet) { func updateDomainIPs(endPoints set.StringSet) {
ipList := set.NewStringSet() ipList := set.NewStringSet()
for e := range endPoints { for e := range endPoints {

@ -279,6 +279,7 @@ var (
// If writes to FS backend should be O_SYNC. // If writes to FS backend should be O_SYNC.
globalFSOSync bool globalFSOSync bool
globalListEndpoints []ListEndpoint
// Add new variable global values here. // Add new variable global values here.
) )

@ -396,6 +396,9 @@ func serverMain(ctx *cli.Context) {
globalRootCAs, err = config.GetRootCAs(globalCertsCADir.Get()) globalRootCAs, err = config.GetRootCAs(globalCertsCADir.Get())
logger.FatalIf(err, "Failed to read root CAs (%v)", err) logger.FatalIf(err, "Failed to read root CAs (%v)", err)
globalListEndpoints, err = GetListEndpoints(globalEndpoints)
logger.FatalIf(err, "Invalid command line arguments")
globalMinioEndpoint = func() string { globalMinioEndpoint = func() string {
host := globalMinioHost host := globalMinioHost
if host == "" { if host == "" {

Loading…
Cancel
Save