mirror of
https://github.com/minio/minio.git
synced 2025-03-03 15:20:08 -05:00
feat: allow expiration of all versions via ILM Expiration action (#17521)
Following extension allows users to specify immediate purge of all versions as soon as the latest version of this object has expired. ``` <LifecycleConfiguration> <Rule> <ID>ClassADocRule</ID> <Filter> <Prefix>classA/</Prefix> </Filter> <Status>Enabled</Status> <Expiration> <Days>3650</Days> <ExpiredObjectAllVersions>true</ExpiredObjectAllVersions> </Expiration> </Rule> ... ```
This commit is contained in:
parent
5317a0b755
commit
aae6846413
@ -1187,6 +1187,9 @@ func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLay
|
|||||||
opts.Versioned = globalBucketVersioningSys.PrefixEnabled(obj.Bucket, obj.Name)
|
opts.Versioned = globalBucketVersioningSys.PrefixEnabled(obj.Bucket, obj.Name)
|
||||||
opts.VersionSuspended = globalBucketVersioningSys.PrefixSuspended(obj.Bucket, obj.Name)
|
opts.VersionSuspended = globalBucketVersioningSys.PrefixSuspended(obj.Bucket, obj.Name)
|
||||||
}
|
}
|
||||||
|
if lcEvent.Action.DeleteAll() {
|
||||||
|
opts.DeletePrefix = true
|
||||||
|
}
|
||||||
|
|
||||||
obj, err := objLayer.DeleteObject(ctx, obj.Bucket, obj.Name, opts)
|
obj, err := objLayer.DeleteObject(ctx, obj.Bucket, obj.Name, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -993,13 +993,10 @@ func (z *erasureServerPools) DeleteObject(ctx context.Context, bucket string, ob
|
|||||||
return objInfo, err
|
return objInfo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.DeletePrefix {
|
if !opts.DeletePrefix { // DeletePrefix handles dir object encoding differently.
|
||||||
err := z.deletePrefix(ctx, bucket, object)
|
object = encodeDirObject(object)
|
||||||
return ObjectInfo{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object = encodeDirObject(object)
|
|
||||||
|
|
||||||
// Acquire a write lock before deleting the object.
|
// Acquire a write lock before deleting the object.
|
||||||
lk := z.NewNSLock(bucket, object)
|
lk := z.NewNSLock(bucket, object)
|
||||||
lkctx, err := lk.GetLock(ctx, globalDeleteOperationTimeout)
|
lkctx, err := lk.GetLock(ctx, globalDeleteOperationTimeout)
|
||||||
@ -1009,6 +1006,10 @@ func (z *erasureServerPools) DeleteObject(ctx context.Context, bucket string, ob
|
|||||||
ctx = lkctx.Context()
|
ctx = lkctx.Context()
|
||||||
defer lk.Unlock(lkctx)
|
defer lk.Unlock(lkctx)
|
||||||
|
|
||||||
|
if opts.DeletePrefix {
|
||||||
|
return ObjectInfo{}, z.deletePrefix(ctx, bucket, object)
|
||||||
|
}
|
||||||
|
|
||||||
gopts := opts
|
gopts := opts
|
||||||
gopts.NoLock = true
|
gopts.NoLock = true
|
||||||
pinfo, err := z.getPoolInfoExistingWithOpts(ctx, bucket, object, gopts)
|
pinfo, err := z.getPoolInfoExistingWithOpts(ctx, bucket, object, gopts)
|
||||||
|
@ -129,9 +129,31 @@ of objects under the prefix `user-uploads/` as soon as there are more than `N` n
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: This rule has an implicit zero NoncurrentDays, which makes the expiry of those 'extra' noncurrent versions immediate.
|
Note: This rule has an implicit zero NoncurrentDays, which makes the expiry of those 'extra' noncurrent versions immediate.
|
||||||
|
|
||||||
|
#### 3.2.b Automatic removal of all versions (MinIO only extension)
|
||||||
|
|
||||||
|
This is available only on MinIO as an extension to the Expiration feature. The following rule makes it possible to remove all versions of an object under
|
||||||
|
the prefix `user-uploads/` as soon as the latest object satisfies the expiration criteria.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"Rules": [
|
||||||
|
{
|
||||||
|
"ID": "Purge all versions of an expired object",
|
||||||
|
"Status": "Enabled",
|
||||||
|
"Filter": {
|
||||||
|
"Prefix": "users-uploads/"
|
||||||
|
},
|
||||||
|
"Expiration": {
|
||||||
|
"Days": 7,
|
||||||
|
"ExpiredObjectAllVersions": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### 3.3 Automatic removal of delete markers with no other versions
|
### 3.3 Automatic removal of delete markers with no other versions
|
||||||
|
|
||||||
When an object has only one version as a delete marker, the latter can be automatically removed after a certain number of days using the following configuration:
|
When an object has only one version as a delete marker, the latter can be automatically removed after a certain number of days using the following configuration:
|
||||||
|
@ -162,7 +162,6 @@ func getDiskLocation(f format) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var node, args string
|
var node, args string
|
||||||
|
|
||||||
flag.StringVar(&node, "local-node-name", "", "the name of the local node")
|
flag.StringVar(&node, "local-node-name", "", "the name of the local node")
|
||||||
|
@ -15,12 +15,13 @@ func _() {
|
|||||||
_ = x[TransitionVersionAction-4]
|
_ = x[TransitionVersionAction-4]
|
||||||
_ = x[DeleteRestoredAction-5]
|
_ = x[DeleteRestoredAction-5]
|
||||||
_ = x[DeleteRestoredVersionAction-6]
|
_ = x[DeleteRestoredVersionAction-6]
|
||||||
_ = x[ActionCount-7]
|
_ = x[DeleteAllVersionsAction-7]
|
||||||
|
_ = x[ActionCount-8]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Action_name = "NoneActionDeleteActionDeleteVersionActionTransitionActionTransitionVersionActionDeleteRestoredActionDeleteRestoredVersionActionActionCount"
|
const _Action_name = "NoneActionDeleteActionDeleteVersionActionTransitionActionTransitionVersionActionDeleteRestoredActionDeleteRestoredVersionActionDeleteAllVersionsActionActionCount"
|
||||||
|
|
||||||
var _Action_index = [...]uint8{0, 10, 22, 41, 57, 80, 100, 127, 138}
|
var _Action_index = [...]uint8{0, 10, 22, 41, 57, 80, 100, 127, 150, 161}
|
||||||
|
|
||||||
func (i Action) String() string {
|
func (i Action) String() string {
|
||||||
if i < 0 || i >= Action(len(_Action_index)-1) {
|
if i < 0 || i >= Action(len(_Action_index)-1) {
|
||||||
|
@ -100,6 +100,11 @@ func (eDate ExpirationDate) MarshalXML(e *xml.Encoder, startElement xml.StartEle
|
|||||||
|
|
||||||
// ExpireDeleteMarker represents value of ExpiredObjectDeleteMarker field in Expiration XML element.
|
// ExpireDeleteMarker represents value of ExpiredObjectDeleteMarker field in Expiration XML element.
|
||||||
type ExpireDeleteMarker struct {
|
type ExpireDeleteMarker struct {
|
||||||
|
Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean signifies a boolean XML struct with custom marshaling
|
||||||
|
type Boolean struct {
|
||||||
val bool
|
val bool
|
||||||
set bool
|
set bool
|
||||||
}
|
}
|
||||||
@ -110,12 +115,16 @@ type Expiration struct {
|
|||||||
Days ExpirationDays `xml:"Days,omitempty"`
|
Days ExpirationDays `xml:"Days,omitempty"`
|
||||||
Date ExpirationDate `xml:"Date,omitempty"`
|
Date ExpirationDate `xml:"Date,omitempty"`
|
||||||
DeleteMarker ExpireDeleteMarker `xml:"ExpiredObjectDeleteMarker"`
|
DeleteMarker ExpireDeleteMarker `xml:"ExpiredObjectDeleteMarker"`
|
||||||
|
// Indicates whether MinIO will remove all versions. If set to true, all versions will be deleted;
|
||||||
|
// if set to false the policy takes no action. This action uses the Days/Date to expire objects.
|
||||||
|
// This check is verified for latest version of the object.
|
||||||
|
DeleteAll Boolean `xml:"ExpiredObjectAllVersions"`
|
||||||
|
|
||||||
set bool
|
set bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML encodes delete marker boolean into an XML form.
|
// MarshalXML encodes delete marker boolean into an XML form.
|
||||||
func (b ExpireDeleteMarker) MarshalXML(e *xml.Encoder, startElement xml.StartElement) error {
|
func (b Boolean) MarshalXML(e *xml.Encoder, startElement xml.StartElement) error {
|
||||||
if !b.set {
|
if !b.set {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -123,7 +132,7 @@ func (b ExpireDeleteMarker) MarshalXML(e *xml.Encoder, startElement xml.StartEle
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalXML decodes delete marker boolean from the XML form.
|
// UnmarshalXML decodes delete marker boolean from the XML form.
|
||||||
func (b *ExpireDeleteMarker) UnmarshalXML(d *xml.Decoder, startElement xml.StartElement) error {
|
func (b *Boolean) UnmarshalXML(d *xml.Decoder, startElement xml.StartElement) error {
|
||||||
var exp bool
|
var exp bool
|
||||||
err := d.DecodeElement(&exp, &startElement)
|
err := d.DecodeElement(&exp, &startElement)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -65,6 +65,8 @@ const (
|
|||||||
DeleteRestoredAction
|
DeleteRestoredAction
|
||||||
// DeleteRestoredVersionAction deletes a particular version that was temporarily restored
|
// DeleteRestoredVersionAction deletes a particular version that was temporarily restored
|
||||||
DeleteRestoredVersionAction
|
DeleteRestoredVersionAction
|
||||||
|
// DeleteAllVersionsAction deletes all versions when an object expires
|
||||||
|
DeleteAllVersionsAction
|
||||||
|
|
||||||
// ActionCount must be the last action and shouldn't be used as a regular action.
|
// ActionCount must be the last action and shouldn't be used as a regular action.
|
||||||
ActionCount
|
ActionCount
|
||||||
@ -80,6 +82,11 @@ func (a Action) DeleteVersioned() bool {
|
|||||||
return a == DeleteVersionAction || a == DeleteRestoredVersionAction
|
return a == DeleteVersionAction || a == DeleteRestoredVersionAction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteAll - Returns true if the action demands deleting all versions of an object
|
||||||
|
func (a Action) DeleteAll() bool {
|
||||||
|
return a == DeleteAllVersionsAction
|
||||||
|
}
|
||||||
|
|
||||||
// Delete - Returns true if action demands delete on all objects (including restored)
|
// Delete - Returns true if action demands delete on all objects (including restored)
|
||||||
func (a Action) Delete() bool {
|
func (a Action) Delete() bool {
|
||||||
if a.DeleteRestored() {
|
if a.DeleteRestored() {
|
||||||
@ -324,6 +331,23 @@ func (lc Lifecycle) eval(obj ObjectOpts, now time.Time) Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, rule := range lc.FilterRules(obj) {
|
for _, rule := range lc.FilterRules(obj) {
|
||||||
|
if obj.IsLatest && rule.Expiration.DeleteAll.val {
|
||||||
|
if !rule.Expiration.IsDaysNull() {
|
||||||
|
// Specifying the Days tag will automatically perform all versions cleanup
|
||||||
|
// once the latest object is old enough to satisfy the age criteria.
|
||||||
|
// This is a MinIO only extension.
|
||||||
|
if expectedExpiry := ExpectedExpiryTime(obj.ModTime, int(rule.Expiration.Days)); now.IsZero() || now.After(expectedExpiry) {
|
||||||
|
events = append(events, Event{
|
||||||
|
Action: DeleteAllVersionsAction,
|
||||||
|
RuleID: rule.ID,
|
||||||
|
Due: expectedExpiry,
|
||||||
|
})
|
||||||
|
// No other conflicting actions apply to an all version expired object.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if obj.ExpiredObjectDeleteMarker() {
|
if obj.ExpiredObjectDeleteMarker() {
|
||||||
if rule.Expiration.DeleteMarker.val {
|
if rule.Expiration.DeleteMarker.val {
|
||||||
// Indicates whether MinIO will remove a delete marker with no noncurrent versions.
|
// Indicates whether MinIO will remove a delete marker with no noncurrent versions.
|
||||||
|
@ -388,6 +388,15 @@ func TestEval(t *testing.T) {
|
|||||||
isExpiredDelMarker: true,
|
isExpiredDelMarker: true,
|
||||||
expectedAction: DeleteVersionAction,
|
expectedAction: DeleteVersionAction,
|
||||||
},
|
},
|
||||||
|
// Should delete expired object right away with 1 day expiration
|
||||||
|
{
|
||||||
|
inputConfig: `<BucketLifecycleConfiguration><Rule><Expiration><Days>1</Days><ExpiredObjectAllVersions>true</ExpiredObjectAllVersions></Expiration><Filter></Filter><Status>Enabled</Status></Rule></BucketLifecycleConfiguration>`,
|
||||||
|
objectName: "foodir/fooobject",
|
||||||
|
objectModTime: time.Now().UTC().Add(-10 * 24 * time.Hour), // Created 10 days ago
|
||||||
|
isExpiredDelMarker: true,
|
||||||
|
expectedAction: DeleteAllVersionsAction,
|
||||||
|
},
|
||||||
|
|
||||||
// Should not delete expired marker if its time has not come yet
|
// Should not delete expired marker if its time has not come yet
|
||||||
{
|
{
|
||||||
inputConfig: `<BucketLifecycleConfiguration><Rule><Filter></Filter><Status>Enabled</Status><Expiration><Days>1</Days></Expiration></Rule></BucketLifecycleConfiguration>`,
|
inputConfig: `<BucketLifecycleConfiguration><Rule><Filter></Filter><Status>Enabled</Status><Expiration><Days>1</Days></Expiration></Rule></BucketLifecycleConfiguration>`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user