/* * MinIO Cloud Storage, (C) 2019 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package lifecycle import ( "bytes" "encoding/xml" "github.com/google/uuid" ) // Status represents lifecycle configuration status type Status string // Supported status types const ( Enabled Status = "Enabled" Disabled Status = "Disabled" ) // Rule - a rule for lifecycle configuration. type Rule struct { XMLName xml.Name `xml:"Rule"` ID string `xml:"ID,omitempty"` Status Status `xml:"Status"` Filter Filter `xml:"Filter,omitempty"` Prefix Prefix `xml:"Prefix,omitempty"` Expiration Expiration `xml:"Expiration,omitempty"` Transition Transition `xml:"Transition,omitempty"` // FIXME: add a type to catch unsupported AbortIncompleteMultipartUpload AbortIncompleteMultipartUpload `xml:"AbortIncompleteMultipartUpload,omitempty"` NoncurrentVersionExpiration NoncurrentVersionExpiration `xml:"NoncurrentVersionExpiration,omitempty"` NoncurrentVersionTransition NoncurrentVersionTransition `xml:"NoncurrentVersionTransition,omitempty"` } var ( errInvalidRuleID = Errorf("ID length is limited to 255 characters") errEmptyRuleStatus = Errorf("Status should not be empty") errInvalidRuleStatus = Errorf("Status must be set to either Enabled or Disabled") ) // generates random UUID func getNewUUID() (string, error) { u, err := uuid.NewRandom() if err != nil { return "", err } return u.String(), nil } // validateID - checks if ID is valid or not. func (r Rule) validateID() error { IDLen := len(string(r.ID)) // generate new ID when not provided // cannot be longer than 255 characters if IDLen == 0 { if newID, err := getNewUUID(); err == nil { r.ID = newID } else { return err } } else if IDLen > 255 { return errInvalidRuleID } return nil } // validateStatus - checks if status is valid or not. func (r Rule) validateStatus() error { // Status can't be empty if len(r.Status) == 0 { return errEmptyRuleStatus } // Status must be one of Enabled or Disabled if r.Status != Enabled && r.Status != Disabled { return errInvalidRuleStatus } return nil } func (r Rule) validateExpiration() error { return r.Expiration.Validate() } func (r Rule) validateNoncurrentExpiration() error { return r.NoncurrentVersionExpiration.Validate() } func (r Rule) validatePrefixAndFilter() error { if !r.Prefix.set && r.Filter.IsEmpty() || r.Prefix.set && !r.Filter.IsEmpty() { return errXMLNotWellFormed } if !r.Prefix.set { return r.Filter.Validate() } return nil } func (r Rule) validateTransition() error { return r.Transition.Validate() } func (r Rule) validateNoncurrentTransition() error { return r.NoncurrentVersionTransition.Validate() } // GetPrefix - a rule can either have prefix under , // or under . This method returns the prefix from the // location where it is available. func (r Rule) GetPrefix() string { if p := r.Prefix.String(); p != "" { return p } if p := r.Filter.Prefix.String(); p != "" { return p } if p := r.Filter.And.Prefix.String(); p != "" { return p } return "" } // Tags - a rule can either have tag under or under // . This method returns all the tags from the // rule in the format tag1=value1&tag2=value2 func (r Rule) Tags() string { if !r.Filter.Tag.IsEmpty() { return r.Filter.Tag.String() } if len(r.Filter.And.Tags) != 0 { var buf bytes.Buffer for _, t := range r.Filter.And.Tags { if buf.Len() > 0 { buf.WriteString("&") } buf.WriteString(t.String()) } return buf.String() } return "" } // Validate - validates the rule element func (r Rule) Validate() error { if err := r.validateID(); err != nil { return err } if err := r.validateStatus(); err != nil { return err } if err := r.validateExpiration(); err != nil { return err } if err := r.validateNoncurrentExpiration(); err != nil { return err } if err := r.validatePrefixAndFilter(); err != nil { return err } if err := r.validateTransition(); err != nil { return err } if err := r.validateNoncurrentTransition(); err != nil { return err } if !r.Expiration.set && !r.Transition.set && !r.NoncurrentVersionExpiration.set && !r.NoncurrentVersionTransition.set { return errXMLNotWellFormed } return nil }