diff --git a/docker/compose/local-cluster-compose.yml b/docker/compose/local-cluster-compose.yml index 7fb93e15b..05251ff1e 100644 --- a/docker/compose/local-cluster-compose.yml +++ b/docker/compose/local-cluster-compose.yml @@ -67,7 +67,7 @@ services: - 8888:8888 - 18888:18888 - 8111:8111 - command: 'filer -defaultReplicaPlacement 000 -iam -master="master0:9333,master1:9334,master2:9335"' + command: 'filer -defaultReplicaPlacement 100 -iam -master="master0:9333,master1:9334,master2:9335"' depends_on: - master0 - master1 @@ -85,20 +85,4 @@ services: - master2 - volume1 - volume2 - - filer - minio: - image: minio/minio - ports: - - 9000:9000 - command: 'minio server /data' - environment: - MINIO_ACCESS_KEY: "some_access_key1" - MINIO_SECRET_KEY: "some_secret_key1" - depends_on: - - s3 - nexus: - image: registry.tochka-tech.com/oci_nexus/nexus:v3.34.1-2 - ports: - - 8081:8081 - depends_on: - - s3 \ No newline at end of file + - filer \ No newline at end of file diff --git a/weed/filer/filer_conf.go b/weed/filer/filer_conf.go index 6a23189b8..acd1c6ecf 100644 --- a/weed/filer/filer_conf.go +++ b/weed/filer/filer_conf.go @@ -142,6 +142,18 @@ func (fc *FilerConf) MatchStorageRule(path string) (pathConf *filer_pb.FilerConf return pathConf } +func (fc *FilerConf) GetCollectionTtls(collection string) (ttls map[string]string) { + ttls = make(map[string]string) + fc.rules.Walk(func(key []byte, value interface{}) bool { + t := value.(*filer_pb.FilerConf_PathConf) + if t.Collection == collection { + ttls[t.LocationPrefix] = t.GetTtl() + } + return true + }) + return ttls +} + // merge if values in b is not empty, merge them into a func mergePathConf(a, b *filer_pb.FilerConf_PathConf) { a.Collection = util.Nvl(b.Collection, a.Collection) diff --git a/weed/s3api/s3api_bucket_handlers.go b/weed/s3api/s3api_bucket_handlers.go index 13129dbe4..b75012e9d 100644 --- a/weed/s3api/s3api_bucket_handlers.go +++ b/weed/s3api/s3api_bucket_handlers.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/chrislusf/seaweedfs/weed/filer" "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants" + "github.com/chrislusf/seaweedfs/weed/storage/needle" "math" "net/http" "time" @@ -264,7 +265,26 @@ func (s3a *S3ApiServer) GetBucketLifecycleConfigurationHandler(w http.ResponseWr s3err.WriteErrorResponse(w, s3err.ErrInternalError, r) return } - s3err.WriteErrorResponse(w, s3err.ErrNoSuchLifecycleConfiguration, r) + ttls := fc.GetCollectionTtls(bucket) + if len(ttls) == 0 { + s3err.WriteErrorResponse(w, s3err.ErrNoSuchLifecycleConfiguration, r) + } + response := Lifecycle{} + for prefix, internalTtl := range ttls { + ttl, _ := needle.ReadTTL(internalTtl) + days := int(ttl.Minutes() / 60 / 24) + if days == 0 { + continue + } + response.Rules = append(response.Rules, Rule{ + Status: Enabled, Filter: Filter{ + Prefix: Prefix{string: prefix, set: true}, + set: true, + }, + Expiration: Expiration{Days: days, set: true}, + }) + } + writeSuccessResponseXML(w, response) } // PutBucketLifecycleConfigurationHandler Put Bucket Lifecycle configuration diff --git a/weed/s3api/s3api_policy.go b/weed/s3api/s3api_policy.go index 20dac9564..4177d27f3 100644 --- a/weed/s3api/s3api_policy.go +++ b/weed/s3api/s3api_policy.go @@ -51,6 +51,24 @@ type Prefix struct { set bool } +// MarshalXML - decodes XML data. +func (p Prefix) MarshalXML(e *xml.Encoder, startElement xml.StartElement) error { + if !p.set { + return nil + } + return e.EncodeElement(p.string, startElement) +} + +func (f Filter) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if err := e.EncodeToken(start); err != nil { + return err + } + if err := e.EncodeElement(f.Prefix, xml.StartElement{Name: xml.Name{Local: "Prefix"}}); err != nil { + return err + } + return e.EncodeToken(xml.EndElement{Name: start.Name}) +} + // And - a tag to combine a prefix and multiple tags for lifecycle configuration rule. type And struct { XMLName xml.Name `xml:"And"` @@ -62,18 +80,50 @@ type And struct { type Expiration struct { XMLName xml.Name `xml:"Expiration"` Days int `xml:"Days,omitempty"` - Date time.Time `xml:"Date,omitempty"` + Date ExpirationDate `xml:"Date,omitempty"` DeleteMarker ExpireDeleteMarker `xml:"ExpiredObjectDeleteMarker"` set bool } +// MarshalXML encodes expiration field into an XML form. +func (e Expiration) MarshalXML(enc *xml.Encoder, startElement xml.StartElement) error { + if !e.set { + return nil + } + type expirationWrapper Expiration + return enc.EncodeElement(expirationWrapper(e), startElement) +} + // ExpireDeleteMarker represents value of ExpiredObjectDeleteMarker field in Expiration XML element. type ExpireDeleteMarker struct { val bool set bool } +// MarshalXML encodes delete marker boolean into an XML form. +func (b ExpireDeleteMarker) MarshalXML(e *xml.Encoder, startElement xml.StartElement) error { + if !b.set { + return nil + } + return e.EncodeElement(b.val, startElement) +} + +// ExpirationDate is a embedded type containing time.Time to unmarshal +// Date in Expiration +type ExpirationDate struct { + time.Time +} + +// MarshalXML encodes expiration date if it is non-zero and encodes +// empty string otherwise +func (eDate ExpirationDate) MarshalXML(e *xml.Encoder, startElement xml.StartElement) error { + if eDate.Time.IsZero() { + return nil + } + return e.EncodeElement(eDate.Format(time.RFC3339), startElement) +} + // Transition - transition actions for a rule in lifecycle configuration. type Transition struct { XMLName xml.Name `xml:"Transition"` @@ -84,5 +134,14 @@ type Transition struct { set bool } +// MarshalXML encodes transition field into an XML form. +func (t Transition) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { + if !t.set { + return nil + } + type transitionWrapper Transition + return enc.EncodeElement(transitionWrapper(t), start) +} + // TransitionDays is a type alias to unmarshal Days in Transition type TransitionDays int