diff options
Diffstat (limited to 'src/model/helper')
-rw-r--r-- | src/model/helper/bucket.rs | 56 | ||||
-rw-r--r-- | src/model/helper/error.rs | 51 | ||||
-rw-r--r-- | src/model/helper/mod.rs | 2 |
3 files changed, 109 insertions, 0 deletions
diff --git a/src/model/helper/bucket.rs b/src/model/helper/bucket.rs new file mode 100644 index 00000000..e89a723d --- /dev/null +++ b/src/model/helper/bucket.rs @@ -0,0 +1,56 @@ +use garage_table::util::EmptyKey; +use garage_util::data::*; + +use crate::bucket_table::Bucket; +use crate::garage::Garage; +use crate::helper::error::*; + +pub struct BucketHelper<'a>(pub(crate) &'a Garage); + +impl<'a> BucketHelper<'a> { + #[allow(clippy::ptr_arg)] + pub async fn resolve_global_bucket_name( + &self, + bucket_name: &String, + ) -> Result<Option<Uuid>, Error> { + // Bucket names in Garage are aliases, true bucket identifiers + // are 32-byte UUIDs. This function resolves bucket names into + // their full identifier by looking up in the bucket_alias_table. + // This function also allows buckets to be identified by their + // full UUID (hex-encoded). Here, if the name to be resolved is a + // hex string of the correct length, it is directly parsed as a bucket + // identifier which is returned. There is no risk of this conflicting + // with an actual bucket name: bucket names are max 63 chars long by + // the AWS spec, and hex-encoded UUIDs are 64 chars long. + let hexbucket = hex::decode(bucket_name.as_str()) + .ok() + .map(|by| Uuid::try_from(&by)) + .flatten(); + if let Some(bucket_id) = hexbucket { + Ok(self + .0 + .bucket_table + .get(&bucket_id, &EmptyKey) + .await? + .filter(|x| !x.state.is_deleted()) + .map(|_| bucket_id)) + } else { + Ok(self + .0 + .bucket_alias_table + .get(&EmptyKey, bucket_name) + .await? + .map(|x| x.state.get().as_option().map(|x| x.bucket_id)) + .flatten()) + } + } + + pub async fn get_existing_bucket(&self, bucket_id: Uuid) -> Result<Bucket, Error> { + self.0 + .bucket_table + .get(&bucket_id, &EmptyKey) + .await? + .filter(|b| !b.is_deleted()) + .ok_or_bad_request(format!("Bucket {:?} does not exist", bucket_id)) + } +} diff --git a/src/model/helper/error.rs b/src/model/helper/error.rs new file mode 100644 index 00000000..b9b515f3 --- /dev/null +++ b/src/model/helper/error.rs @@ -0,0 +1,51 @@ +use err_derive::Error; +use serde::{Deserialize, Serialize}; + +use garage_util::error::Error as GarageError; + +#[derive(Debug, Error, Serialize, Deserialize)] +pub enum Error { + #[error(display = "Internal error: {}", _0)] + Internal(#[error(source)] GarageError), + + #[error(display = "Bad request: {}", _0)] + BadRequest(String), +} + +impl From<netapp::error::Error> for Error { + fn from(e: netapp::error::Error) -> Self { + Error::Internal(GarageError::Netapp(e)) + } +} + +pub trait OkOrBadRequest { + type S; + fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<Self::S, Error>; +} + +impl<T, E> OkOrBadRequest for Result<T, E> +where + E: std::fmt::Display, +{ + type S = T; + fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<T, Error> { + match self { + Ok(x) => Ok(x), + Err(e) => Err(Error::BadRequest(format!( + "{}: {}", + reason.as_ref(), + e.to_string() + ))), + } + } +} + +impl<T> OkOrBadRequest for Option<T> { + type S = T; + fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<T, Error> { + match self { + Some(x) => Ok(x), + None => Err(Error::BadRequest(reason.as_ref().to_string())), + } + } +} diff --git a/src/model/helper/mod.rs b/src/model/helper/mod.rs new file mode 100644 index 00000000..2f4e8898 --- /dev/null +++ b/src/model/helper/mod.rs @@ -0,0 +1,2 @@ +pub mod bucket; +pub mod error; |