Compare commits
18 Commits
master
...
765a8108fd
| Author | SHA1 | Date | |
|---|---|---|---|
| 765a8108fd | |||
| 268f9a47cd | |||
| 073c91fe0d | |||
| c90e46f038 | |||
| 328036b7b3 | |||
| 1ae2cf7282 | |||
| 42e2ea5539 | |||
| 239b58d8db | |||
| e3860d9f93 | |||
| fb2a9f39fb | |||
| f779715d65 | |||
| a3f523410f | |||
| 11d2ba5312 | |||
| 76c22150c0 | |||
| 36aaf5fb4d | |||
| 547cc02800 | |||
| 4b7748bfbf | |||
| 68c27a310d |
57
.drone.yml
57
.drone.yml
@@ -4,64 +4,13 @@ type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: fetch_dependencies
|
||||
- name: cargo_check
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
commands:
|
||||
- cargo fetch
|
||||
|
||||
- name: code_quality
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
depends_on:
|
||||
- fetch_dependencies
|
||||
commands:
|
||||
- rustup component add clippy
|
||||
- cargo clippy -- -D warnings
|
||||
|
||||
- name: test
|
||||
image: rust
|
||||
depends_on:
|
||||
- code_quality
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
commands:
|
||||
- wget -O /usr/bin/minio https://dl.min.io/server/minio/release/linux-amd64/minio
|
||||
- wget -O /usr/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc
|
||||
- chmod +x /usr/bin/minio /usr/bin/mc
|
||||
- rustup component add clippy
|
||||
- cargo clippy -- -D warnings
|
||||
- cargo test
|
||||
|
||||
- name: build_doc
|
||||
image: python
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: AWS_ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: AWS_SECRET_ACCESS_KEY
|
||||
AWS_DEFAULT_REGION: us-east-1
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
exclude:
|
||||
- pull_request
|
||||
commands:
|
||||
# Build website
|
||||
- pip install mkdocs-material
|
||||
- mkdocs build --site-dir public
|
||||
# Install AWS
|
||||
- curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
||||
- unzip awscliv2.zip
|
||||
- ./aws/install
|
||||
- aws configure set default.s3.signature_version s3v4
|
||||
# Upload to bucket
|
||||
- cd public && aws --endpoint-url https://s3.communiquons.org s3 sync . s3://miniok8sbucketsoperator-website
|
||||
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
temp: {}
|
||||
2115
Cargo.lock
generated
2115
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
28
Cargo.toml
28
Cargo.toml
@@ -6,17 +6,17 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.28"
|
||||
env_logger = "0.11.8"
|
||||
anyhow = "1.0.100"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.145"
|
||||
schemars = "1.1.0"
|
||||
tokio = { version = "1.48.0", features = ["full"] }
|
||||
kube = { version = "2.0.1", features = ["runtime", "derive"] }
|
||||
k8s-openapi = { version = "0.26.0", features = ["v1_31"] }
|
||||
futures = "0.3.31"
|
||||
thiserror = "2.0.17"
|
||||
rand = "0.9.2"
|
||||
mktemp = "0.5.1"
|
||||
reqwest = "0.12.24"
|
||||
log = "0.4.17"
|
||||
env_logger = "0.10.0"
|
||||
anyhow = "1.0.71"
|
||||
serde = { version = "1.0.162", features = ["derive"] }
|
||||
serde_json = "1.0.96"
|
||||
schemars = "0.8.12"
|
||||
tokio = { version = "1.28.0", features = ["full"] }
|
||||
kube = { version = "0.82.2", features = ["runtime", "derive"] }
|
||||
k8s-openapi = { version = "0.18.0", features = ["v1_26"] } # TODO : switch to v1_27
|
||||
futures = "0.3.28"
|
||||
thiserror = "1.0.40"
|
||||
rand = "0.8.5"
|
||||
mktemp = "0.5.0"
|
||||
reqwest = "0.11.17"
|
||||
10
Dockerfile
10
Dockerfile
@@ -1,10 +0,0 @@
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libssl3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY minio-operator /usr/local/bin/minio-operator
|
||||
COPY mc /usr/local/bin/mc
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/minio-operator"]
|
||||
13
README.md
13
README.md
@@ -1,6 +1,13 @@
|
||||
# MinioK8sBuckets
|
||||
[](https://drone.communiquons.org/pierre/MinioK8sBuckets)
|
||||
|
||||
Automatically create Minio buckets based on K8S Custom Resources.
|
||||
Automatically create Minio buckets based on K8S CRD.
|
||||
|
||||
See the [docs](docs) to learn more.
|
||||
WIP, early project
|
||||
|
||||
Apply all K8s config files manually:
|
||||
|
||||
```bash
|
||||
cat yaml/*.yaml | kubectl apply -f -
|
||||
```
|
||||
|
||||
Note : [mc tool](https://min.io/download) is required
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
cargo build --release
|
||||
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
cp target/release/minio-operator "$TEMP_DIR"
|
||||
|
||||
# Download mc
|
||||
wget -O "$TEMP_DIR/mc" https://dl.min.io/client/mc/release/linux-amd64/mc
|
||||
chmod +x "$TEMP_DIR/mc"
|
||||
|
||||
docker build -f Dockerfile "$TEMP_DIR" -t pierre42100/minio_operator
|
||||
|
||||
rm -r $TEMP_DIR
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
# Setup for development
|
||||
This guide will present you how to prepare your computer to update features of MinioK8SBucket
|
||||
|
||||
|
||||
## Install Rust
|
||||
As this project has been written using Rust, you will need to install it prior working on MinioK8SBucket. Please follow the official instructions: [https://www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install)
|
||||
|
||||
## Install Minikube
|
||||
First, you need to install Minikube on your computer to have a K8S environment. In order to do this, please follow the official instructions: [https://minikube.sigs.k8s.io/docs/start](https://minikube.sigs.k8s.io/docs/start)
|
||||
|
||||
|
||||
## Start Minikube
|
||||
You will then need to start Minikube using the following command:
|
||||
|
||||
```bash
|
||||
minikube start
|
||||
```
|
||||
|
||||
You can then make sure that Minikube is working properly:
|
||||
|
||||
```
|
||||
minikube kubectl get nodes
|
||||
```
|
||||
|
||||
You should get a response similar to this one:
|
||||
|
||||
```
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
minikube Ready control-plane 2m16s v1.32.0
|
||||
```
|
||||
|
||||
## Clone repository
|
||||
Clone this repository using:
|
||||
|
||||
```bash
|
||||
https://gitea.communiquons.org/pierre/MinioK8sBuckets
|
||||
```
|
||||
|
||||
!!! note "Gitea account request"
|
||||
If you want to get a Gitea account to make pull request on this repository, you will need to contact me at: `pierre.git@communiquons.org`
|
||||
|
||||
## Deploy Minio
|
||||
First, enable Minikube tunnel:
|
||||
```bash
|
||||
minikube tunnel --bind-address '127.0.0.1'
|
||||
```
|
||||
|
||||
You will then need to deploy Minio in Minikube. Apply the Minio deployment located at the in MinioK8SBucket repository:
|
||||
|
||||
```bash
|
||||
minikube kubectl -- apply -f yaml/minio-dev-deployment.yml
|
||||
```
|
||||
|
||||
Wait for the pod to become ready:
|
||||
|
||||
```bash
|
||||
minikube kubectl -- get pods -w
|
||||
```
|
||||
|
||||
Check for the availability of the service that expose Minio to your host computer:
|
||||
|
||||
```bash
|
||||
minikube kubectl -- get services
|
||||
```
|
||||
|
||||
You should get a result similar to this one:
|
||||
|
||||
```
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 31m
|
||||
minio LoadBalancer 10.103.82.87 127.0.0.1 9000:30656/TCP,9090:31369/TCP 6m40s
|
||||
```
|
||||
|
||||
You should be able to access minio at the following address: [http://127.0.0.1:9090](http://127.0.0.1:9090/)
|
||||
|
||||
Minio API should be available at: [http://127.0.0.1:9000/](http://127.0.0.1:9000/)
|
||||
|
||||
## Deploy CRD
|
||||
You will need then to deploy the Custom Resource Definitions of MinioK8SBucket using the following command:
|
||||
|
||||
```bash
|
||||
minikube kubectl -- apply -f yaml/crd.yaml
|
||||
```
|
||||
|
||||
## Run operator
|
||||
You can then run the project using the following command:
|
||||
|
||||
```bash
|
||||
cargo fmt && cargo clippy && RUST_LOG=debug cargo run --
|
||||
```
|
||||
|
||||
## Create a first bucket
|
||||
You should be able to create a first bucket using the following command:
|
||||
|
||||
```bash
|
||||
minikube kubectl -- apply -f test/test-outside-cluster.yaml
|
||||
```
|
||||
|
||||
The bucket should then appear in buckets list:
|
||||
|
||||
```bash
|
||||
minikube kubectl -- get buckets
|
||||
```
|
||||
```
|
||||
NAME AGE
|
||||
first-bucket 8m43s
|
||||
```
|
||||
|
||||
Have fun working for MinioK8SBucket!
|
||||
116
docs/README.md
116
docs/README.md
@@ -1,116 +0,0 @@
|
||||
# Minio K8S bucket operator
|
||||
|
||||
An operator to automatically create and update S3 buckets on Minio, with their accounts.
|
||||
|
||||
One deployed, this tool will allow you to automatically create Minio accounts associated with buckets.
|
||||
|
||||
|
||||
## Pre-requisites
|
||||
You will need:
|
||||
|
||||
* `kubectl` access to the target cluster
|
||||
* A running Minio instance, and especially:
|
||||
* The URL where the API of the instance can be reached
|
||||
* The root credentials
|
||||
|
||||
|
||||
## Installation
|
||||
The operator can be installed using the following commands:
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://raw.githubusercontent.com/pierre42100/MinioK8sBuckets/master/yaml/crd.yaml
|
||||
kubectl apply -f https://raw.githubusercontent.com/pierre42100/MinioK8sBuckets/master/yaml/deployment.yaml
|
||||
```
|
||||
|
||||
!!! warning "Known limitation"
|
||||
The operator install a deployment on the `default` namespace. Currently, only this namespace is supported!
|
||||
|
||||
## Configure instance
|
||||
In order to create buckets, the operator needs to know how to reach the Minio instance.
|
||||
|
||||
You first need to secret similar to that one:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: minio-root
|
||||
type: Opaque
|
||||
dyringData:
|
||||
accessKey: <MINIO_ROOT_ACCESS_KEY>
|
||||
secretKey: <MINIO_ROOT_SECRET_KEY>
|
||||
```
|
||||
|
||||
Replace `<MINIO_ROOT_ACCESS_KEY>` and `<MINIO_ROOT_SECRET_KEY>` with the appropriate values.
|
||||
|
||||
|
||||
|
||||
You can then declare a Minio instance simiarl to that one:
|
||||
|
||||
```yaml
|
||||
apiVersion: "communiquons.org/v1"
|
||||
kind: MinioInstance
|
||||
metadata:
|
||||
name: my-minio-instance
|
||||
spec:
|
||||
endpoint: https://minio.example.com/
|
||||
credentials: minio-root
|
||||
```
|
||||
|
||||
!!! note
|
||||
Minio itself can be located outside of the Kubernetes cluster.
|
||||
|
||||
|
||||
## Create a bucket
|
||||
You are now ready to create your first bucket!
|
||||
|
||||
Here is a basic bucket example:
|
||||
|
||||
```yaml
|
||||
apiVersion: "communiquons.org/v1"
|
||||
kind: MinioBucket
|
||||
metadata:
|
||||
name: first-bucket
|
||||
spec:
|
||||
# The name of the minio instance
|
||||
instance: my-minio-instance
|
||||
# The name of the bucket to create
|
||||
name: first-bucket
|
||||
# The name of the secret that will be created
|
||||
# by the operator which contains credentials to
|
||||
# use to access the bucket
|
||||
secret: first-bucket-secret
|
||||
```
|
||||
|
||||
## More complete example
|
||||
Here is a more complete example that makes use of all the available options:
|
||||
|
||||
```yaml
|
||||
apiVersion: "communiquons.org/v1"
|
||||
kind: MinioBucket
|
||||
metadata:
|
||||
name: my-bucket
|
||||
spec:
|
||||
instance: my-minio-instance
|
||||
name: my-bucket
|
||||
secret: my-bucket-secret
|
||||
# This must be set to true to allow unauthenticated
|
||||
# access to the bucket resources. Use this to host a
|
||||
# static website for example
|
||||
anonymous_read_access: true
|
||||
# Enable versioning on the bucket => keep old versions
|
||||
# of uploaded files
|
||||
versioning: true
|
||||
# If specified, a quota will be applied to the bucket, in bytes
|
||||
quota: 1000000000
|
||||
# Prevent files from being removed from the bucket. This parameter
|
||||
# can not be changed, once the bucket has been created
|
||||
lock: true
|
||||
# Data retention policy. Versioning must be enabled to allow this
|
||||
retention:
|
||||
# The number of days data shall be kept
|
||||
validity: 100
|
||||
# compliance => nobody can bypass the policy
|
||||
# governance => users with privileges might bypass policy restrictions
|
||||
mode: compliance
|
||||
```
|
||||
20
mkdocs.yml
20
mkdocs.yml
@@ -1,20 +0,0 @@
|
||||
site_name: Minio K8S buckets operator
|
||||
theme:
|
||||
language: en
|
||||
name: material
|
||||
palette:
|
||||
# Palette toggle for dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- pymdownx.details
|
||||
- pymdownx.superfences
|
||||
|
||||
repo_url: https://gitea.communiquons.org/pierre/MinioK8sBuckets
|
||||
edit_uri: src/branch/master/docs/
|
||||
|
||||
plugins:
|
||||
- search
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": ["local>renovate/presets"]
|
||||
}
|
||||
@@ -4,5 +4,4 @@ pub mod minio;
|
||||
#[cfg(test)]
|
||||
pub mod minio_test_server;
|
||||
pub mod secrets;
|
||||
pub mod temp;
|
||||
pub mod utils;
|
||||
|
||||
14
src/main.rs
14
src/main.rs
@@ -10,7 +10,6 @@ use minio_operator::crd::{MinioBucket, MinioInstance};
|
||||
use minio_operator::minio::{MinioService, MinioUser};
|
||||
use minio_operator::secrets::{create_secret, read_secret_str};
|
||||
use std::collections::BTreeMap;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
@@ -55,17 +54,6 @@ async fn apply_bucket(b: &MinioBucket, client: &Client) -> anyhow::Result<()> {
|
||||
secret_key: read_secret_str(&instance_secret, SECRET_MINIO_INSTANCE_SECRET_KEY)?,
|
||||
};
|
||||
|
||||
// Check if Minio is responding
|
||||
let mut ready_count = 0;
|
||||
while !service.is_ready().await {
|
||||
if ready_count > 10 {
|
||||
panic!("Minio is unreachable!");
|
||||
}
|
||||
ready_count += 1;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
log::warn!("Minio is not responding yet, will try again to connect soon...");
|
||||
}
|
||||
|
||||
// Get user key & password
|
||||
let user_secret = match secrets.get_opt(&b.spec.secret).await? {
|
||||
Some(s) => s,
|
||||
@@ -77,7 +65,7 @@ async fn apply_bucket(b: &MinioBucket, client: &Client) -> anyhow::Result<()> {
|
||||
);
|
||||
|
||||
// The secret needs to be created
|
||||
let new_user = MinioUser::gen_random(&b.spec.name);
|
||||
let new_user = MinioUser::gen_random();
|
||||
create_secret(
|
||||
&secrets,
|
||||
&b.spec.secret,
|
||||
|
||||
43
src/minio.rs
43
src/minio.rs
@@ -5,7 +5,6 @@ use serde::Deserialize;
|
||||
|
||||
use crate::constants::{MC_EXE, SECRET_MINIO_BUCKET_ACCESS_LEN, SECRET_MINIO_BUCKET_SECRET_LEN};
|
||||
use crate::crd::{BucketRetention, MinioBucketSpec, RetentionType};
|
||||
use crate::temp;
|
||||
use crate::utils::rand_str;
|
||||
|
||||
const MC_ALIAS_NAME: &str = "managedminioinst";
|
||||
@@ -44,9 +43,9 @@ pub struct MinioUser {
|
||||
}
|
||||
|
||||
impl MinioUser {
|
||||
pub fn gen_random(prefix: &str) -> Self {
|
||||
pub fn gen_random() -> Self {
|
||||
Self {
|
||||
username: format!("{prefix}_{}", rand_str(SECRET_MINIO_BUCKET_ACCESS_LEN)),
|
||||
username: rand_str(SECRET_MINIO_BUCKET_ACCESS_LEN),
|
||||
password: rand_str(SECRET_MINIO_BUCKET_SECRET_LEN),
|
||||
}
|
||||
}
|
||||
@@ -164,7 +163,7 @@ impl MinioService {
|
||||
|
||||
/// Get bucket name prefixed by mc alias name
|
||||
fn absolute_bucket_name(&self, name: &str) -> String {
|
||||
format!("{MC_ALIAS_NAME}/{name}")
|
||||
format!("{}/{name}", MC_ALIAS_NAME)
|
||||
}
|
||||
|
||||
/// Execute a minio mc command
|
||||
@@ -172,9 +171,9 @@ impl MinioService {
|
||||
where
|
||||
A: DeserializeOwned,
|
||||
{
|
||||
log::debug!("exec_mc_cmd with args {args:?}");
|
||||
log::debug!("exec_mc_cmd with args {:?}", args);
|
||||
|
||||
let conf_dir = temp::create_temp_dir()?;
|
||||
let conf_dir = mktemp::Temp::new_dir()?;
|
||||
let global_flags = ["--config-dir", conf_dir.to_str().unwrap(), "--json"];
|
||||
|
||||
// First, set our alias to mc in a temporary directory
|
||||
@@ -262,7 +261,7 @@ impl MinioService {
|
||||
}
|
||||
|
||||
let res = self.exec_mc_cmd::<BasicMinioResult>(&args).await?;
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::MakeBucketFailed.into());
|
||||
}
|
||||
|
||||
@@ -293,7 +292,7 @@ impl MinioService {
|
||||
])
|
||||
.await?;
|
||||
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::SetQuotaFailed.into());
|
||||
}
|
||||
Ok(())
|
||||
@@ -317,7 +316,7 @@ impl MinioService {
|
||||
bucket_name: &str,
|
||||
access: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let target = format!("{}/*", self.absolute_bucket_name(bucket_name));
|
||||
let target = self.absolute_bucket_name(bucket_name);
|
||||
|
||||
let res = self
|
||||
.exec_mc_cmd::<BasicMinioResult>(&[
|
||||
@@ -331,7 +330,7 @@ impl MinioService {
|
||||
])
|
||||
.await?;
|
||||
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::SetAnonymousAcccessFailed.into());
|
||||
}
|
||||
|
||||
@@ -340,7 +339,7 @@ impl MinioService {
|
||||
|
||||
/// Get current bucket anonymous access status
|
||||
pub async fn bucket_get_anonymous_access(&self, bucket_name: &str) -> anyhow::Result<bool> {
|
||||
let bucket_name = format!("{}/*", self.absolute_bucket_name(bucket_name));
|
||||
let bucket_name = self.absolute_bucket_name(bucket_name);
|
||||
Ok(self
|
||||
.exec_mc_cmd::<MinioAnonymousAccess>(&["anonymous", "get", bucket_name.as_str()])
|
||||
.await?
|
||||
@@ -354,7 +353,7 @@ impl MinioService {
|
||||
let bucket_name = self.absolute_bucket_name(bucket);
|
||||
|
||||
let res = if let Some(quota) = "a {
|
||||
let quota = format!("{quota}B");
|
||||
let quota = format!("{}B", quota);
|
||||
self.exec_mc_cmd::<BasicMinioResult>(&[
|
||||
"quota",
|
||||
"set",
|
||||
@@ -368,7 +367,7 @@ impl MinioService {
|
||||
.await?
|
||||
};
|
||||
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::SetQuotaFailed.into());
|
||||
}
|
||||
Ok(())
|
||||
@@ -416,7 +415,7 @@ impl MinioService {
|
||||
.await?
|
||||
};
|
||||
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::SetRetentionFailed.into());
|
||||
}
|
||||
|
||||
@@ -447,7 +446,7 @@ impl MinioService {
|
||||
"governance" => RetentionType::Governance,
|
||||
"compliance" => RetentionType::Compliance,
|
||||
o => {
|
||||
log::error!("Unknown retention type: {o}");
|
||||
log::error!("Unknown retention type: {}", o);
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
@@ -459,7 +458,7 @@ impl MinioService {
|
||||
|
||||
/// Apply a bucket policy
|
||||
pub async fn policy_apply(&self, name: &str, content: &str) -> anyhow::Result<()> {
|
||||
let tmp_file = temp::create_temp_file()?;
|
||||
let tmp_file = mktemp::Temp::new_file()?;
|
||||
std::fs::write(&tmp_file, content)?;
|
||||
|
||||
let res = self
|
||||
@@ -473,7 +472,7 @@ impl MinioService {
|
||||
])
|
||||
.await?;
|
||||
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::ApplyPolicyFailed.into());
|
||||
}
|
||||
|
||||
@@ -513,7 +512,7 @@ impl MinioService {
|
||||
])
|
||||
.await?;
|
||||
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::CreateUserFailed.into());
|
||||
}
|
||||
|
||||
@@ -553,7 +552,7 @@ impl MinioService {
|
||||
])
|
||||
.await?;
|
||||
|
||||
if res.first().map(|r| r.success()) != Some(true) {
|
||||
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||
return Err(MinioError::CreateUserFailed.into());
|
||||
}
|
||||
|
||||
@@ -580,7 +579,7 @@ impl MinioService {
|
||||
.userMappings;
|
||||
|
||||
if let Some(mapping) = res {
|
||||
if let Some(e) = mapping.first() {
|
||||
if let Some(e) = mapping.get(0) {
|
||||
return Ok(e.policies.clone());
|
||||
}
|
||||
}
|
||||
@@ -1099,7 +1098,7 @@ mod test {
|
||||
let srv = MinioTestServer::start().await.unwrap();
|
||||
let service = srv.as_service();
|
||||
|
||||
let user = MinioUser::gen_random("policy_user");
|
||||
let user = MinioUser::gen_random();
|
||||
|
||||
assert!(!service.user_list().await.unwrap().contains(&user.username));
|
||||
service.user_apply(&user).await.unwrap();
|
||||
@@ -1113,7 +1112,7 @@ mod test {
|
||||
let srv = MinioTestServer::start().await.unwrap();
|
||||
let service = srv.as_service();
|
||||
|
||||
let user = MinioUser::gen_random("attach_policy_user");
|
||||
let user = MinioUser::gen_random();
|
||||
|
||||
service.user_apply(&user).await.unwrap();
|
||||
service
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
//! Used for testing only
|
||||
|
||||
use crate::minio::MinioService;
|
||||
use crate::temp;
|
||||
use crate::utils::rand_str;
|
||||
use rand::RngCore;
|
||||
use std::io::ErrorKind;
|
||||
@@ -21,11 +20,11 @@ pub struct MinioTestServer {
|
||||
|
||||
impl MinioTestServer {
|
||||
pub async fn start() -> anyhow::Result<Self> {
|
||||
let storage_dir = temp::create_temp_dir()?;
|
||||
let storage_dir = mktemp::Temp::new_dir()?;
|
||||
|
||||
let root_user = rand_str(30);
|
||||
let root_password = rand_str(30);
|
||||
let api_port = (2000 + rand::rng().next_u64() % 5000) as u16;
|
||||
let api_port = (2000 + rand::thread_rng().next_u64() % 5000) as u16;
|
||||
log::info!(
|
||||
"Spwan a new Minio server on port {} with root credentials {}:{}",
|
||||
api_port,
|
||||
@@ -52,7 +51,6 @@ impl MinioTestServer {
|
||||
};
|
||||
|
||||
// Wait for Minio to become ready
|
||||
std::thread::sleep(Duration::from_millis(500));
|
||||
let mut check_count = 0;
|
||||
loop {
|
||||
if check_count >= 100 {
|
||||
|
||||
26
src/temp.rs
26
src/temp.rs
@@ -1,26 +0,0 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Get the directory where temp files should be created
|
||||
fn temp_path() -> Option<PathBuf> {
|
||||
std::env::var("TEMP_DIR")
|
||||
.as_deref()
|
||||
.ok()
|
||||
.map(Path::new)
|
||||
.map(|p| p.to_path_buf())
|
||||
}
|
||||
|
||||
/// Create a temporary directory
|
||||
pub fn create_temp_dir() -> std::io::Result<mktemp::Temp> {
|
||||
match temp_path() {
|
||||
None => mktemp::Temp::new_dir(),
|
||||
Some(p) => mktemp::Temp::new_dir_in(p),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a temporary file
|
||||
pub fn create_temp_file() -> std::io::Result<mktemp::Temp> {
|
||||
match temp_path() {
|
||||
None => mktemp::Temp::new_file(),
|
||||
Some(p) => mktemp::Temp::new_file_in(p),
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
use rand::distr::{Alphanumeric, SampleString};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::Rng;
|
||||
|
||||
/// Generate a random string of a given size
|
||||
pub fn rand_str(len: usize) -> String {
|
||||
Alphanumeric.sample_string(&mut rand::rng(), len)
|
||||
rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(len)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -7,4 +7,3 @@ spec:
|
||||
instance: my-minio-instance
|
||||
name: second-bucket
|
||||
secret: second-bucket-secret
|
||||
versioning: false
|
||||
@@ -1,25 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: minio-root
|
||||
type: Opaque
|
||||
data:
|
||||
accessKey: bWluaW9hZG1pbg==
|
||||
secretKey: bWluaW9hZG1pbg==
|
||||
---
|
||||
apiVersion: "communiquons.org/v1"
|
||||
kind: MinioInstance
|
||||
metadata:
|
||||
name: my-minio-instance
|
||||
spec:
|
||||
endpoint: http://192.168.2.103:9000/
|
||||
credentials: minio-root
|
||||
---
|
||||
apiVersion: "communiquons.org/v1"
|
||||
kind: MinioBucket
|
||||
metadata:
|
||||
name: first-bucket
|
||||
spec:
|
||||
instance: my-minio-instance
|
||||
name: first-bucket
|
||||
secret: first-bucket-secret
|
||||
@@ -12,7 +12,7 @@ kind: MinioInstance
|
||||
metadata:
|
||||
name: my-minio-instance
|
||||
spec:
|
||||
endpoint: http://localhost:9000
|
||||
endpoint: http://localhost:9000/
|
||||
credentials: minio-root
|
||||
---
|
||||
apiVersion: "communiquons.org/v1"
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
automountServiceAccountToken: true
|
||||
metadata:
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
labels:
|
||||
app: minio-operator
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
rules:
|
||||
- apiGroups: ["communiquons.org"]
|
||||
resources: ["minioinstances", "miniobuckets"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get", "create"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: minio-operator
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: minio-operator
|
||||
labels:
|
||||
app: minio-operator
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: minio-operator
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: minio-operator
|
||||
spec:
|
||||
serviceAccountName: minio-operator
|
||||
containers:
|
||||
- name: minio-operator
|
||||
image: pierre42100/minio_operator
|
||||
resources:
|
||||
limits:
|
||||
memory: 300Mi
|
||||
cpu: "0.1"
|
||||
requests:
|
||||
memory: 150Mi
|
||||
cpu: "0.01"
|
||||
volumeMounts:
|
||||
- mountPath: /tmp
|
||||
readOnly: false
|
||||
name: tempdir
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumes:
|
||||
- name: tempdir
|
||||
emptyDir:
|
||||
sizeLimit: 500Mi
|
||||
@@ -1,54 +1,5 @@
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: minioinstances.communiquons.org
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: communiquons.org
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
description: Information about how to reach the Minio bucket
|
||||
properties:
|
||||
endpoint:
|
||||
description: The URL where the Minio API can be reached
|
||||
example: https://minio.communiquons.org
|
||||
type: string
|
||||
credentials:
|
||||
description: |
|
||||
The name of the secret containings privilegied / root credentials of Minio instance
|
||||
|
||||
The secret must contains two fields :
|
||||
* An access key named `accessKey`
|
||||
* A secret key named `secretKey`
|
||||
type: string
|
||||
example: minio-root
|
||||
# either Namespaced or Cluster
|
||||
scope: Namespaced
|
||||
names:
|
||||
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
|
||||
plural: minioinstances
|
||||
# singular name to be used as an alias on the CLI and for display
|
||||
singular: minioinstance
|
||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||
kind: MinioInstance
|
||||
# shortNames allow shorter string to match your resource on the CLI
|
||||
shortNames:
|
||||
- mis
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: miniobuckets.communiquons.org
|
||||
@@ -1,89 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: minio
|
||||
labels:
|
||||
app: minio
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: minio
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: minio
|
||||
spec:
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: minio
|
||||
containers:
|
||||
- name: minio
|
||||
image: minio/minio
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
protocol: TCP
|
||||
name: api
|
||||
- containerPort: 9090
|
||||
protocol: TCP
|
||||
name: console
|
||||
args:
|
||||
- server
|
||||
- /data
|
||||
- --console-address
|
||||
- ":9090"
|
||||
env:
|
||||
- name: MINIO_ROOT_USER
|
||||
value: minioadmin
|
||||
- name: MINIO_ROOT_PASSWORD
|
||||
value: minioadmin
|
||||
volumeMounts:
|
||||
- mountPath: "/data"
|
||||
name: data
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: minio
|
||||
spec:
|
||||
storageClassName: manual
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
hostPath:
|
||||
path: /data/minio/
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: minio
|
||||
spec:
|
||||
storageClassName: manual
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 3Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: minio
|
||||
labels:
|
||||
app: minio
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
selector:
|
||||
app: minio
|
||||
ports:
|
||||
- name: api
|
||||
port: 9000
|
||||
targetPort: api
|
||||
- name: console
|
||||
port: 9090
|
||||
targetPort: console
|
||||
externalTrafficPolicy: Local
|
||||
49
yaml/minio-instance.yaml
Normal file
49
yaml/minio-instance.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: minioinstances.communiquons.org
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: communiquons.org
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
description: Information about how to reach the Minio bucket
|
||||
properties:
|
||||
endpoint:
|
||||
description: The URL where the Minio API can be reached
|
||||
example: https://minio.communiquons.org
|
||||
type: string
|
||||
credentials:
|
||||
description: |
|
||||
The name of the secret containings privilegied / root credentials of Minio instance
|
||||
|
||||
The secret must contains two fields :
|
||||
* An access key named `accessKey`
|
||||
* A secret key named `secretKey`
|
||||
type: string
|
||||
example: minio-root
|
||||
# either Namespaced or Cluster
|
||||
scope: Namespaced
|
||||
names:
|
||||
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
|
||||
plural: minioinstances
|
||||
# singular name to be used as an alias on the CLI and for display
|
||||
singular: minioinstance
|
||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||
kind: MinioInstance
|
||||
# shortNames allow shorter string to match your resource on the CLI
|
||||
shortNames:
|
||||
- mis
|
||||
---
|
||||
33
yaml/service_account.yaml
Normal file
33
yaml/service_account.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
automountServiceAccountToken: true
|
||||
metadata:
|
||||
name: minio-buckets
|
||||
namespace: default
|
||||
labels:
|
||||
app: minio
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: minio-buckets
|
||||
namespace: default
|
||||
rules:
|
||||
- apiGroups: ["communiquons.org"]
|
||||
resources: ["minioinstances", "miniobuckets"]
|
||||
verbs: ["get", "watch"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: minio-buckets
|
||||
namespace: default
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: minio-buckets
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: minio-buckets
|
||||
---
|
||||
Reference in New Issue
Block a user