Support buckets with '.' with etcd+coreDNS (#7353)

Fixes #7340
This commit is contained in:
Harshavardhana 2019-03-12 17:57:08 -07:00 committed by kannappanr
parent ce4563370c
commit 285c09fe6b
3 changed files with 27 additions and 24 deletions

View File

@ -226,7 +226,7 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
continue continue
} }
bucketsInfo = append(bucketsInfo, BucketInfo{ bucketsInfo = append(bucketsInfo, BucketInfo{
Name: strings.Trim(dnsRecord.Key, slashSeparator), Name: dnsRecord.Key,
Created: dnsRecord.CreationDate, Created: dnsRecord.CreationDate,
}) })
bucketSet.Add(dnsRecord.Key) bucketSet.Add(dnsRecord.Key)

View File

@ -39,6 +39,7 @@ import (
"github.com/gorilla/rpc/v2/json2" "github.com/gorilla/rpc/v2/json2"
miniogopolicy "github.com/minio/minio-go/pkg/policy" miniogopolicy "github.com/minio/minio-go/pkg/policy"
"github.com/minio/minio-go/pkg/s3utils" "github.com/minio/minio-go/pkg/s3utils"
"github.com/minio/minio-go/pkg/set"
"github.com/minio/minio/browser" "github.com/minio/minio/browser"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
@ -296,24 +297,29 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re
// If etcd, dns federation configured list buckets from etcd. // If etcd, dns federation configured list buckets from etcd.
if globalDNSConfig != nil { if globalDNSConfig != nil {
dnsBuckets, err := globalDNSConfig.List() dnsBuckets, err := globalDNSConfig.List()
if err != nil { if err != nil && err != dns.ErrNoEntriesFound {
return toJSONError(err) return toJSONError(err)
} }
bucketSet := set.NewStringSet()
for _, dnsRecord := range dnsBuckets { for _, dnsRecord := range dnsBuckets {
bucketName := strings.Trim(dnsRecord.Key, "/") if bucketSet.Contains(dnsRecord.Key) {
continue
}
if globalIAMSys.IsAllowed(iampolicy.Args{ if globalIAMSys.IsAllowed(iampolicy.Args{
AccountName: claims.Subject, AccountName: claims.Subject,
Action: iampolicy.ListBucketAction, Action: iampolicy.ListBucketAction,
BucketName: bucketName, BucketName: dnsRecord.Key,
ConditionValues: getConditionValues(r, "", claims.Subject), ConditionValues: getConditionValues(r, "", claims.Subject),
IsOwner: owner, IsOwner: owner,
ObjectName: "", ObjectName: "",
}) { }) {
reply.Buckets = append(reply.Buckets, WebBucketInfo{ reply.Buckets = append(reply.Buckets, WebBucketInfo{
Name: bucketName, Name: dnsRecord.Key,
CreationDate: dnsRecord.CreationDate, CreationDate: dnsRecord.CreationDate,
}) })
bucketSet.Add(dnsRecord.Key)
} }
} }
} else { } else {

View File

@ -35,6 +35,8 @@ import (
// ErrNoEntriesFound - Indicates no entries were found for the given key (directory) // ErrNoEntriesFound - Indicates no entries were found for the given key (directory)
var ErrNoEntriesFound = errors.New("No entries found for this key") var ErrNoEntriesFound = errors.New("No entries found for this key")
const etcdPathSeparator = "/"
// create a new coredns service record for the bucket. // create a new coredns service record for the bucket.
func newCoreDNSMsg(bucket, ip string, port int, ttl uint32) ([]byte, error) { func newCoreDNSMsg(bucket, ip string, port int, ttl uint32) ([]byte, error) {
return json.Marshal(&SrvRecord{ return json.Marshal(&SrvRecord{
@ -73,6 +75,15 @@ func (c *coreDNS) Get(bucket string) ([]SrvRecord, error) {
return srvRecords, nil return srvRecords, nil
} }
// msgUnPath converts a etcd path to domainname.
func msgUnPath(s string) string {
ks := strings.Split(strings.Trim(s, etcdPathSeparator), etcdPathSeparator)
for i, j := 0, len(ks)-1; i < j; i, j = i+1, j-1 {
ks[i], ks[j] = ks[j], ks[i]
}
return strings.Join(ks, ".")
}
// Retrieves list of entries under the key passed. // Retrieves list of entries under the key passed.
// Note that this method fetches entries upto only two levels deep. // Note that this method fetches entries upto only two levels deep.
func (c *coreDNS) list(key string) ([]SrvRecord, error) { func (c *coreDNS) list(key string) ([]SrvRecord, error) {
@ -83,7 +94,7 @@ func (c *coreDNS) list(key string) ([]SrvRecord, error) {
return nil, err return nil, err
} }
if r.Count == 0 { if r.Count == 0 {
key = strings.TrimSuffix(key, "/") key = strings.TrimSuffix(key, etcdPathSeparator)
r, err = c.etcdClient.Get(ctx, key) r, err = c.etcdClient.Get(ctx, key)
if err != nil { if err != nil {
return nil, err return nil, err
@ -110,22 +121,8 @@ func (c *coreDNS) list(key string) ([]SrvRecord, error) {
continue continue
} }
// SRV records are stored in the following form srvRecord.Key = msgUnPath(srvRecord.Key)
// /skydns/net/miniocloud/bucket1, so this function serves multiple srvRecords = append(srvRecords, srvRecord)
// purposes basically when we do a Get(bucketName) this function
// should return a single DNS record for any input 'bucketName'.
//
// In all other situations when we want to list all DNS records,
// which is handled in the else clause.
for _, domainName := range c.domainNames {
if key != msg.Path(fmt.Sprintf(".%s.", domainName), defaultPrefixPath) {
if srvRecord.Key == "/" {
srvRecords = append(srvRecords, srvRecord)
}
} else {
srvRecords = append(srvRecords, srvRecord)
}
}
} }
if len(srvRecords) == 0 { if len(srvRecords) == 0 {
@ -146,7 +143,7 @@ func (c *coreDNS) Put(bucket string) error {
} }
for _, domainName := range c.domainNames { for _, domainName := range c.domainNames {
key := msg.Path(fmt.Sprintf("%s.%s", bucket, domainName), defaultPrefixPath) key := msg.Path(fmt.Sprintf("%s.%s", bucket, domainName), defaultPrefixPath)
key = key + "/" + ip key = key + etcdPathSeparator + ip
ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout) ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout)
_, err = c.etcdClient.Put(ctx, key, string(bucketMsg)) _, err = c.etcdClient.Put(ctx, key, string(bucketMsg))
defer cancel() defer cancel()
@ -171,7 +168,7 @@ func (c *coreDNS) Delete(bucket string) error {
} }
for _, record := range srvRecords { for _, record := range srvRecords {
dctx, dcancel := context.WithTimeout(context.Background(), defaultContextTimeout) dctx, dcancel := context.WithTimeout(context.Background(), defaultContextTimeout)
if _, err = c.etcdClient.Delete(dctx, key+"/"+record.Host); err != nil { if _, err = c.etcdClient.Delete(dctx, key+etcdPathSeparator+record.Host); err != nil {
dcancel() dcancel()
return err return err
} }