From 932959bc5ce5c58270a235010a27e65b2a3e21a4 Mon Sep 17 00:00:00 2001 From: kjuulh Date: Wed, 20 Nov 2024 16:12:47 +0100 Subject: [PATCH] feat: add support for raw reading of variables Signed-off-by: kjuulh --- .../src/catalog/cluster_vars.rs | 125 +++++++++++++++++- .../src/catalog/cuddle_vars.rs | 5 +- .../tests/with_cluster_vars/cuddle.yaml | 6 +- .../with_cluster_vars/expected/dev/some.yaml | 4 + .../with_cluster_vars/expected/prod/some.yaml | 1 + .../templates/clusters/some.yaml.jinja2 | 9 ++ 6 files changed, 144 insertions(+), 6 deletions(-) diff --git a/crates/cuddle-clusters/src/catalog/cluster_vars.rs b/crates/cuddle-clusters/src/catalog/cluster_vars.rs index fadbeeb..1ca9676 100644 --- a/crates/cuddle-clusters/src/catalog/cluster_vars.rs +++ b/crates/cuddle-clusters/src/catalog/cluster_vars.rs @@ -1,7 +1,24 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; + +use serde_yaml::Value; use crate::Component; +use super::cuddle_vars::CuddleVariables; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum RawClusterVariable { + Map(RawClusterVariables), + List(RawClusterVariableList), + String(String), + Bool(bool), +} + +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct RawClusterVariables(BTreeMap); +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct RawClusterVariableList(Vec); + #[derive(PartialEq, Eq, Debug, Clone)] pub enum ClusterVariable { String(String), @@ -18,6 +35,9 @@ pub struct ClusterVariables { name: String, namespace: String, replicas: u64, + + raw: RawClusterVariables, + // raw: CuddleVariables, } #[derive(Default)] @@ -42,8 +62,6 @@ impl Component for ClusterVars { ..Default::default() }; - // TODO: actually extract values - if let Some(mapping) = value.as_mapping() { if let Some(env) = mapping.get("env") { if let Some(env_entries) = env.as_mapping() { @@ -63,6 +81,11 @@ impl Component for ClusterVars { } } } + // vars.raw = match value.clone().try_into() { + // Ok(o) => o, + // Err(e) => panic!("{}", e), + // }; + vars.raw = value.into(); vars.name = environment.into(); vars.namespace = environment.into(); @@ -78,6 +101,10 @@ impl minijinja::value::Object for ClusterVariables { "name" => minijinja::Value::from_safe_string(self.name.clone()), "namespace" => minijinja::Value::from_safe_string(self.namespace.clone()), "replicas" => minijinja::Value::from_safe_string(self.replicas.to_string()), + "raw" => { + tracing::info!("returning raw: {:?}", self.raw); + minijinja::Value::from_object(self.raw.clone()) + } _ => return None, }; @@ -103,3 +130,95 @@ impl minijinja::value::Object for ClusterEnv { ) } } + +impl From<&Value> for RawClusterVariables { + fn from(value: &Value) -> Self { + match value { + Value::Mapping(mapping) => RawClusterVariables( + mapping + .into_iter() + .map(|(k, v)| { + ( + k.as_str() + .expect("keys to always be valid strings") + .to_string(), + v.into(), + ) + }) + .collect(), + ), + Value::Null => RawClusterVariables::default(), + _ => todo!(), + } + } +} + +impl From<&Value> for RawClusterVariable { + fn from(value: &Value) -> Self { + match value { + Value::Null => Self::Map(RawClusterVariables::default()), + Value::Bool(b) => Self::Bool(*b), + Value::Number(number) => Self::String(number.to_string()), + Value::String(s) => Self::String(s.into()), + Value::Sequence(vec) => Self::List(RawClusterVariableList( + vec.iter().map(|i| i.into()).collect(), + )), + Value::Mapping(mapping) => Self::Map(RawClusterVariables( + mapping + .into_iter() + .map(|(k, v)| { + ( + k.as_str() + .expect("keys to always be valid strings") + .to_string(), + v.into(), + ) + }) + .collect(), + )), + Value::Tagged(_tagged_value) => todo!(), + } + } +} + +impl minijinja::value::Object for RawClusterVariables { + fn get_value(self: &std::sync::Arc, key: &minijinja::Value) -> Option { + self.0.get(key.as_str()?).map(|o| match o { + RawClusterVariable::Map(raw_cluster_variables) => { + minijinja::Value::from_object(raw_cluster_variables.clone()) + } + RawClusterVariable::List(list) => minijinja::Value::from_object(list.clone()), + RawClusterVariable::String(s) => minijinja::Value::from_safe_string(s.clone()), + RawClusterVariable::Bool(b) => minijinja::Value::from_safe_string(b.to_string()), + }) + } + + fn enumerate(self: &std::sync::Arc) -> minijinja::value::Enumerator { + minijinja::value::Enumerator::Values( + self.0 + .keys() + .map(|key| minijinja::Value::from_safe_string(key.clone())) + .collect::>(), + ) + } +} + +impl minijinja::value::Object for RawClusterVariableList { + fn enumerate(self: &std::sync::Arc) -> minijinja::value::Enumerator { + minijinja::value::Enumerator::Values( + self.0 + .iter() + .map(|i| match i { + RawClusterVariable::Map(raw_cluster_variables) => { + minijinja::Value::from_object(raw_cluster_variables.clone()) + } + RawClusterVariable::List(list) => minijinja::Value::from_object(list.clone()), + RawClusterVariable::String(s) => minijinja::Value::from_safe_string(s.clone()), + RawClusterVariable::Bool(b) => { + minijinja::Value::from_safe_string(b.to_string()) + } + }) + .collect(), + ) + } +} diff --git a/crates/cuddle-clusters/src/catalog/cuddle_vars.rs b/crates/cuddle-clusters/src/catalog/cuddle_vars.rs index a9e6c12..bdf568f 100644 --- a/crates/cuddle-clusters/src/catalog/cuddle_vars.rs +++ b/crates/cuddle-clusters/src/catalog/cuddle_vars.rs @@ -34,12 +34,13 @@ impl TryFrom for CuddleVariable { serde_yaml::Value::String(s) => Ok(Self::String(s)), serde_yaml::Value::Number(num) => Ok(Self::String(num.to_string())), serde_yaml::Value::Bool(bool) => Ok(Self::String(bool.to_string())), + serde_yaml::Value::Null => Ok(Self::Object(Box::default())), _ => Err(anyhow::anyhow!("cannot handle type of serde value")), } } } -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone, Default)] pub struct CuddleVariables(pub HashMap); impl TryFrom for CuddleVariables { @@ -68,7 +69,7 @@ impl TryFrom for CuddleVariables { fn try_from(value: serde_yaml::Value) -> Result { match value { - serde_yaml::Value::Null => anyhow::bail!("cannot handle null"), + serde_yaml::Value::Null => Ok(Self::default()), serde_yaml::Value::Bool(_) => anyhow::bail!("cannot handle bool"), serde_yaml::Value::Number(_) => anyhow::bail!("cannot handle number"), serde_yaml::Value::String(_) => anyhow::bail!("cannot handle string"), diff --git a/crates/cuddle-clusters/tests/with_cluster_vars/cuddle.yaml b/crates/cuddle-clusters/tests/with_cluster_vars/cuddle.yaml index 015809a..49e83a1 100644 --- a/crates/cuddle-clusters/tests/with_cluster_vars/cuddle.yaml +++ b/crates/cuddle-clusters/tests/with_cluster_vars/cuddle.yaml @@ -3,10 +3,14 @@ vars: cuddle/clusters: dev: replicas: 1 + list: + - listItem: listValue env: + vault: true something.something: something something: - # ignored + something: "something" vault: true prod: env: + diff --git a/crates/cuddle-clusters/tests/with_cluster_vars/expected/dev/some.yaml b/crates/cuddle-clusters/tests/with_cluster_vars/expected/dev/some.yaml index 3b221a4..bf34443 100644 --- a/crates/cuddle-clusters/tests/with_cluster_vars/expected/dev/some.yaml +++ b/crates/cuddle-clusters/tests/with_cluster_vars/expected/dev/some.yaml @@ -3,3 +3,7 @@ namespace: dev replicas: 1 items: - something.something +listValue + + +something: something diff --git a/crates/cuddle-clusters/tests/with_cluster_vars/expected/prod/some.yaml b/crates/cuddle-clusters/tests/with_cluster_vars/expected/prod/some.yaml index caf56ca..2359c22 100644 --- a/crates/cuddle-clusters/tests/with_cluster_vars/expected/prod/some.yaml +++ b/crates/cuddle-clusters/tests/with_cluster_vars/expected/prod/some.yaml @@ -2,3 +2,4 @@ name: prod namespace: prod replicas: 3 items: + diff --git a/crates/cuddle-clusters/tests/with_cluster_vars/templates/clusters/some.yaml.jinja2 b/crates/cuddle-clusters/tests/with_cluster_vars/templates/clusters/some.yaml.jinja2 index f3c364f..0981cb7 100644 --- a/crates/cuddle-clusters/tests/with_cluster_vars/templates/clusters/some.yaml.jinja2 +++ b/crates/cuddle-clusters/tests/with_cluster_vars/templates/clusters/some.yaml.jinja2 @@ -6,3 +6,12 @@ items: - {{val}} {%- endfor %} +{%- if vars.cluster_vars.raw.list -%} +{%- for val in vars.cluster_vars.raw.list %} +{{ val.listItem }} +{%- endfor -%} +{%- endif %} + +{% if vars.cluster_vars.raw.env.something %} +something: {{ vars.cluster_vars.raw.env.something.something }} +{% endif %}