github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/bucket/lifecycle/noncurrentversion.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package lifecycle 19 20 import ( 21 "encoding/xml" 22 "time" 23 ) 24 25 // NoncurrentVersionExpiration - an action for lifecycle configuration rule. 26 type NoncurrentVersionExpiration struct { 27 XMLName xml.Name `xml:"NoncurrentVersionExpiration"` 28 NoncurrentDays ExpirationDays `xml:"NoncurrentDays,omitempty"` 29 NewerNoncurrentVersions int `xml:"NewerNoncurrentVersions,omitempty"` 30 set bool 31 } 32 33 // MarshalXML if non-current days not set to non zero value 34 func (n NoncurrentVersionExpiration) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 35 if n.IsNull() { 36 return nil 37 } 38 type noncurrentVersionExpirationWrapper NoncurrentVersionExpiration 39 return e.EncodeElement(noncurrentVersionExpirationWrapper(n), start) 40 } 41 42 // UnmarshalXML decodes NoncurrentVersionExpiration 43 func (n *NoncurrentVersionExpiration) UnmarshalXML(d *xml.Decoder, startElement xml.StartElement) error { 44 // To handle xml with MaxNoncurrentVersions from older MinIO releases. 45 // note: only one of MaxNoncurrentVersions or NewerNoncurrentVersions would be present. 46 type noncurrentExpiration struct { 47 XMLName xml.Name `xml:"NoncurrentVersionExpiration"` 48 NoncurrentDays ExpirationDays `xml:"NoncurrentDays,omitempty"` 49 NewerNoncurrentVersions int `xml:"NewerNoncurrentVersions,omitempty"` 50 MaxNoncurrentVersions int `xml:"MaxNoncurrentVersions,omitempty"` 51 } 52 53 var val noncurrentExpiration 54 err := d.DecodeElement(&val, &startElement) 55 if err != nil { 56 return err 57 } 58 if val.MaxNoncurrentVersions > 0 { 59 val.NewerNoncurrentVersions = val.MaxNoncurrentVersions 60 } 61 *n = NoncurrentVersionExpiration{ 62 XMLName: val.XMLName, 63 NoncurrentDays: val.NoncurrentDays, 64 NewerNoncurrentVersions: val.NewerNoncurrentVersions, 65 } 66 n.set = true 67 return nil 68 } 69 70 // IsNull returns if both NoncurrentDays and NoncurrentVersions are empty 71 func (n NoncurrentVersionExpiration) IsNull() bool { 72 return n.IsDaysNull() && n.NewerNoncurrentVersions == 0 73 } 74 75 // IsDaysNull returns true if days field is null 76 func (n NoncurrentVersionExpiration) IsDaysNull() bool { 77 return n.NoncurrentDays == ExpirationDays(0) 78 } 79 80 // Validate returns an error with wrong value 81 func (n NoncurrentVersionExpiration) Validate() error { 82 if !n.set { 83 return nil 84 } 85 val := int(n.NoncurrentDays) 86 switch { 87 case val == 0 && n.NewerNoncurrentVersions == 0: 88 // both fields can't be zero 89 return errXMLNotWellFormed 90 91 case val < 0, n.NewerNoncurrentVersions < 0: 92 // negative values are not supported 93 return errXMLNotWellFormed 94 } 95 return nil 96 } 97 98 // NoncurrentVersionTransition - an action for lifecycle configuration rule. 99 type NoncurrentVersionTransition struct { 100 NoncurrentDays TransitionDays `xml:"NoncurrentDays"` 101 StorageClass string `xml:"StorageClass"` 102 set bool 103 } 104 105 // MarshalXML is extended to leave out 106 // <NoncurrentVersionTransition></NoncurrentVersionTransition> tags 107 func (n NoncurrentVersionTransition) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 108 if n.IsNull() { 109 return nil 110 } 111 type noncurrentVersionTransitionWrapper NoncurrentVersionTransition 112 return e.EncodeElement(noncurrentVersionTransitionWrapper(n), start) 113 } 114 115 // UnmarshalXML decodes NoncurrentVersionExpiration 116 func (n *NoncurrentVersionTransition) UnmarshalXML(d *xml.Decoder, startElement xml.StartElement) error { 117 type noncurrentVersionTransitionWrapper NoncurrentVersionTransition 118 var val noncurrentVersionTransitionWrapper 119 err := d.DecodeElement(&val, &startElement) 120 if err != nil { 121 return err 122 } 123 *n = NoncurrentVersionTransition(val) 124 n.set = true 125 return nil 126 } 127 128 // IsNull returns true if NoncurrentTransition doesn't refer to any storage-class. 129 // Note: It supports immediate transition, i.e zero noncurrent days. 130 func (n NoncurrentVersionTransition) IsNull() bool { 131 return n.StorageClass == "" 132 } 133 134 // Validate returns an error with wrong value 135 func (n NoncurrentVersionTransition) Validate() error { 136 if !n.set { 137 return nil 138 } 139 if n.StorageClass == "" { 140 return errXMLNotWellFormed 141 } 142 return nil 143 } 144 145 // NextDue returns upcoming NoncurrentVersionTransition date for obj if 146 // applicable, returns false otherwise. 147 func (n NoncurrentVersionTransition) NextDue(obj ObjectOpts) (time.Time, bool) { 148 if obj.IsLatest || n.StorageClass == "" { 149 return time.Time{}, false 150 } 151 // Days == 0 indicates immediate tiering, i.e object is eligible for tiering since it became noncurrent. 152 if n.NoncurrentDays == 0 { 153 return obj.SuccessorModTime, true 154 } 155 return ExpectedExpiryTime(obj.SuccessorModTime, int(n.NoncurrentDays)), true 156 }