improve internal item counter mechanisms and implement bucket quotas #326
4 changed files with 60 additions and 51 deletions
|
@ -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
|
||||||
{
|
{
|
||||||
|
"websiteAccess": {
|
||||||
|
"enabled": true,
|
||||||
"indexDocument": "index.html",
|
"indexDocument": "index.html",
|
||||||
"errorDocument": "404.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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
if let Some(wa) = req.website_access {
|
||||||
|
if wa.enabled {
|
||||||
state.website_config.update(Some(WebsiteConfig {
|
state.website_config.update(Some(WebsiteConfig {
|
||||||
index_document: req.index_document,
|
index_document: wa.index_document.ok_or_bad_request(
|
||||||
error_document: req.error_document,
|
"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 ----
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue