Implement base operator #1
@ -14,7 +14,7 @@ pub struct MinioInstanceSpec {
|
||||
pub credentials: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, Clone, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, Default, Copy, Clone, JsonSchema, PartialEq, Eq)]
|
||||
pub enum RetentionType {
|
||||
#[default]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
@ -23,7 +23,7 @@ pub enum RetentionType {
|
||||
Governance,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, Clone, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, Default, Clone, Copy, JsonSchema, PartialEq, Eq)]
|
||||
pub struct BucketRetention {
|
||||
pub validity: usize,
|
||||
pub r#type: RetentionType,
|
||||
|
240
src/minio.rs
240
src/minio.rs
@ -4,7 +4,7 @@ use serde::de::DeserializeOwned;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::constants::{MC_EXE, SECRET_MINIO_BUCKET_ACCESS_LEN, SECRET_MINIO_BUCKET_SECRET_LEN};
|
||||
use crate::crd::{MinioBucketSpec, RetentionType};
|
||||
use crate::crd::{BucketRetention, MinioBucketSpec, RetentionType};
|
||||
use crate::utils::rand_str;
|
||||
|
||||
const MC_ALIAS_NAME: &str = "managedminioinst";
|
||||
@ -84,6 +84,13 @@ struct MinioQuota {
|
||||
pub quota: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
struct MinioRetentionResult {
|
||||
pub enabled: Option<String>,
|
||||
pub mode: Option<String>,
|
||||
pub validity: Option<String>,
|
||||
}
|
||||
|
||||
impl BasicMinioResult {
|
||||
pub fn success(&self) -> bool {
|
||||
self.status == "success"
|
||||
@ -206,7 +213,7 @@ impl MinioService {
|
||||
let bucket_name = format!("{}/{}", MC_ALIAS_NAME, b.name);
|
||||
let mut args = ["mb", bucket_name.as_str()].to_vec();
|
||||
|
||||
if b.lock || b.retention.is_some() {
|
||||
if b.lock {
|
||||
args.push("--with-lock");
|
||||
}
|
||||
|
||||
@ -215,36 +222,15 @@ impl MinioService {
|
||||
return Err(MinioError::MakeBucketFailed.into());
|
||||
}
|
||||
|
||||
self.bucket_set_versioning(&b.name, b.versioning).await?;
|
||||
self.bucket_set_versioning(&b.name, b.versioning || b.lock)
|
||||
.await?;
|
||||
self.bucket_set_anonymous_access(&b.name, b.anonymous_read_access)
|
||||
.await?;
|
||||
|
||||
// Set quota, if requested
|
||||
self.bucket_set_quota(&b.name, b.quota).await?;
|
||||
|
||||
// Set retention, if requested
|
||||
if let Some(retention) = &b.retention {
|
||||
let days = format!("{}d", retention.validity);
|
||||
|
||||
let res = self
|
||||
.exec_mc_cmd::<BasicMinioResult>(&[
|
||||
"retention",
|
||||
"set",
|
||||
"--default",
|
||||
match retention.r#type {
|
||||
RetentionType::Compliance => "compliance",
|
||||
RetentionType::Governance => "governance",
|
||||
},
|
||||
days.as_str(),
|
||||
bucket_name.as_str(),
|
||||
])
|
||||
if b.lock {
|
||||
self.bucket_set_default_retention(&b.name, b.retention)
|
||||
.await?;
|
||||
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::SetRetentionFailed.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -353,11 +339,84 @@ impl MinioService {
|
||||
.remove(0)
|
||||
.quota)
|
||||
}
|
||||
|
||||
/// Set bucket default retention policy
|
||||
pub async fn bucket_set_default_retention(
|
||||
&self,
|
||||
bucket_name: &str,
|
||||
retention: Option<BucketRetention>,
|
||||
) -> anyhow::Result<()> {
|
||||
let bucket_name = self.absolute_bucket_name(bucket_name);
|
||||
let res = if let Some(retention) = &retention {
|
||||
let days = format!("{}d", retention.validity);
|
||||
|
||||
self.exec_mc_cmd::<BasicMinioResult>(&[
|
||||
"retention",
|
||||
"set",
|
||||
"--default",
|
||||
match retention.r#type {
|
||||
RetentionType::Compliance => "compliance",
|
||||
RetentionType::Governance => "governance",
|
||||
},
|
||||
days.as_str(),
|
||||
bucket_name.as_str(),
|
||||
])
|
||||
.await?
|
||||
} else {
|
||||
self.exec_mc_cmd::<BasicMinioResult>(&[
|
||||
"retention",
|
||||
"clear",
|
||||
"--default",
|
||||
bucket_name.as_str(),
|
||||
])
|
||||
.await?
|
||||
};
|
||||
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::SetRetentionFailed.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get bucket default retention policy
|
||||
pub async fn bucket_get_default_retention(
|
||||
&self,
|
||||
bucket: &str,
|
||||
) -> anyhow::Result<Option<BucketRetention>> {
|
||||
let bucket_name = self.absolute_bucket_name(bucket);
|
||||
let res = self
|
||||
.exec_mc_cmd::<MinioRetentionResult>(&[
|
||||
"retention",
|
||||
"info",
|
||||
bucket_name.as_str(),
|
||||
"--default",
|
||||
])
|
||||
.await?
|
||||
.remove(0);
|
||||
|
||||
if let (Some(mode), Some(validity), Some(enabled)) = (res.mode, res.validity, res.enabled) {
|
||||
if enabled.to_lowercase().eq("enabled") {
|
||||
return Ok(Some(BucketRetention {
|
||||
validity: validity.to_lowercase().replace("days", "").parse()?,
|
||||
r#type: match mode.to_lowercase().as_str() {
|
||||
"governance" => RetentionType::Governance,
|
||||
"compliance" => RetentionType::Compliance,
|
||||
o => {
|
||||
log::error!("Unknown retention type: {}", o);
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::crd::MinioBucketSpec;
|
||||
use crate::crd::{BucketRetention, MinioBucketSpec, RetentionType};
|
||||
use crate::minio_test_server::MinioTestServer;
|
||||
|
||||
const TEST_BUCKET_NAME: &str = "mybucket";
|
||||
@ -614,7 +673,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn bucket_without_qutoa() {
|
||||
async fn bucket_without_quota() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let srv = MinioTestServer::start().await.unwrap();
|
||||
@ -659,7 +718,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn bucket_with_qutoa() {
|
||||
async fn bucket_with_quota() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let srv = MinioTestServer::start().await.unwrap();
|
||||
@ -685,6 +744,123 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO : with retention
|
||||
// TODO : without retention
|
||||
#[tokio::test]
|
||||
async fn bucket_with_retention() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let srv = MinioTestServer::start().await.unwrap();
|
||||
let service = srv.as_service();
|
||||
service
|
||||
.create_bucket(&MinioBucketSpec {
|
||||
instance: "".to_string(),
|
||||
name: TEST_BUCKET_NAME.to_string(),
|
||||
secret: "".to_string(),
|
||||
anonymous_read_access: false,
|
||||
versioning: false,
|
||||
quota: Some(42300),
|
||||
lock: true,
|
||||
retention: Some(BucketRetention {
|
||||
validity: 10,
|
||||
r#type: RetentionType::Governance,
|
||||
}),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||
assert_eq!(
|
||||
service
|
||||
.bucket_get_default_retention(TEST_BUCKET_NAME)
|
||||
.await
|
||||
.unwrap(),
|
||||
Some(BucketRetention {
|
||||
validity: 10,
|
||||
r#type: RetentionType::Governance
|
||||
})
|
||||
);
|
||||
|
||||
service
|
||||
.bucket_set_default_retention(TEST_BUCKET_NAME, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
service
|
||||
.bucket_get_default_retention(TEST_BUCKET_NAME)
|
||||
.await
|
||||
.unwrap(),
|
||||
None
|
||||
);
|
||||
|
||||
service
|
||||
.bucket_set_default_retention(
|
||||
TEST_BUCKET_NAME,
|
||||
Some(BucketRetention {
|
||||
validity: 42,
|
||||
r#type: RetentionType::Compliance,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
service
|
||||
.bucket_get_default_retention(TEST_BUCKET_NAME)
|
||||
.await
|
||||
.unwrap(),
|
||||
Some(BucketRetention {
|
||||
validity: 42,
|
||||
r#type: RetentionType::Compliance
|
||||
})
|
||||
);
|
||||
|
||||
service
|
||||
.bucket_set_default_retention(
|
||||
TEST_BUCKET_NAME,
|
||||
Some(BucketRetention {
|
||||
validity: 21,
|
||||
r#type: RetentionType::Governance,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
service
|
||||
.bucket_get_default_retention(TEST_BUCKET_NAME)
|
||||
.await
|
||||
.unwrap(),
|
||||
Some(BucketRetention {
|
||||
validity: 21,
|
||||
r#type: RetentionType::Governance
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn bucket_without_retention() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let srv = MinioTestServer::start().await.unwrap();
|
||||
let service = srv.as_service();
|
||||
service
|
||||
.create_bucket(&MinioBucketSpec {
|
||||
instance: "".to_string(),
|
||||
name: TEST_BUCKET_NAME.to_string(),
|
||||
secret: "".to_string(),
|
||||
anonymous_read_access: false,
|
||||
versioning: false,
|
||||
quota: Some(42300),
|
||||
lock: true,
|
||||
retention: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||
assert_eq!(
|
||||
service
|
||||
.bucket_get_default_retention(TEST_BUCKET_NAME)
|
||||
.await
|
||||
.unwrap(),
|
||||
None
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use crate::utils::rand_str;
|
||||
use rand::RngCore;
|
||||
use std::io::ErrorKind;
|
||||
use std::process::{Child, Command};
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct MinioTestServer {
|
||||
#[allow(dead_code)]
|
||||
@ -62,6 +63,8 @@ impl MinioTestServer {
|
||||
}
|
||||
check_count += 1;
|
||||
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
|
||||
if instance.as_service().is_ready().await {
|
||||
break;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ spec:
|
||||
description: Limits the amount of data in the bucket, in bytes. By default it is unlimited
|
||||
example: 1000000000
|
||||
lock:
|
||||
description: Object locking prevent objects from being deleted. Will be considered as set to true when retention is defined.
|
||||
description: Object locking prevent objects from being deleted. MUST be set to true when retention is defined. Cannot be changed.
|
||||
type: boolean
|
||||
default: false
|
||||
retention:
|
||||
|
Loading…
Reference in New Issue
Block a user