2021-12-14 12:55:11 +00:00
use serde ::{ Deserialize , Serialize } ;
2021-12-22 17:50:08 +00:00
use garage_util ::data ::* ;
2021-12-14 12:55:11 +00:00
use garage_table ::crdt ::* ;
use garage_table ::* ;
/// The bucket alias table holds the names given to buckets
/// in the global namespace.
#[ derive(PartialEq, Clone, Debug, Serialize, Deserialize) ]
pub struct BucketAlias {
2021-12-17 10:53:13 +00:00
name : String ,
2021-12-14 12:55:11 +00:00
pub state : crdt ::Lww < crdt ::Deletable < AliasParams > > ,
}
#[ derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize) ]
pub struct AliasParams {
pub bucket_id : Uuid ,
}
impl AutoCrdt for AliasParams {
const WARN_IF_DIFFERENT : bool = true ;
}
impl BucketAlias {
2022-01-03 16:22:40 +00:00
pub fn new ( name : String , ts : u64 , bucket_id : Uuid ) -> Option < Self > {
2021-12-17 10:53:13 +00:00
if ! is_valid_bucket_name ( & name ) {
None
} else {
Some ( BucketAlias {
name ,
2021-12-22 17:50:08 +00:00
state : crdt ::Lww ::raw ( ts , crdt ::Deletable ::present ( AliasParams { bucket_id } ) ) ,
2021-12-17 10:53:13 +00:00
} )
2021-12-14 12:55:11 +00:00
}
}
2021-12-22 17:50:08 +00:00
2021-12-14 12:55:11 +00:00
pub fn is_deleted ( & self ) -> bool {
self . state . get ( ) . is_deleted ( )
}
2021-12-17 10:53:13 +00:00
pub fn name ( & self ) -> & str {
& self . name
}
2021-12-14 12:55:11 +00:00
}
impl Crdt for BucketAlias {
fn merge ( & mut self , o : & Self ) {
self . state . merge ( & o . state ) ;
}
}
impl Entry < EmptyKey , String > for BucketAlias {
fn partition_key ( & self ) -> & EmptyKey {
& EmptyKey
}
fn sort_key ( & self ) -> & String {
& self . name
}
}
pub struct BucketAliasTable ;
impl TableSchema for BucketAliasTable {
const TABLE_NAME : & 'static str = " bucket_alias " ;
type P = EmptyKey ;
type S = String ;
type E = BucketAlias ;
type Filter = DeletedFilter ;
fn matches_filter ( entry : & Self ::E , filter : & Self ::Filter ) -> bool {
filter . apply ( entry . is_deleted ( ) )
}
}
2021-12-17 10:53:13 +00:00
/// Check if a bucket name is valid.
///
/// The requirements are listed here:
///
/// <https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html>
///
/// In the case of Garage, bucket names must not be hex-encoded
/// 32 byte string, which is excluded thanks to the
/// maximum length of 63 bytes given in the spec.
pub fn is_valid_bucket_name ( n : & str ) -> bool {
// Bucket names must be between 3 and 63 characters
n . len ( ) > = 3 & & n . len ( ) < = 63
// Bucket names must be composed of lowercase letters, numbers,
// dashes and dots
& & n . chars ( ) . all ( | c | matches! ( c , '.' | '-' | 'a' ..= 'z' | '0' ..= '9' ) )
// Bucket names must start and end with a letter or a number
& & ! n . starts_with ( & [ '-' , '.' ] [ .. ] )
& & ! n . ends_with ( & [ '-' , '.' ] [ .. ] )
// Bucket names must not be formated as an IP address
& & n . parse ::< std ::net ::IpAddr > ( ) . is_err ( )
// Bucket names must not start wih "xn--"
& & ! n . starts_with ( " xn-- " )
// Bucket names must not end with "-s3alias"
& & ! n . ends_with ( " -s3alias " )
}
2022-01-03 16:22:40 +00:00
/// Error message to return for invalid bucket names
pub const INVALID_BUCKET_NAME_MESSAGE : & str = " Invalid bucket name. See AWS documentation for constraints on S3 bucket names: \n https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html " ;