New admin API endpoint: UpdateBucket, that unifies website config and quotas
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing

This commit is contained in:
Alex 2022-06-10 10:52:12 +02:00
parent c6c4f007f0
commit ef7db797bd
Signed by: lx
GPG key ID: 0E496D15096376BE
4 changed files with 60 additions and 51 deletions

View file

@ -540,26 +540,37 @@ Deletes a storage bucket. A bucket cannot be deleted if it is not empty.
Warning: this will delete all aliases associated with the bucket! Warning: this will delete all aliases associated with the bucket!
#### PutBucketWebsite `PUT /v0/bucket/website?id=<bucket id>` #### UpdateBucket `PUT /v0/bucket?id=<bucket id>`
Sets the website configuration for a bucket (this also enables website access for this bucket). Updates configuration of the given bucket.
Request body format: Request body format:
```json ```json
{ {
"indexDocument": "index.html", "websiteAccess": {
"errorDocument": "404.html" "enabled": true,
"indexDocument": "index.html",
"errorDocument": "404.html"
},
"quotas": {
"maxSize": 19029801,
"maxObjects": null,
}
} }
``` ```
The field `errorDocument` is optional, if no error document is set a generic error message is displayed when errors happen. All fields (`websiteAccess` and `quotas`) are optionnal.
If they are present, the corresponding modifications are applied to the bucket, otherwise nothing is changed.
In `websiteAccess`: if `enabled` is `true`, `indexDocument` must be specified.
The field `errorDocument` is optional, if no error document is set a generic
error message is displayed when errors happen. Conversely, if `enabled` is
`false`, neither `indexDocument` nor `errorDocument` must be specified.
#### DeleteBucketWebsite `DELETE /v0/bucket/website?id=<bucket id>` In `quotas`: new values of `maxSize` and `maxObjects` must both be specified, or set to `null`
to remove the quotas. An absent value will be considered the same as a `null`. It is not possible
Deletes the website configuration for a bucket (disables website access for this bucket). to change only one of the two quotas.
### Operations on permissions for keys on buckets ### Operations on permissions for keys on buckets

View file

@ -156,12 +156,7 @@ impl ApiHandler for AdminApiServer {
} }
Endpoint::CreateBucket => handle_create_bucket(&self.garage, req).await, Endpoint::CreateBucket => handle_create_bucket(&self.garage, req).await,
Endpoint::DeleteBucket { id } => handle_delete_bucket(&self.garage, id).await, Endpoint::DeleteBucket { id } => handle_delete_bucket(&self.garage, id).await,
Endpoint::PutBucketWebsite { id } => { Endpoint::UpdateBucket { id } => handle_update_bucket(&self.garage, id, req).await,
handle_put_bucket_website(&self.garage, id, req).await
}
Endpoint::DeleteBucketWebsite { id } => {
handle_delete_bucket_website(&self.garage, id).await
}
// Bucket-key permissions // Bucket-key permissions
Endpoint::BucketAllowKey => { Endpoint::BucketAllowKey => {
handle_bucket_change_key_perm(&self.garage, req, true).await handle_bucket_change_key_perm(&self.garage, req, true).await

View file

@ -102,7 +102,7 @@ struct BucketLocalAlias {
alias: String, alias: String,
} }
#[derive(Serialize)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct ApiBucketQuotas { struct ApiBucketQuotas {
max_size: Option<u64>, max_size: Option<u64>,
@ -418,14 +418,12 @@ pub async fn handle_delete_bucket(
.body(Body::empty())?) .body(Body::empty())?)
} }
// ---- BUCKET WEBSITE CONFIGURATION ---- pub async fn handle_update_bucket(
pub async fn handle_put_bucket_website(
garage: &Arc<Garage>, garage: &Arc<Garage>,
id: String, id: String,
req: Request<Body>, req: Request<Body>,
) -> Result<Response<Body>, Error> { ) -> Result<Response<Body>, Error> {
let req = parse_json_body::<PutBucketWebsiteRequest>(req).await?; let req = parse_json_body::<UpdateBucketRequest>(req).await?;
let bucket_id = parse_bucket_id(&id)?; let bucket_id = parse_bucket_id(&id)?;
let mut bucket = garage let mut bucket = garage
@ -434,10 +432,31 @@ pub async fn handle_put_bucket_website(
.await?; .await?;
let state = bucket.state.as_option_mut().unwrap(); let state = bucket.state.as_option_mut().unwrap();
state.website_config.update(Some(WebsiteConfig {
index_document: req.index_document, if let Some(wa) = req.website_access {
error_document: req.error_document, if wa.enabled {
})); state.website_config.update(Some(WebsiteConfig {
index_document: wa.index_document.ok_or_bad_request(
"Please specify indexDocument when enabling website access.",
)?,
error_document: wa.error_document,
}));
} else {
if wa.index_document.is_some() || wa.error_document.is_some() {
return Err(Error::bad_request(
"Cannot specify indexDocument or errorDocument when disabling website access.",
));
}
state.website_config.update(None);
}
}
if let Some(q) = req.quotas {
state.quotas.update(BucketQuotas {
max_size: q.max_size,
max_objects: q.max_objects,
});
}
garage.bucket_table.insert(&bucket).await?; garage.bucket_table.insert(&bucket).await?;
@ -446,29 +465,17 @@ pub async fn handle_put_bucket_website(
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct PutBucketWebsiteRequest { struct UpdateBucketRequest {
index_document: String, website_access: Option<UpdateBucketWebsiteAccess>,
#[serde(default)] quotas: Option<ApiBucketQuotas>,
error_document: Option<String>,
} }
pub async fn handle_delete_bucket_website( #[derive(Deserialize)]
garage: &Arc<Garage>, #[serde(rename_all = "camelCase")]
id: String, struct UpdateBucketWebsiteAccess {
) -> Result<Response<Body>, Error> { enabled: bool,
let bucket_id = parse_bucket_id(&id)?; index_document: Option<String>,
error_document: Option<String>,
let mut bucket = garage
.bucket_helper()
.get_existing_bucket(bucket_id)
.await?;
let state = bucket.state.as_option_mut().unwrap();
state.website_config.update(None);
garage.bucket_table.insert(&bucket).await?;
bucket_info_results(garage, bucket_id).await
} }
// ---- BUCKET/KEY PERMISSIONS ---- // ---- BUCKET/KEY PERMISSIONS ----

View file

@ -48,10 +48,7 @@ pub enum Endpoint {
DeleteBucket { DeleteBucket {
id: String, id: String,
}, },
PutBucketWebsite { UpdateBucket {
id: String,
},
DeleteBucketWebsite {
id: String, id: String,
}, },
// Bucket-Key Permissions // Bucket-Key Permissions
@ -113,8 +110,7 @@ impl Endpoint {
GET "/v0/bucket" => ListBuckets, GET "/v0/bucket" => ListBuckets,
POST "/v0/bucket" => CreateBucket, POST "/v0/bucket" => CreateBucket,
DELETE "/v0/bucket" if id => DeleteBucket (query::id), DELETE "/v0/bucket" if id => DeleteBucket (query::id),
PUT "/v0/bucket/website" if id => PutBucketWebsite (query::id), PUT "/v0/bucket" if id => UpdateBucket (query::id),
DELETE "/v0/bucket/website" if id => DeleteBucketWebsite (query::id),
// Bucket-key permissions // Bucket-key permissions
POST "/v0/bucket/allow" => BucketAllowKey, POST "/v0/bucket/allow" => BucketAllowKey,
POST "/v0/bucket/deny" => BucketDenyKey, POST "/v0/bucket/deny" => BucketDenyKey,