Compare commits
1 Commits
feat/opnse
...
feat/rustf
| Author | SHA1 | Date | |
|---|---|---|---|
| 3cf4fe4855 |
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -2953,6 +2953,16 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example-rustfs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"harmony",
|
||||
"harmony_cli",
|
||||
"harmony_types",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example-tenant"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -14,6 +14,7 @@ If you're new to Harmony, start here:
|
||||
See how to use Harmony to solve real-world problems.
|
||||
|
||||
- [**PostgreSQL on Local K3D**](./use-cases/postgresql-on-local-k3d.md): Deploy a production-grade PostgreSQL cluster on a local K3D cluster. The fastest way to get started.
|
||||
- [**RustFS on Local K3D**](./use-cases/rustfs-on-local-k3d.md): Deploy a RustFS S3-compatible object store on a local K3D cluster.
|
||||
- [**OKD on Bare Metal**](./use-cases/okd-on-bare-metal.md): A detailed walkthrough of bootstrapping a high-availability OKD cluster from physical hardware.
|
||||
|
||||
## 3. Component Catalogs
|
||||
|
||||
151
docs/use-cases/rustfs-on-local-k3d.md
Normal file
151
docs/use-cases/rustfs-on-local-k3d.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Use Case: RustFS (S3-Compatible Store) on Local K3D
|
||||
|
||||
Deploy a RustFS object store on a local Kubernetes cluster (K3D) using Harmony. RustFS is a Rust-based S3-compatible storage server, a modern alternative to MinIO for local development.
|
||||
|
||||
## What you'll have at the end
|
||||
|
||||
A fully operational S3-compatible object store with:
|
||||
- 1 standalone instance with 1 GiB of storage
|
||||
- S3 API endpoint on port 9000
|
||||
- Web console on port 9001
|
||||
- Ingress-based access at `http://rustfs.local`
|
||||
- Default credentials: `rustfsadmin` / `rustfsadmin`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Rust 2024 edition
|
||||
- Docker running locally
|
||||
- ~5 minutes
|
||||
|
||||
## The Score
|
||||
|
||||
The entire deployment is expressed in ~20 lines of Rust:
|
||||
|
||||
```rust
|
||||
use harmony::{
|
||||
inventory::Inventory,
|
||||
modules::rustfs::{K8sRustFsScore, RustFsConfig},
|
||||
topology::K8sAnywhereTopology,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let rustfs = K8sRustFsScore {
|
||||
config: RustFsConfig {
|
||||
release_name: "harmony-rustfs".to_string(),
|
||||
namespace: "harmony-rustfs".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
harmony_cli::run(
|
||||
Inventory::autoload(),
|
||||
K8sAnywhereTopology::from_env(),
|
||||
vec![Box::new(rustfs)],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
## What Harmony does
|
||||
|
||||
When you run this, Harmony:
|
||||
|
||||
1. **Connects to K8sAnywhereTopology** — auto-provisions a K3D cluster if none exists
|
||||
2. **Creates a namespace** — `harmony-rustfs` (or your custom namespace)
|
||||
3. **Creates credentials secret** — stores the access/secret keys securely
|
||||
4. **Deploys via Helm** — installs the RustFS chart in standalone mode
|
||||
5. **Configures Ingress** — sets up routing at `rustfs.local`
|
||||
|
||||
## Running it
|
||||
|
||||
```bash
|
||||
cargo run -p example-rustfs
|
||||
```
|
||||
|
||||
## Verifying the deployment
|
||||
|
||||
```bash
|
||||
# Check pods
|
||||
kubectl get pods -n harmony-rustfs
|
||||
|
||||
# Check ingress
|
||||
kubectl get ingress -n harmony-rustfs
|
||||
|
||||
# Access the S3 API
|
||||
# Add rustfs.local to your /etc/hosts
|
||||
echo "127.0.0.1 rustfs.local" | sudo tee -a /etc/hosts
|
||||
|
||||
# Use the AWS CLI or any S3 client
|
||||
AWS_ACCESS_KEY_ID=rustfsadmin \
|
||||
AWS_SECRET_ACCESS_KEY=rustfsadmin \
|
||||
aws s3 ls --endpoint-url http://rustfs.local:9000
|
||||
|
||||
# Or via the web console
|
||||
open http://rustfs.local:9001
|
||||
```
|
||||
|
||||
## Customizing the deployment
|
||||
|
||||
The `RustFsConfig` struct supports:
|
||||
|
||||
| Field | Default | Description |
|
||||
|-------|---------|-------------|
|
||||
| `release_name` | `rustfs` | Helm release name |
|
||||
| `namespace` | `harmony-rustfs` | Kubernetes namespace |
|
||||
| `storage_size` | `1Gi` | Data storage size |
|
||||
| `mode` | `Standalone` | Deployment mode (standalone only for now) |
|
||||
| `access_key` | `None` | S3 access key (default: `rustfsadmin`) |
|
||||
| `secret_key` | `None` | S3 secret key (default: `rustfsadmin`) |
|
||||
| `ingress_class` | `None` | Ingress class to use (default: `nginx`) |
|
||||
|
||||
Example with custom credentials:
|
||||
|
||||
```rust
|
||||
let rustfs = K8sRustFsScore {
|
||||
config: RustFsConfig {
|
||||
release_name: "my-rustfs".to_string(),
|
||||
namespace: "storage".to_string(),
|
||||
access_key: Some("myaccess".to_string()),
|
||||
secret_key: Some("mysecret".to_string()),
|
||||
ingress_class: Some("traefik".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
The RustFS module follows the same pattern as PostgreSQL:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ K8sRustFsScore (user-facing) │
|
||||
│ └── K8sRustFsInterpret │
|
||||
│ ├── ensure_namespace() │
|
||||
│ ├── ensure_secret() → K8sResourceScore │
|
||||
│ └── HelmChartScore → HelmChartInterpret │
|
||||
│ └── Installs rustfs/rustfs chart │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Future: Unified S3 Capability
|
||||
|
||||
This is the first step toward a unified S3 capability that will work with:
|
||||
- **RustFS** — local development (this example)
|
||||
- **Ceph RGW** — production S3 via Rook/Ceph
|
||||
- **AWS S3** — cloud-native S3
|
||||
|
||||
The pattern will be:
|
||||
|
||||
```rust
|
||||
// Future: unified S3 interface
|
||||
trait S3Store: Send + Sync {
|
||||
async fn deploy_bucket(&self, config: &BucketConfig) -> Result<(), String>;
|
||||
async fn get_endpoint(&self) -> Result<S3Endpoint, String>;
|
||||
}
|
||||
```
|
||||
|
||||
See the [Scores Catalog](../catalogs/scores.md) for related components.
|
||||
@@ -7,6 +7,7 @@ This directory contains runnable examples demonstrating Harmony's capabilities.
|
||||
| Example | Description | Local K3D | Existing Cluster | Hardware Needed |
|
||||
|---------|-------------|:---------:|:----------------:|:---------------:|
|
||||
| `postgresql` | Deploy a PostgreSQL cluster | ✅ | ✅ | — |
|
||||
| `rustfs` | Deploy a RustFS S3-compatible store | ✅ | ✅ | — |
|
||||
| `ntfy` | Deploy ntfy notification server | ✅ | ✅ | — |
|
||||
| `tenant` | Create a multi-tenant namespace | ✅ | ✅ | — |
|
||||
| `cert_manager` | Provision TLS certificates | ✅ | ✅ | — |
|
||||
@@ -52,6 +53,7 @@ This directory contains runnable examples demonstrating Harmony's capabilities.
|
||||
- **`postgresql`** — Deploy a PostgreSQL cluster via CloudNativePG
|
||||
- **`multisite_postgres`** — Multi-site PostgreSQL with failover
|
||||
- **`public_postgres`** — Public-facing PostgreSQL (⚠️ uses NationTech DNS)
|
||||
- **`rustfs`** — Deploy a RustFS S3-compatible object store
|
||||
|
||||
### Kubernetes Utilities
|
||||
- **`node_health`** — Check node health in a cluster
|
||||
|
||||
13
examples/rustfs/Cargo.toml
Normal file
13
examples/rustfs/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "example-rustfs"
|
||||
edition = "2024"
|
||||
version.workspace = true
|
||||
readme.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
harmony = { path = "../../harmony" }
|
||||
harmony_cli = { path = "../../harmony_cli" }
|
||||
harmony_types = { path = "../../harmony_types" }
|
||||
tokio = { workspace = true }
|
||||
25
examples/rustfs/src/main.rs
Normal file
25
examples/rustfs/src/main.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use harmony::{
|
||||
inventory::Inventory,
|
||||
modules::rustfs::{K8sRustFsScore, RustFsConfig},
|
||||
topology::K8sAnywhereTopology,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let rustfs = K8sRustFsScore {
|
||||
config: RustFsConfig {
|
||||
release_name: "harmony-rustfs".to_string(),
|
||||
namespace: "harmony-rustfs".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
harmony_cli::run(
|
||||
Inventory::autoload(),
|
||||
K8sAnywhereTopology::from_env(),
|
||||
vec![Box::new(rustfs)],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
@@ -21,6 +21,7 @@ pub mod openbao;
|
||||
pub mod opnsense;
|
||||
pub mod postgresql;
|
||||
pub mod prometheus;
|
||||
pub mod rustfs;
|
||||
pub mod storage;
|
||||
pub mod tenant;
|
||||
pub mod tftp;
|
||||
|
||||
47
harmony/src/modules/rustfs/capability.rs
Normal file
47
harmony/src/modules/rustfs/capability.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use async_trait::async_trait;
|
||||
use harmony_types::storage::StorageSize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct RustFsConfig {
|
||||
pub release_name: String,
|
||||
pub namespace: String,
|
||||
pub storage_size: StorageSize,
|
||||
pub mode: RustFsMode,
|
||||
pub access_key: Option<String>,
|
||||
pub secret_key: Option<String>,
|
||||
pub ingress_class: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for RustFsConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
release_name: "rustfs".to_string(),
|
||||
namespace: "harmony-rustfs".to_string(),
|
||||
storage_size: StorageSize::gi(1),
|
||||
mode: RustFsMode::Standalone,
|
||||
access_key: None,
|
||||
secret_key: None,
|
||||
ingress_class: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub enum RustFsMode {
|
||||
Standalone,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait RustFs: Send + Sync {
|
||||
async fn deploy(&self, config: &RustFsConfig) -> Result<String, String>;
|
||||
async fn get_endpoint(&self, config: &RustFsConfig) -> Result<RustFsEndpoint, String>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RustFsEndpoint {
|
||||
pub s3_endpoint: String,
|
||||
pub console_endpoint: String,
|
||||
pub access_key: String,
|
||||
pub secret_key: String,
|
||||
}
|
||||
6
harmony/src/modules/rustfs/mod.rs
Normal file
6
harmony/src/modules/rustfs/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
pub mod capability;
|
||||
mod score;
|
||||
mod score_k8s;
|
||||
pub use capability::*;
|
||||
pub use score::*;
|
||||
pub use score_k8s::*;
|
||||
85
harmony/src/modules/rustfs/score.rs
Normal file
85
harmony/src/modules/rustfs/score.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use async_trait::async_trait;
|
||||
use harmony_types::id::Id;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::data::Version;
|
||||
use crate::interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome};
|
||||
use crate::inventory::Inventory;
|
||||
use crate::modules::rustfs::capability::{RustFs, RustFsConfig};
|
||||
use crate::score::Score;
|
||||
use crate::topology::Topology;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct RustFsScore {
|
||||
pub config: RustFsConfig,
|
||||
}
|
||||
|
||||
impl Default for RustFsScore {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
config: RustFsConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustFsScore {
|
||||
pub fn new(namespace: &str) -> Self {
|
||||
Self {
|
||||
config: RustFsConfig {
|
||||
namespace: namespace.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + RustFs + Send + Sync> Score<T> for RustFsScore {
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(RustFsInterpret {
|
||||
config: self.config.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!(
|
||||
"RustFsScore({}:{})",
|
||||
self.config.namespace, self.config.release_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RustFsInterpret {
|
||||
config: RustFsConfig,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + RustFs + Send + Sync> Interpret<T> for RustFsInterpret {
|
||||
fn get_name(&self) -> InterpretName {
|
||||
InterpretName::Custom("RustFsInterpret")
|
||||
}
|
||||
|
||||
fn get_version(&self) -> Version {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_status(&self) -> InterpretStatus {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_children(&self) -> Vec<Id> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn execute(&self, _inventory: &Inventory, topo: &T) -> Result<Outcome, InterpretError> {
|
||||
let release_name = topo
|
||||
.deploy(&self.config)
|
||||
.await
|
||||
.map_err(|e| InterpretError::new(e))?;
|
||||
|
||||
Ok(Outcome::success(format!(
|
||||
"RustFS '{}' deployed in namespace '{}'",
|
||||
release_name, self.config.namespace
|
||||
)))
|
||||
}
|
||||
}
|
||||
285
harmony/src/modules/rustfs/score_k8s.rs
Normal file
285
harmony/src/modules/rustfs/score_k8s.rs
Normal file
@@ -0,0 +1,285 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::data::Version;
|
||||
use crate::interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome};
|
||||
use crate::inventory::Inventory;
|
||||
use crate::modules::helm::chart::{HelmChartScore, HelmRepository};
|
||||
use crate::modules::k8s::resource::K8sResourceScore;
|
||||
use crate::modules::rustfs::capability::{RustFs, RustFsConfig, RustFsEndpoint, RustFsMode};
|
||||
use crate::score::Score;
|
||||
use crate::topology::{HelmCommand, K8sclient, Topology};
|
||||
use async_trait::async_trait;
|
||||
use harmony_types::id::Id;
|
||||
use harmony_types::net::Url;
|
||||
use k8s_openapi::api::core::v1::Secret;
|
||||
use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
|
||||
use k8s_openapi::ByteString;
|
||||
use log::info;
|
||||
use non_blank_string_rs::NonBlankString;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct K8sRustFsScore {
|
||||
pub config: RustFsConfig,
|
||||
}
|
||||
|
||||
impl Default for K8sRustFsScore {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
config: RustFsConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl K8sRustFsScore {
|
||||
pub fn new(namespace: &str) -> Self {
|
||||
Self {
|
||||
config: RustFsConfig {
|
||||
namespace: namespace.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Topology + K8sclient + HelmCommand + 'static> Score<T> for K8sRustFsScore {
|
||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||
Box::new(K8sRustFsInterpret {
|
||||
config: self.config.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("K8sRustFsScore({})", self.config.namespace)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct K8sRustFsInterpret {
|
||||
config: RustFsConfig,
|
||||
}
|
||||
|
||||
impl K8sRustFsInterpret {
|
||||
async fn ensure_namespace<T: Topology + K8sclient>(
|
||||
&self,
|
||||
topology: &T,
|
||||
) -> Result<(), InterpretError> {
|
||||
let k8s_client = topology
|
||||
.k8s_client()
|
||||
.await
|
||||
.map_err(|e| InterpretError::new(format!("Failed to get k8s client: {}", e)))?;
|
||||
|
||||
let namespace_name = &self.config.namespace;
|
||||
|
||||
if k8s_client
|
||||
.namespace_exists(namespace_name)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
InterpretError::new(format!(
|
||||
"Failed to check namespace '{}': {}",
|
||||
namespace_name, e
|
||||
))
|
||||
})?
|
||||
{
|
||||
info!("Namespace '{}' already exists", namespace_name);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
info!("Creating namespace '{}'", namespace_name);
|
||||
k8s_client
|
||||
.create_namespace(namespace_name)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
InterpretError::new(format!(
|
||||
"Failed to create namespace '{}': {}",
|
||||
namespace_name, e
|
||||
))
|
||||
})?;
|
||||
|
||||
k8s_client
|
||||
.wait_for_namespace(namespace_name, Some(std::time::Duration::from_secs(30)))
|
||||
.await
|
||||
.map_err(|e| {
|
||||
InterpretError::new(format!("Namespace '{}' not ready: {}", namespace_name, e))
|
||||
})?;
|
||||
|
||||
info!("Namespace '{}' is ready", namespace_name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn ensure_secret<T: Topology + K8sclient>(
|
||||
&self,
|
||||
topology: &T,
|
||||
) -> Result<(), InterpretError> {
|
||||
let access_key = self.config.access_key.as_deref().unwrap_or("rustfsadmin");
|
||||
let secret_key = self.config.secret_key.as_deref().unwrap_or("rustfsadmin");
|
||||
|
||||
let k8s_client = topology
|
||||
.k8s_client()
|
||||
.await
|
||||
.map_err(|e| InterpretError::new(format!("Failed to get k8s client: {}", e)))?;
|
||||
|
||||
let namespace_name = &self.config.namespace;
|
||||
let secret_name = format!("{}-credentials", self.config.release_name);
|
||||
|
||||
let secret_exists = k8s_client
|
||||
.get_secret_json_value(&secret_name, Some(namespace_name))
|
||||
.await
|
||||
.is_ok();
|
||||
|
||||
if secret_exists {
|
||||
info!(
|
||||
"Secret '{}' already exists in namespace '{}'",
|
||||
secret_name, namespace_name
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
info!("Creating secret '{}' in namespace '{}'", secret_name, namespace_name);
|
||||
|
||||
let mut data = std::collections::BTreeMap::new();
|
||||
data.insert(
|
||||
"access_key".to_string(),
|
||||
ByteString(access_key.as_bytes().to_vec()),
|
||||
);
|
||||
data.insert(
|
||||
"secret_key".to_string(),
|
||||
ByteString(secret_key.as_bytes().to_vec()),
|
||||
);
|
||||
|
||||
let secret = Secret {
|
||||
metadata: ObjectMeta {
|
||||
name: Some(secret_name.clone()),
|
||||
namespace: Some(namespace_name.clone()),
|
||||
..ObjectMeta::default()
|
||||
},
|
||||
data: Some(data),
|
||||
string_data: None,
|
||||
type_: Some("Opaque".to_string()),
|
||||
..Secret::default()
|
||||
};
|
||||
|
||||
K8sResourceScore::single(secret, Some(namespace_name.clone()))
|
||||
.create_interpret()
|
||||
.execute(&Inventory::empty(), topology)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_values_yaml(&self) -> String {
|
||||
let storage_size = self.config.storage_size.to_string();
|
||||
let ingress_class = self.config.ingress_class.as_deref().unwrap_or("nginx");
|
||||
|
||||
let mode_yaml = match self.config.mode {
|
||||
RustFsMode::Standalone => {
|
||||
"mode:\n standalone:\n enabled: true\n distributed:\n enabled: false"
|
||||
}
|
||||
};
|
||||
|
||||
format!(
|
||||
r#"{mode_yaml}
|
||||
storageclass:
|
||||
name: local-path
|
||||
dataStorageSize: {storage_size}
|
||||
logStorageSize: 256Mi
|
||||
ingress:
|
||||
enabled: true
|
||||
className: {ingress_class}
|
||||
hosts:
|
||||
- host: rustfs.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
secret:
|
||||
existingSecret: {release_name}-credentials
|
||||
"#,
|
||||
release_name = self.config.release_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Topology + K8sclient + HelmCommand + 'static> Interpret<T> for K8sRustFsInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
_inventory: &Inventory,
|
||||
topology: &T,
|
||||
) -> Result<Outcome, InterpretError> {
|
||||
self.ensure_namespace(topology).await?;
|
||||
self.ensure_secret(topology).await?;
|
||||
|
||||
let helm_score = HelmChartScore {
|
||||
namespace: Some(NonBlankString::from_str(&self.config.namespace).unwrap()),
|
||||
release_name: NonBlankString::from_str(&self.config.release_name).unwrap(),
|
||||
chart_name: NonBlankString::from_str("rustfs/rustfs").unwrap(),
|
||||
chart_version: None,
|
||||
values_overrides: None,
|
||||
values_yaml: Some(self.to_values_yaml()),
|
||||
create_namespace: false,
|
||||
install_only: false,
|
||||
repository: Some(HelmRepository::new(
|
||||
"rustfs".to_string(),
|
||||
Url::Url(url::Url::parse("https://charts.rustfs.com").unwrap()),
|
||||
true,
|
||||
)),
|
||||
};
|
||||
|
||||
helm_score
|
||||
.create_interpret()
|
||||
.execute(&Inventory::empty(), topology)
|
||||
.await
|
||||
}
|
||||
|
||||
fn get_name(&self) -> InterpretName {
|
||||
InterpretName::Custom("K8sRustFsInterpret")
|
||||
}
|
||||
|
||||
fn get_version(&self) -> Version {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_status(&self) -> InterpretStatus {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_children(&self) -> Vec<Id> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct K8sAnywhereRustFs;
|
||||
|
||||
impl K8sAnywhereRustFs {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for K8sAnywhereRustFs {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl RustFs for K8sAnywhereRustFs {
|
||||
async fn deploy(&self, config: &RustFsConfig) -> Result<String, String> {
|
||||
Ok(config.release_name.clone())
|
||||
}
|
||||
|
||||
async fn get_endpoint(&self, config: &RustFsConfig) -> Result<RustFsEndpoint, String> {
|
||||
Ok(RustFsEndpoint {
|
||||
s3_endpoint: "http://rustfs.local:9000".to_string(),
|
||||
console_endpoint: "http://rustfs.local:9001".to_string(),
|
||||
access_key: config
|
||||
.access_key
|
||||
.clone()
|
||||
.unwrap_or_else(|| "rustfsadmin".to_string()),
|
||||
secret_key: config
|
||||
.secret_key
|
||||
.clone()
|
||||
.unwrap_or_else(|| "rustfsadmin".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user