aboutsummaryrefslogtreecommitdiff
path: root/src/api/s3
diff options
context:
space:
mode:
authorAlex <alex@adnab.me>2024-02-22 12:05:19 +0000
committerAlex <alex@adnab.me>2024-02-22 12:05:19 +0000
commit74d0c47f21ae2f9998a7dcbca3a27e3cc51e70b6 (patch)
treef7747f950672246c1ecc079e50222a07d23bc635 /src/api/s3
parent7e212e20e02b9cdced52ce23111214c6285a095a (diff)
parentcff702a951cb5bb193c7a891ababfd1d962ae9ed (diff)
downloadgarage-74d0c47f21ae2f9998a7dcbca3a27e3cc51e70b6.tar.gz
garage-74d0c47f21ae2f9998a7dcbca3a27e3cc51e70b6.zip
Merge pull request 'Add node-global lock for bucket/key operations (fix #723)' (#728) from lock-createbucket into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/728
Diffstat (limited to 'src/api/s3')
-rw-r--r--src/api/s3/api_server.rs11
-rw-r--r--src/api/s3/bucket.rs51
2 files changed, 31 insertions, 31 deletions
diff --git a/src/api/s3/api_server.rs b/src/api/s3/api_server.rs
index 7fac6261..08405923 100644
--- a/src/api/s3/api_server.rs
+++ b/src/api/s3/api_server.rs
@@ -148,7 +148,14 @@ impl ApiHandler for S3ApiServer {
// Special code path for CreateBucket API endpoint
if let Endpoint::CreateBucket {} = endpoint {
- return handle_create_bucket(&garage, req, content_sha256, api_key, bucket_name).await;
+ return handle_create_bucket(
+ &garage,
+ req,
+ content_sha256,
+ &api_key.key_id,
+ bucket_name,
+ )
+ .await;
}
let bucket_id = garage
@@ -261,7 +268,7 @@ impl ApiHandler for S3ApiServer {
Ok(response)
}
Endpoint::DeleteBucket {} => {
- handle_delete_bucket(&garage, bucket_id, bucket_name, api_key).await
+ handle_delete_bucket(&garage, bucket_id, bucket_name, &api_key.key_id).await
}
Endpoint::GetBucketLocation {} => handle_get_bucket_location(garage),
Endpoint::GetBucketVersioning {} => handle_get_bucket_versioning(),
diff --git a/src/api/s3/bucket.rs b/src/api/s3/bucket.rs
index fa2f1b6d..fa337566 100644
--- a/src/api/s3/bucket.rs
+++ b/src/api/s3/bucket.rs
@@ -122,7 +122,7 @@ pub async fn handle_create_bucket(
garage: &Garage,
req: Request<ReqBody>,
content_sha256: Option<Hash>,
- api_key: Key,
+ api_key_id: &String,
bucket_name: String,
) -> Result<Response<ResBody>, Error> {
let body = BodyExt::collect(req.into_body()).await?.to_bytes();
@@ -144,16 +144,18 @@ pub async fn handle_create_bucket(
}
}
- let key_params = api_key
- .params()
- .ok_or_internal_error("Key should not be deleted at this point")?;
+ let helper = garage.locked_helper().await;
+
+ // refetch API key after taking lock to ensure up-to-date data
+ let api_key = helper.key().get_existing_key(api_key_id).await?;
+ let key_params = api_key.params().unwrap();
let existing_bucket = if let Some(Some(bucket_id)) = key_params.local_aliases.get(&bucket_name)
{
Some(*bucket_id)
} else {
- garage
- .bucket_helper()
+ helper
+ .bucket()
.resolve_global_bucket_name(&bucket_name)
.await?
};
@@ -187,13 +189,11 @@ pub async fn handle_create_bucket(
let bucket = Bucket::new();
garage.bucket_table.insert(&bucket).await?;
- garage
- .bucket_helper()
+ helper
.set_bucket_key_permissions(bucket.id, &api_key.key_id, BucketKeyPerm::ALL_PERMISSIONS)
.await?;
- garage
- .bucket_helper()
+ helper
.set_local_bucket_alias(bucket.id, &api_key.key_id, &bucket_name)
.await?;
}
@@ -208,18 +208,16 @@ pub async fn handle_delete_bucket(
garage: &Garage,
bucket_id: Uuid,
bucket_name: String,
- api_key: Key,
+ api_key_id: &String,
) -> Result<Response<ResBody>, Error> {
- let key_params = api_key
- .params()
- .ok_or_internal_error("Key should not be deleted at this point")?;
+ let helper = garage.locked_helper().await;
+
+ let api_key = helper.key().get_existing_key(api_key_id).await?;
+ let key_params = api_key.params().unwrap();
let is_local_alias = matches!(key_params.local_aliases.get(&bucket_name), Some(Some(_)));
- let mut bucket = garage
- .bucket_helper()
- .get_existing_bucket(bucket_id)
- .await?;
+ let mut bucket = helper.bucket().get_existing_bucket(bucket_id).await?;
let bucket_state = bucket.state.as_option().unwrap();
// If the bucket has no other aliases, this is a true deletion.
@@ -243,28 +241,25 @@ pub async fn handle_delete_bucket(
// Delete bucket
// Check bucket is empty
- if !garage.bucket_helper().is_bucket_empty(bucket_id).await? {
+ if !helper.bucket().is_bucket_empty(bucket_id).await? {
return Err(CommonError::BucketNotEmpty.into());
}
// --- done checking, now commit ---
// 1. delete bucket alias
if is_local_alias {
- garage
- .bucket_helper()
+ helper
.unset_local_bucket_alias(bucket_id, &api_key.key_id, &bucket_name)
.await?;
} else {
- garage
- .bucket_helper()
+ helper
.unset_global_bucket_alias(bucket_id, &bucket_name)
.await?;
}
// 2. delete authorization from keys that had access
for (key_id, _) in bucket.authorized_keys() {
- garage
- .bucket_helper()
+ helper
.set_bucket_key_permissions(bucket.id, key_id, BucketKeyPerm::NO_PERMISSIONS)
.await?;
}
@@ -274,14 +269,12 @@ pub async fn handle_delete_bucket(
garage.bucket_table.insert(&bucket).await?;
} else if is_local_alias {
// Just unalias
- garage
- .bucket_helper()
+ helper
.unset_local_bucket_alias(bucket_id, &api_key.key_id, &bucket_name)
.await?;
} else {
// Just unalias (but from global namespace)
- garage
- .bucket_helper()
+ helper
.unset_global_bucket_alias(bucket_id, &bucket_name)
.await?;
}