github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/bucket/lifecycle/rule.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  	"bytes"
    22  	"encoding/xml"
    23  )
    24  
    25  // Status represents lifecycle configuration status
    26  type Status string
    27  
    28  // Supported status types
    29  const (
    30  	Enabled  Status = "Enabled"
    31  	Disabled Status = "Disabled"
    32  )
    33  
    34  // Rule - a rule for lifecycle configuration.
    35  type Rule struct {
    36  	XMLName    xml.Name   `xml:"Rule"`
    37  	ID         string     `xml:"ID,omitempty"`
    38  	Status     Status     `xml:"Status"`
    39  	Filter     Filter     `xml:"Filter,omitempty"`
    40  	Prefix     Prefix     `xml:"Prefix,omitempty"`
    41  	Expiration Expiration `xml:"Expiration,omitempty"`
    42  	Transition Transition `xml:"Transition,omitempty"`
    43  	// FIXME: add a type to catch unsupported AbortIncompleteMultipartUpload AbortIncompleteMultipartUpload `xml:"AbortIncompleteMultipartUpload,omitempty"`
    44  	NoncurrentVersionExpiration NoncurrentVersionExpiration `xml:"NoncurrentVersionExpiration,omitempty"`
    45  	NoncurrentVersionTransition NoncurrentVersionTransition `xml:"NoncurrentVersionTransition,omitempty"`
    46  }
    47  
    48  var (
    49  	errInvalidRuleID     = Errorf("ID length is limited to 255 characters")
    50  	errEmptyRuleStatus   = Errorf("Status should not be empty")
    51  	errInvalidRuleStatus = Errorf("Status must be set to either Enabled or Disabled")
    52  )
    53  
    54  // validateID - checks if ID is valid or not.
    55  func (r Rule) validateID() error {
    56  	if len(r.ID) > 255 {
    57  		return errInvalidRuleID
    58  	}
    59  	return nil
    60  }
    61  
    62  // validateStatus - checks if status is valid or not.
    63  func (r Rule) validateStatus() error {
    64  	// Status can't be empty
    65  	if len(r.Status) == 0 {
    66  		return errEmptyRuleStatus
    67  	}
    68  
    69  	// Status must be one of Enabled or Disabled
    70  	if r.Status != Enabled && r.Status != Disabled {
    71  		return errInvalidRuleStatus
    72  	}
    73  	return nil
    74  }
    75  
    76  func (r Rule) validateExpiration() error {
    77  	return r.Expiration.Validate()
    78  }
    79  
    80  func (r Rule) validateNoncurrentExpiration() error {
    81  	return r.NoncurrentVersionExpiration.Validate()
    82  }
    83  
    84  func (r Rule) validatePrefixAndFilter() error {
    85  	if !r.Prefix.set && r.Filter.IsEmpty() || r.Prefix.set && !r.Filter.IsEmpty() {
    86  		return errXMLNotWellFormed
    87  	}
    88  	if !r.Prefix.set {
    89  		return r.Filter.Validate()
    90  	}
    91  	return nil
    92  }
    93  
    94  func (r Rule) validateTransition() error {
    95  	return r.Transition.Validate()
    96  }
    97  
    98  func (r Rule) validateNoncurrentTransition() error {
    99  	return r.NoncurrentVersionTransition.Validate()
   100  }
   101  
   102  // GetPrefix - a rule can either have prefix under <rule></rule>, <filter></filter>
   103  // or under <filter><and></and></filter>. This method returns the prefix from the
   104  // location where it is available.
   105  func (r Rule) GetPrefix() string {
   106  	if p := r.Prefix.String(); p != "" {
   107  		return p
   108  	}
   109  	if p := r.Filter.Prefix.String(); p != "" {
   110  		return p
   111  	}
   112  	if p := r.Filter.And.Prefix.String(); p != "" {
   113  		return p
   114  	}
   115  	return ""
   116  }
   117  
   118  // Tags - a rule can either have tag under <filter></filter> or under
   119  // <filter><and></and></filter>. This method returns all the tags from the
   120  // rule in the format tag1=value1&tag2=value2
   121  func (r Rule) Tags() string {
   122  	if !r.Filter.Tag.IsEmpty() {
   123  		return r.Filter.Tag.String()
   124  	}
   125  	if len(r.Filter.And.Tags) != 0 {
   126  		var buf bytes.Buffer
   127  		for _, t := range r.Filter.And.Tags {
   128  			if buf.Len() > 0 {
   129  				buf.WriteString("&")
   130  			}
   131  			buf.WriteString(t.String())
   132  		}
   133  		return buf.String()
   134  	}
   135  	return ""
   136  }
   137  
   138  // Validate - validates the rule element
   139  func (r Rule) Validate() error {
   140  	if err := r.validateID(); err != nil {
   141  		return err
   142  	}
   143  	if err := r.validateStatus(); err != nil {
   144  		return err
   145  	}
   146  	if err := r.validateExpiration(); err != nil {
   147  		return err
   148  	}
   149  	if err := r.validateNoncurrentExpiration(); err != nil {
   150  		return err
   151  	}
   152  	if err := r.validatePrefixAndFilter(); err != nil {
   153  		return err
   154  	}
   155  	if err := r.validateTransition(); err != nil {
   156  		return err
   157  	}
   158  	if err := r.validateNoncurrentTransition(); err != nil {
   159  		return err
   160  	}
   161  	if !r.Expiration.set && !r.Transition.set && !r.NoncurrentVersionExpiration.set && !r.NoncurrentVersionTransition.set {
   162  		return errXMLNotWellFormed
   163  	}
   164  	return nil
   165  }
   166  
   167  // CloneNonTransition - returns a clone of the object containing non transition rules
   168  func (r Rule) CloneNonTransition() Rule {
   169  	return Rule{
   170  		XMLName:                     r.XMLName,
   171  		ID:                          r.ID,
   172  		Status:                      r.Status,
   173  		Filter:                      r.Filter,
   174  		Prefix:                      r.Prefix,
   175  		Expiration:                  r.Expiration,
   176  		NoncurrentVersionExpiration: r.NoncurrentVersionExpiration,
   177  	}
   178  }