storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/replication/destination.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  	"encoding/xml"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"storj.io/minio/pkg/wildcard"
    25  )
    26  
    27  // DestinationARNPrefix - destination ARN prefix as per AWS S3 specification.
    28  const DestinationARNPrefix = "arn:aws:s3:::"
    29  
    30  // Destination - destination in ReplicationConfiguration.
    31  type Destination struct {
    32  	XMLName      xml.Name `xml:"Destination" json:"Destination"`
    33  	Bucket       string   `xml:"Bucket" json:"Bucket"`
    34  	StorageClass string   `xml:"StorageClass" json:"StorageClass"`
    35  	//EncryptionConfiguration TODO: not needed for MinIO
    36  }
    37  
    38  func (d Destination) isValidStorageClass() bool {
    39  	if d.StorageClass == "" {
    40  		return true
    41  	}
    42  	return d.StorageClass == "STANDARD" || d.StorageClass == "REDUCED_REDUNDANCY"
    43  }
    44  
    45  // IsValid - checks whether Destination is valid or not.
    46  func (d Destination) IsValid() bool {
    47  	return d.Bucket != "" || !d.isValidStorageClass()
    48  }
    49  
    50  func (d Destination) String() string {
    51  	return DestinationARNPrefix + d.Bucket
    52  }
    53  
    54  // MarshalXML - encodes to XML data.
    55  func (d Destination) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    56  	if err := e.EncodeToken(start); err != nil {
    57  		return err
    58  	}
    59  	if err := e.EncodeElement(d.String(), xml.StartElement{Name: xml.Name{Local: "Bucket"}}); err != nil {
    60  		return err
    61  	}
    62  	if d.StorageClass != "" {
    63  		if err := e.EncodeElement(d.StorageClass, xml.StartElement{Name: xml.Name{Local: "StorageClass"}}); err != nil {
    64  			return err
    65  		}
    66  	}
    67  	return e.EncodeToken(xml.EndElement{Name: start.Name})
    68  }
    69  
    70  // UnmarshalXML - decodes XML data.
    71  func (d *Destination) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) (err error) {
    72  	// Make subtype to avoid recursive UnmarshalXML().
    73  	type destination Destination
    74  	dest := destination{}
    75  
    76  	if err := dec.DecodeElement(&dest, &start); err != nil {
    77  		return err
    78  	}
    79  	parsedDest, err := parseDestination(dest.Bucket)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	if dest.StorageClass != "" {
    84  		switch dest.StorageClass {
    85  		case "STANDARD", "REDUCED_REDUNDANCY":
    86  		default:
    87  			return fmt.Errorf("unknown storage class %s", dest.StorageClass)
    88  		}
    89  	}
    90  	parsedDest.StorageClass = dest.StorageClass
    91  	*d = parsedDest
    92  	return nil
    93  }
    94  
    95  // Validate - validates Resource is for given bucket or not.
    96  func (d Destination) Validate(bucketName string) error {
    97  	if !d.IsValid() {
    98  		return Errorf("invalid destination")
    99  	}
   100  
   101  	if !wildcard.Match(d.Bucket, bucketName) {
   102  		return Errorf("bucket name does not match")
   103  	}
   104  	return nil
   105  }
   106  
   107  // parseDestination - parses string to Destination.
   108  func parseDestination(s string) (Destination, error) {
   109  	if !strings.HasPrefix(s, DestinationARNPrefix) {
   110  		return Destination{}, Errorf("invalid destination '%s'", s)
   111  	}
   112  
   113  	bucketName := strings.TrimPrefix(s, DestinationARNPrefix)
   114  
   115  	return Destination{
   116  		Bucket: bucketName,
   117  	}, nil
   118  }