You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
6.0 KiB

  1. package s3api
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
  6. "github.com/aws/aws-sdk-go/service/s3"
  7. "github.com/seaweedfs/seaweedfs/weed/glog"
  8. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  9. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  10. "github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
  11. //"github.com/seaweedfs/seaweedfs/weed/s3api"
  12. "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
  13. "github.com/seaweedfs/seaweedfs/weed/util"
  14. "math"
  15. "sync"
  16. )
  17. var loadBucketMetadataFromFiler = func(r *BucketRegistry, bucketName string) (*BucketMetaData, error) {
  18. entry, err := filer_pb.GetEntry(r.s3a, util.NewFullPath(r.s3a.option.BucketsPath, bucketName))
  19. if err != nil {
  20. return nil, err
  21. }
  22. return buildBucketMetadata(entry), nil
  23. }
  24. type BucketMetaData struct {
  25. _ struct{} `type:"structure"`
  26. Name string
  27. //By default, when another AWS account uploads an object to S3 bucket,
  28. //that account (the object writer) owns the object, has access to it, and
  29. //can grant other users access to it through ACLs. You can use Object Ownership
  30. //to change this default behavior so that ACLs are disabled and you, as the
  31. //bucket owner, automatically own every object in your bucket.
  32. ObjectOwnership string
  33. // Container for the bucket owner's display name and ID.
  34. Owner *s3.Owner `type:"structure"`
  35. // A list of grants for access controls.
  36. Acl []*s3.Grant `locationName:"AccessControlList" locationNameList:"Grant" type:"list"`
  37. }
  38. type BucketRegistry struct {
  39. metadataCache map[string]*BucketMetaData
  40. metadataCacheLock sync.RWMutex
  41. notFound map[string]struct{}
  42. notFoundLock sync.RWMutex
  43. s3a *S3ApiServer
  44. }
  45. func NewBucketRegistry(s3a *S3ApiServer) *BucketRegistry {
  46. br := &BucketRegistry{
  47. metadataCache: make(map[string]*BucketMetaData),
  48. notFound: make(map[string]struct{}),
  49. s3a: s3a,
  50. }
  51. err := br.init()
  52. if err != nil {
  53. glog.Fatal("init bucket registry failed", err)
  54. return nil
  55. }
  56. return br
  57. }
  58. func (r *BucketRegistry) init() error {
  59. err := filer_pb.List(r.s3a, r.s3a.option.BucketsPath, "", func(entry *filer_pb.Entry, isLast bool) error {
  60. r.LoadBucketMetadata(entry)
  61. return nil
  62. }, "", false, math.MaxUint32)
  63. return err
  64. }
  65. func (r *BucketRegistry) LoadBucketMetadata(entry *filer_pb.Entry) {
  66. bucketMetadata := buildBucketMetadata(entry)
  67. r.metadataCacheLock.Lock()
  68. defer r.metadataCacheLock.Unlock()
  69. r.metadataCache[entry.Name] = bucketMetadata
  70. }
  71. func buildBucketMetadata(entry *filer_pb.Entry) *BucketMetaData {
  72. entryJson, _ := json.Marshal(entry)
  73. glog.V(3).Infof("build bucket metadata,entry=%s", entryJson)
  74. bucketMetadata := &BucketMetaData{
  75. Name: entry.Name,
  76. //Default ownership: OwnershipBucketOwnerEnforced, which means Acl is disabled
  77. ObjectOwnership: s3_constants.OwnershipBucketOwnerEnforced,
  78. // Default owner: `AccountAdmin`
  79. Owner: &s3.Owner{
  80. ID: &s3account.AccountAdmin.Id,
  81. DisplayName: &s3account.AccountAdmin.Name,
  82. },
  83. }
  84. if entry.Extended != nil {
  85. //ownership control
  86. ownership, ok := entry.Extended[s3_constants.ExtOwnershipKey]
  87. if ok {
  88. ownership := string(ownership)
  89. valid := s3_constants.ValidateOwnership(ownership)
  90. if valid {
  91. bucketMetadata.ObjectOwnership = ownership
  92. } else {
  93. glog.Warningf("Invalid ownership: %s, bucket: %s", ownership, bucketMetadata.Name)
  94. }
  95. }
  96. //access control policy
  97. acpBytes, ok := entry.Extended[s3_constants.ExtAcpKey]
  98. if ok {
  99. var acp s3.AccessControlPolicy
  100. err := jsonutil.UnmarshalJSON(&acp, bytes.NewReader(acpBytes))
  101. if err == nil {
  102. //validate owner
  103. if acp.Owner != nil && acp.Owner.ID != nil {
  104. bucketMetadata.Owner = acp.Owner
  105. } else {
  106. glog.Warningf("bucket ownerId is empty! bucket: %s", bucketMetadata.Name)
  107. }
  108. //acl
  109. bucketMetadata.Acl = acp.Grants
  110. } else {
  111. glog.Warningf("Unmarshal ACP: %s(%v), bucket: %s", string(acpBytes), err, bucketMetadata.Name)
  112. }
  113. }
  114. }
  115. return bucketMetadata
  116. }
  117. func (r *BucketRegistry) RemoveBucketMetadata(entry *filer_pb.Entry) {
  118. r.removeMetadataCache(entry.Name)
  119. r.unMarkNotFound(entry.Name)
  120. }
  121. func (r *BucketRegistry) GetBucketMetadata(bucketName string) (*BucketMetaData, s3err.ErrorCode) {
  122. r.metadataCacheLock.RLock()
  123. bucketMetadata, ok := r.metadataCache[bucketName]
  124. r.metadataCacheLock.RUnlock()
  125. if ok {
  126. return bucketMetadata, s3err.ErrNone
  127. }
  128. r.notFoundLock.RLock()
  129. _, ok = r.notFound[bucketName]
  130. r.notFoundLock.RUnlock()
  131. if ok {
  132. return nil, s3err.ErrNoSuchBucket
  133. }
  134. bucketMetadata, errCode := r.LoadBucketMetadataFromFiler(bucketName)
  135. if errCode != s3err.ErrNone {
  136. return nil, errCode
  137. }
  138. r.setMetadataCache(bucketMetadata)
  139. r.unMarkNotFound(bucketName)
  140. return bucketMetadata, s3err.ErrNone
  141. }
  142. func (r *BucketRegistry) LoadBucketMetadataFromFiler(bucketName string) (*BucketMetaData, s3err.ErrorCode) {
  143. r.notFoundLock.Lock()
  144. defer r.notFoundLock.Unlock()
  145. //check if already exists
  146. r.metadataCacheLock.RLock()
  147. bucketMetaData, ok := r.metadataCache[bucketName]
  148. r.metadataCacheLock.RUnlock()
  149. if ok {
  150. return bucketMetaData, s3err.ErrNone
  151. }
  152. //if not exists, load from filer
  153. bucketMetadata, err := loadBucketMetadataFromFiler(r, bucketName)
  154. if err != nil {
  155. if err == filer_pb.ErrNotFound {
  156. // The bucket doesn't actually exist and should no longer loaded from the filer
  157. r.notFound[bucketName] = struct{}{}
  158. return nil, s3err.ErrNoSuchBucket
  159. }
  160. return nil, s3err.ErrInternalError
  161. }
  162. return bucketMetadata, s3err.ErrNone
  163. }
  164. func (r *BucketRegistry) setMetadataCache(metadata *BucketMetaData) {
  165. r.metadataCacheLock.Lock()
  166. defer r.metadataCacheLock.Unlock()
  167. r.metadataCache[metadata.Name] = metadata
  168. }
  169. func (r *BucketRegistry) removeMetadataCache(bucket string) {
  170. r.metadataCacheLock.Lock()
  171. defer r.metadataCacheLock.Unlock()
  172. delete(r.metadataCache, bucket)
  173. }
  174. func (r *BucketRegistry) markNotFound(bucket string) {
  175. r.notFoundLock.Lock()
  176. defer r.notFoundLock.Unlock()
  177. r.notFound[bucket] = struct{}{}
  178. }
  179. func (r *BucketRegistry) unMarkNotFound(bucket string) {
  180. r.notFoundLock.Lock()
  181. defer r.notFoundLock.Unlock()
  182. delete(r.notFound, bucket)
  183. }