Implement base operator #1

Merged
pierre merged 21 commits from operator into master 2023-05-08 16:20:17 +00:00
Showing only changes of commit f779715d65 - Show all commits

View File

@ -1,9 +1,11 @@
use std::process::Command;
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::utils::rand_str;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use std::process::Command;
const MC_ALIAS_NAME: &str = "managedminioinst";
@ -62,6 +64,16 @@ struct BasicMinioResult {
pub status: String,
}
#[derive(Debug, Clone, Deserialize)]
struct MinioGetVersioningResult {
pub versioning: Option<MinioVersioning>,
}
#[derive(Debug, Clone, Deserialize)]
struct MinioVersioning {
pub status: String,
}
impl BasicMinioResult {
pub fn success(&self) -> bool {
self.status == "success"
@ -89,6 +101,11 @@ impl MinioService {
false
}
/// Get bucket name prefixed by mc alias name
fn absolute_bucket_name(&self, name: &str) -> String {
format!("{}/{name}", MC_ALIAS_NAME)
}
/// Execute a minio mc command
async fn exec_mc_cmd<A>(&self, args: &[&str]) -> anyhow::Result<Vec<A>>
where
@ -179,10 +196,6 @@ impl MinioService {
let bucket_name = format!("{}/{}", MC_ALIAS_NAME, b.name);
let mut args = ["mb", bucket_name.as_str()].to_vec();
if b.versioning {
args.push("--with-versioning");
}
if b.lock || b.retention.is_some() {
args.push("--with-lock");
}
@ -192,6 +205,8 @@ impl MinioService {
return Err(MinioError::MakeBucketFailed.into());
}
self.bucket_set_versioning(&b.name, b.versioning).await?;
// Enable anonymous access, eg. public hosting
if b.anonymous_read_access {
let target = format!("{}/*", bucket_name);
@ -249,6 +264,38 @@ impl MinioService {
Ok(())
}
/// Set bucket versioning
pub async fn bucket_set_versioning(&self, bucket: &str, enable: bool) -> anyhow::Result<()> {
let bucket_name = self.absolute_bucket_name(bucket);
let res = self
.exec_mc_cmd::<BasicMinioResult>(&[
"version",
match enable {
true => "enable",
false => "suspend",
},
bucket_name.as_str(),
])
.await?;
if res.get(0).map(|r| r.success()) != Some(true) {
return Err(MinioError::SetQuotaFailed.into());
}
Ok(())
}
/// Get current bucket versioning status
pub async fn bucket_get_versioning(&self, bucket_name: &str) -> anyhow::Result<bool> {
let bucket_name = self.absolute_bucket_name(bucket_name);
Ok(self.exec_mc_cmd::<MinioGetVersioningResult>(&["version", "info", bucket_name.as_str()])
.await?
.remove(0)
.versioning
.map(|v| v.status.to_lowercase().eq("enabled"))
.unwrap_or_default())
}
}
#[cfg(test)]
@ -256,6 +303,8 @@ mod test {
use crate::crd::MinioBucketSpec;
use crate::minio_test_server::MinioTestServer;
const TEST_BUCKET_NAME: &str = "mybucket";
#[tokio::test]
async fn list_buckets_empty_instance() {
let srv = MinioTestServer::start().await.unwrap();
@ -278,7 +327,7 @@ mod test {
service
.create_bucket(&MinioBucketSpec {
instance: "".to_string(),
name: "mybucket".to_string(),
name: TEST_BUCKET_NAME.to_string(),
secret: "".to_string(),
anonymous_read_access: false,
versioning: false,
@ -288,13 +337,148 @@ mod test {
})
.await
.unwrap();
assert!(service.bucket_exists("mybucket").await.unwrap());
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
}
#[tokio::test]
async fn bucket_creation_with_anonymous_access() {
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: true,
versioning: false,
quota: None,
lock: false,
retention: None,
})
.await
.unwrap();
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
assert_eq!(
reqwest::get(format!("{}/{}/test", service.hostname, TEST_BUCKET_NAME))
.await
.unwrap()
.status()
.as_u16(),
404
);
}
#[tokio::test]
async fn bucket_creation_without_anonymous_access() {
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: None,
lock: false,
retention: None,
})
.await
.unwrap();
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
assert_eq!(
reqwest::get(format!("{}/{}/test", service.hostname, TEST_BUCKET_NAME))
.await
.unwrap()
.status()
.as_u16(),
403
);
}
// With versioning
#[tokio::test]
async fn bucket_with_versioning() {
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: true,
quota: None,
lock: false,
retention: None,
})
.await
.unwrap();
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
assert!(service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
}
#[tokio::test]
async fn bucket_without_versioning() {
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: None,
lock: false,
retention: None,
})
.await
.unwrap();
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
assert!(!service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
}
#[tokio::test]
async fn change_versioning() {
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: None,
lock: false,
retention: None,
})
.await
.unwrap();
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
assert!(!service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
service.bucket_set_versioning(TEST_BUCKET_NAME, true).await.unwrap();
assert!(service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
service.bucket_set_versioning(TEST_BUCKET_NAME, false).await.unwrap();
assert!(!service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
}
// TODO : with anonymous access
// TODO : without anonymous access
// TODO : with versioning
// TODO : without versioning
// TODO : with quota
// TODO : without quota
// TODO : with lock