use kube::CustomResource; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; #[derive(CustomResource, Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] #[kube( group = "irc.now", version = "v1alpha1", kind = "WebService", namespaced, status = "WebServiceStatus", shortname = "ws", printcolumn = r#"{"name":"Host", "type":"string", "jsonPath":".spec.host"}"#, printcolumn = r#"{"name":"Ready", "type":"string", "jsonPath":".status.conditions[?(@.type==\"Ready\")].status"}"# )] #[serde(rename_all = "camelCase")] pub struct WebServiceSpec { pub image: String, pub host: String, #[serde(default)] pub tls: Option, #[serde(default)] pub resources: Option, #[serde(default)] pub database: Option, #[serde(default)] pub oidc: Option, #[serde(default)] pub s3: Option, #[serde(default)] pub stripe: Option, #[serde(default)] pub service_account: Option, #[serde(default)] pub port: Option, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct TlsSpec { pub issuer_ref: IssuerRef, pub dns_names: Vec, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct IssuerRef { pub name: String, pub kind: String, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct ResourceRequirements { #[serde(default)] pub requests: Option, #[serde(default)] pub limits: Option, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct ResourceList { #[serde(default)] pub memory: Option, #[serde(default)] pub cpu: Option, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct DatabaseSpec { pub secret_ref: String, pub host: String, pub name: String, #[serde(default = "default_db_port")] pub port: i32, #[serde(default)] pub env_prefix: Option, } fn default_db_port() -> i32 { 5432 } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct OidcSpec { pub issuer_url: String, pub secret_ref: String, pub redirect_url: String, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct S3Spec { pub endpoint: String, pub bucket: String, pub credentials_secret: String, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct StripeSpec { pub secret_ref: String, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct WebServiceStatus { #[serde(default)] pub conditions: Vec, #[serde(default)] pub observed_generation: Option, } #[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)] pub struct Condition { #[serde(rename = "type")] pub type_: String, pub status: String, pub reason: String, pub message: String, pub last_transition_time: String, } #[cfg(test)] mod tests { use super::*; use kube::CustomResourceExt; #[test] fn crd_generates_valid_schema() { let crd = WebService::crd(); let name = crd.metadata.name.unwrap(); assert_eq!(name, "webservices.irc.now"); } #[test] fn default_spec_has_sane_values() { let spec = WebServiceSpec::default(); assert!(spec.database.is_none()); assert!(spec.oidc.is_none()); assert!(spec.s3.is_none()); assert!(spec.stripe.is_none()); assert!(spec.tls.is_none()); assert!(spec.resources.is_none()); assert!(spec.service_account.is_none()); } #[test] fn database_spec_defaults_port() { let db: DatabaseSpec = serde_json::from_str( r#"{"secret_ref":"test","host":"db","name":"test"}"#, ) .unwrap(); assert_eq!(db.port, 5432); } }