diff --git a/crates/cuddle-clusters/src/catalog.rs b/crates/cuddle-clusters/src/catalog.rs index 8e497ef..cae0791 100644 --- a/crates/cuddle-clusters/src/catalog.rs +++ b/crates/cuddle-clusters/src/catalog.rs @@ -1,134 +1,3 @@ pub mod cluster_vars; pub mod cuddle_vars; -pub mod vault_secret { - use minijinja::{value::Object, Value}; - - use crate::Component; - - #[derive(Debug)] - pub struct VaultSecretValues { - name: String, - secrets: VaultSecretsLookup, - } - - #[derive(Debug, Clone)] - pub struct VaultSecretsLookup { - secrets: Vec, - } - - impl From> for VaultSecretsLookup { - fn from(value: Vec) -> Self { - Self { secrets: value } - } - } - - #[derive(Default, Clone)] - pub struct VaultSecret {} - - impl Component for VaultSecret { - fn name(&self) -> String { - "vault/secret".into() - } - - fn validate(&self, value: &serde_yaml::Value) -> anyhow::Result<()> { - Ok(()) - } - - fn render_value( - &self, - environment: &str, - value: &serde_yaml::Value, - ) -> Option> { - if let Some(values) = value - .as_mapping() - .and_then(|map| map.get("env")) - .and_then(|v| v.as_mapping()) - .map(|v| { - v.iter() - .filter_map(|(k, v)| { - if v.as_mapping() - .map(|m| m.get("vault").filter(|v| v.as_bool() == Some(true))) - .is_some() - { - Some(k) - } else { - None - } - }) - .filter_map(|k| k.as_str()) - .collect::>() - }) - { - let vault_values = VaultSecretValues { - name: self.name().replace("/", "-"), - secrets: values - .into_iter() - .map(|i| i.into()) - .collect::>() - .into(), - }; - - return Some(Ok(minijinja::Value::from_object(vault_values))); - } - - None - } - - fn render( - &self, - _environment: &str, - _value: &serde_yaml::Value, - ) -> Option> { - Some(Ok(( - format!("{}.yaml", self.name().replace("/", "_")), - r#"apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: {{ vars.cuddle_vars.service }}-{{ vars.vault_secret.name }} - namespace: {{ vars.cluster_vars.namespace }} -spec: - destination: - create: true - name: {{ vars.cuddle_vars.service }}-{{ vars.vault_secret.name }} - mount: kvv2 - path: {{ vars.cuddle_vars.service }}/{{ environment }} - refreshAfter: 30s - type: kv-v2 -"# - .into(), - ))) - } - } - - impl Object for VaultSecretValues { - fn get_value( - self: &std::sync::Arc, - key: &minijinja::Value, - ) -> Option { - let name = self.name.clone(); - let obj = match key.as_str()? { - "name" => Value::from_safe_string(self.name.clone()), - "secrets" => Value::from_object(self.secrets.clone()), - "has_values" => Value::from_serialize(!self.secrets.secrets.is_empty()), - "file_name" => Value::from_function(move |file_name: String| { - format!("{}-{}", file_name, name.replace("/", "-")) - }), - _ => return None, - }; - - Some(obj) - } - } - - impl Object for VaultSecretsLookup { - fn get_value(self: &std::sync::Arc, key: &Value) -> Option { - let idx = key.as_usize()?; - - self.secrets.get(idx).cloned().map(Value::from_safe_string) - } - - fn enumerate(self: &std::sync::Arc) -> minijinja::value::Enumerator { - minijinja::value::Enumerator::Seq(self.secrets.len()) - } - } -} +pub mod vault_secret; diff --git a/crates/cuddle-clusters/src/catalog/vault_secret.rs b/crates/cuddle-clusters/src/catalog/vault_secret.rs new file mode 100644 index 0000000..64f9db7 --- /dev/null +++ b/crates/cuddle-clusters/src/catalog/vault_secret.rs @@ -0,0 +1,127 @@ +use minijinja::{value::Object, Value}; + +use crate::Component; + +#[derive(Debug)] +pub struct VaultSecretValues { + name: String, + secrets: VaultSecretsLookup, +} + +#[derive(Debug, Clone)] +pub struct VaultSecretsLookup { + secrets: Vec, +} + +impl From> for VaultSecretsLookup { + fn from(value: Vec) -> Self { + Self { secrets: value } + } +} + +#[derive(Default, Clone)] +pub struct VaultSecret {} + +impl Component for VaultSecret { + fn name(&self) -> String { + "vault/secret".into() + } + + fn validate(&self, value: &serde_yaml::Value) -> anyhow::Result<()> { + Ok(()) + } + + fn render_value( + &self, + environment: &str, + value: &serde_yaml::Value, + ) -> Option> { + if let Some(values) = value + .as_mapping() + .and_then(|map| map.get("env")) + .and_then(|v| v.as_mapping()) + .map(|v| { + v.iter() + .filter_map(|(k, v)| { + if v.as_mapping() + .map(|m| m.get("vault").filter(|v| v.as_bool() == Some(true))) + .is_some() + { + Some(k) + } else { + None + } + }) + .filter_map(|k| k.as_str()) + .collect::>() + }) + { + let vault_values = VaultSecretValues { + name: self.name().replace("/", "-"), + secrets: values + .into_iter() + .map(|i| i.into()) + .collect::>() + .into(), + }; + + return Some(Ok(minijinja::Value::from_object(vault_values))); + } + + None + } + + fn render( + &self, + _environment: &str, + _value: &serde_yaml::Value, + ) -> Option> { + Some(Ok(( + format!("{}.yaml", self.name().replace("/", "_")), + r#"apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: {{ vars.cuddle_vars.service }}-{{ vars.vault_secret.name }} + namespace: {{ vars.cluster_vars.namespace }} +spec: + destination: + create: true + name: {{ vars.cuddle_vars.service }}-{{ vars.vault_secret.name }} + mount: kvv2 + path: {{ vars.cuddle_vars.service }}/{{ environment }} + refreshAfter: 30s + type: kv-v2 +"# + .into(), + ))) + } +} + +impl Object for VaultSecretValues { + fn get_value(self: &std::sync::Arc, key: &minijinja::Value) -> Option { + let name = self.name.clone(); + let obj = match key.as_str()? { + "name" => Value::from_safe_string(self.name.clone()), + "secrets" => Value::from_object(self.secrets.clone()), + "has_values" => Value::from_serialize(!self.secrets.secrets.is_empty()), + "file_name" => Value::from_function(move |file_name: String| { + format!("{}-{}", file_name, name.replace("/", "-")) + }), + _ => return None, + }; + + Some(obj) + } +} + +impl Object for VaultSecretsLookup { + fn get_value(self: &std::sync::Arc, key: &Value) -> Option { + let idx = key.as_usize()?; + + self.secrets.get(idx).cloned().map(Value::from_safe_string) + } + + fn enumerate(self: &std::sync::Arc) -> minijinja::value::Enumerator { + minijinja::value::Enumerator::Seq(self.secrets.len()) + } +}