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  }