storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/replication/rule.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2020 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package replication 18 19 import ( 20 "bytes" 21 "encoding/xml" 22 ) 23 24 // Status represents Enabled/Disabled status 25 type Status string 26 27 // Supported status types 28 const ( 29 Enabled Status = "Enabled" 30 Disabled Status = "Disabled" 31 ) 32 33 // DeleteMarkerReplication - whether delete markers are replicated - https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-add-config.html 34 type DeleteMarkerReplication struct { 35 Status Status `xml:"Status"` // should be set to "Disabled" by default 36 } 37 38 // IsEmpty returns true if DeleteMarkerReplication is not set 39 func (d DeleteMarkerReplication) IsEmpty() bool { 40 return len(d.Status) == 0 41 } 42 43 // Validate validates whether the status is disabled. 44 func (d DeleteMarkerReplication) Validate() error { 45 if d.IsEmpty() { 46 return errDeleteMarkerReplicationMissing 47 } 48 if d.Status != Disabled && d.Status != Enabled { 49 return errInvalidDeleteMarkerReplicationStatus 50 } 51 return nil 52 } 53 54 // DeleteReplication - whether versioned deletes are replicated - this is a MinIO only 55 // extension. 56 type DeleteReplication struct { 57 Status Status `xml:"Status"` // should be set to "Disabled" by default 58 } 59 60 // IsEmpty returns true if DeleteReplication is not set 61 func (d DeleteReplication) IsEmpty() bool { 62 return len(d.Status) == 0 63 } 64 65 // Validate validates whether the status is disabled. 66 func (d DeleteReplication) Validate() error { 67 if d.IsEmpty() { 68 return errDeleteReplicationMissing 69 } 70 if d.Status != Disabled && d.Status != Enabled { 71 return errInvalidDeleteReplicationStatus 72 } 73 return nil 74 } 75 76 // UnmarshalXML - decodes XML data. 77 func (d *DeleteReplication) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) (err error) { 78 // Make subtype to avoid recursive UnmarshalXML(). 79 type deleteReplication DeleteReplication 80 drep := deleteReplication{} 81 82 if err := dec.DecodeElement(&drep, &start); err != nil { 83 return err 84 } 85 if len(drep.Status) == 0 { 86 drep.Status = Disabled 87 } 88 d.Status = drep.Status 89 return nil 90 } 91 92 // Rule - a rule for replication configuration. 93 type Rule struct { 94 XMLName xml.Name `xml:"Rule" json:"Rule"` 95 ID string `xml:"ID,omitempty" json:"ID,omitempty"` 96 Status Status `xml:"Status" json:"Status"` 97 Priority int `xml:"Priority" json:"Priority"` 98 DeleteMarkerReplication DeleteMarkerReplication `xml:"DeleteMarkerReplication" json:"DeleteMarkerReplication"` 99 // MinIO extension to replicate versioned deletes 100 DeleteReplication DeleteReplication `xml:"DeleteReplication" json:"DeleteReplication"` 101 Destination Destination `xml:"Destination" json:"Destination"` 102 Filter Filter `xml:"Filter" json:"Filter"` 103 } 104 105 var ( 106 errInvalidRuleID = Errorf("ID must be less than 255 characters") 107 errEmptyRuleStatus = Errorf("Status should not be empty") 108 errInvalidRuleStatus = Errorf("Status must be set to either Enabled or Disabled") 109 errDeleteMarkerReplicationMissing = Errorf("DeleteMarkerReplication must be specified") 110 errPriorityMissing = Errorf("Priority must be specified") 111 errInvalidDeleteMarkerReplicationStatus = Errorf("Delete marker replication status is invalid") 112 errDestinationSourceIdentical = Errorf("Destination bucket cannot be the same as the source bucket.") 113 errDeleteReplicationMissing = Errorf("Delete replication must be specified") 114 errInvalidDeleteReplicationStatus = Errorf("Delete replication is either enable|disable") 115 ) 116 117 // validateID - checks if ID is valid or not. 118 func (r Rule) validateID() error { 119 // cannot be longer than 255 characters 120 if len(r.ID) > 255 { 121 return errInvalidRuleID 122 } 123 return nil 124 } 125 126 // validateStatus - checks if status is valid or not. 127 func (r Rule) validateStatus() error { 128 // Status can't be empty 129 if len(r.Status) == 0 { 130 return errEmptyRuleStatus 131 } 132 133 // Status must be one of Enabled or Disabled 134 if r.Status != Enabled && r.Status != Disabled { 135 return errInvalidRuleStatus 136 } 137 return nil 138 } 139 140 func (r Rule) validateFilter() error { 141 if err := r.Filter.Validate(); err != nil { 142 return err 143 } 144 return nil 145 } 146 147 // Prefix - a rule can either have prefix under <filter></filter> or under 148 // <filter><and></and></filter>. This method returns the prefix from the 149 // location where it is available 150 func (r Rule) Prefix() string { 151 if r.Filter.Prefix != "" { 152 return r.Filter.Prefix 153 } 154 return r.Filter.And.Prefix 155 } 156 157 // Tags - a rule can either have tag under <filter></filter> or under 158 // <filter><and></and></filter>. This method returns all the tags from the 159 // rule in the format tag1=value1&tag2=value2 160 func (r Rule) Tags() string { 161 if !r.Filter.Tag.IsEmpty() { 162 return r.Filter.Tag.String() 163 } 164 if len(r.Filter.And.Tags) != 0 { 165 var buf bytes.Buffer 166 for _, t := range r.Filter.And.Tags { 167 if buf.Len() > 0 { 168 buf.WriteString("&") 169 } 170 buf.WriteString(t.String()) 171 } 172 return buf.String() 173 } 174 return "" 175 } 176 177 // Validate - validates the rule element 178 func (r Rule) Validate(bucket string, sameTarget bool) error { 179 if err := r.validateID(); err != nil { 180 return err 181 } 182 if err := r.validateStatus(); err != nil { 183 return err 184 } 185 if err := r.validateFilter(); err != nil { 186 return err 187 } 188 if err := r.DeleteMarkerReplication.Validate(); err != nil { 189 return err 190 } 191 if err := r.DeleteReplication.Validate(); err != nil { 192 return err 193 } 194 if r.Priority < 0 { 195 return errPriorityMissing 196 } 197 if r.Destination.Bucket == bucket && sameTarget { 198 return errDestinationSourceIdentical 199 } 200 return nil 201 }