mirror of
https://github.com/minio/minio.git
synced 2025-11-10 05:59:43 -05:00
Use random host from among multiple hosts to create requests
Also use hosts passed to Minio startup command to populate IP addresses if MINIO_PUBLIC_IPS is not set.
This commit is contained in:
committed by
kannappanr
parent
6ce7265c8c
commit
3dc13323e5
@@ -32,7 +32,9 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
miniogo "github.com/minio/minio-go"
|
||||
"github.com/minio/minio/cmd/logger"
|
||||
"github.com/minio/minio/pkg/dns"
|
||||
"github.com/minio/minio/pkg/event"
|
||||
"github.com/minio/minio/pkg/hash"
|
||||
"github.com/minio/minio/pkg/ioutil"
|
||||
@@ -538,40 +540,62 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
|
||||
var objInfo ObjectInfo
|
||||
|
||||
// _, err = objectAPI.GetBucketInfo(ctx, dstBucket)
|
||||
// if err == toObjectErr(errVolumeNotFound, dstBucket) && !cpSrcDstSame
|
||||
// Checks if a remote putobject call is needed for CopyObject operation
|
||||
// 1. If source and destination bucket names are same, it means no call needed to etcd to get destination info
|
||||
// 2. If destination bucket doesn't exist locally, only then a etcd call is needed
|
||||
var isRemoteCallRequired = func(ctx context.Context, src, dst string, objAPI ObjectLayer) bool {
|
||||
if src == dst {
|
||||
return false
|
||||
}
|
||||
_, berr := objAPI.GetBucketInfo(ctx, dst)
|
||||
return berr == toObjectErr(errVolumeNotFound, dst)
|
||||
}
|
||||
|
||||
// Returns a minio-go Client configured to access remote host described by destDNSRecord
|
||||
// Applicable only in a federated deployment
|
||||
var getRemoteInstanceClient = func(host string, port int) (*miniogo.Core, error) {
|
||||
// In a federated deployment, all the instances share config files and hence expected to have same
|
||||
// credentials. So, access current instances creds and use it to create client for remote instance
|
||||
endpoint := net.JoinHostPort(host, strconv.Itoa(port))
|
||||
accessKey := globalServerConfig.Credential.AccessKey
|
||||
secretKey := globalServerConfig.Credential.SecretKey
|
||||
return miniogo.NewCore(endpoint, accessKey, secretKey, globalIsSSL)
|
||||
}
|
||||
|
||||
if isRemoteCallRequired(ctx, srcBucket, dstBucket, objectAPI) {
|
||||
if globalDNSConfig != nil {
|
||||
if dstRecord, errEtcd := globalDNSConfig.Get(dstBucket); errEtcd == nil {
|
||||
go func() {
|
||||
if gerr := objectAPI.GetObject(ctx, srcBucket, srcObject, 0, srcInfo.Size, srcInfo.Writer, srcInfo.ETag); gerr != nil {
|
||||
pipeWriter.CloseWithError(gerr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
// Close writer explicitly to indicate data has been written
|
||||
defer srcInfo.Writer.Close()
|
||||
}()
|
||||
// Send PutObject request to appropriate instance (in federated deployment)
|
||||
client, rerr := getRemoteInstanceClient(dstRecord[0])
|
||||
if rerr != nil {
|
||||
pipeWriter.CloseWithError(rerr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
remoteObjInfo, rerr := client.PutObject(dstBucket, dstObject, srcInfo.Reader, srcInfo.Size, "", "", srcInfo.UserDefined)
|
||||
if rerr != nil {
|
||||
pipeWriter.CloseWithError(rerr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
objInfo.ETag = remoteObjInfo.ETag
|
||||
objInfo.ModTime = remoteObjInfo.LastModified
|
||||
}
|
||||
} else {
|
||||
if globalDNSConfig == nil {
|
||||
writeErrorResponse(w, ErrNoSuchBucket, r.URL)
|
||||
return
|
||||
}
|
||||
var dstRecords []dns.SrvRecord
|
||||
if dstRecords, err = globalDNSConfig.Get(dstBucket); err == nil {
|
||||
go func() {
|
||||
if gerr := objectAPI.GetObject(ctx, srcBucket, srcObject, 0, srcInfo.Size, srcInfo.Writer, srcInfo.ETag); gerr != nil {
|
||||
pipeWriter.CloseWithError(gerr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
// Close writer explicitly to indicate data has been written
|
||||
srcInfo.Writer.Close()
|
||||
}()
|
||||
|
||||
// Send PutObject request to appropriate instance (in federated deployment)
|
||||
host, port := getRandomHostPort(dstRecords)
|
||||
client, rerr := getRemoteInstanceClient(host, port)
|
||||
if rerr != nil {
|
||||
pipeWriter.CloseWithError(rerr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
remoteObjInfo, rerr := client.PutObject(dstBucket, dstObject, srcInfo.Reader, srcInfo.Size, "", "", srcInfo.UserDefined)
|
||||
if rerr != nil {
|
||||
pipeWriter.CloseWithError(rerr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
objInfo.ETag = remoteObjInfo.ETag
|
||||
objInfo.ModTime = remoteObjInfo.LastModified
|
||||
}
|
||||
} else {
|
||||
// Copy source object to destination, if source and destination
|
||||
// object is same then only metadata is updated.
|
||||
|
||||
Reference in New Issue
Block a user