feat: add actual example
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
461f8acb73
commit
f27d538b38
@ -1 +1,2 @@
|
|||||||
|
pub mod cluster_vars;
|
||||||
pub mod cuddle_vars;
|
pub mod cuddle_vars;
|
||||||
|
94
crates/cuddle-clusters/src/catalog/cluster_vars.rs
Normal file
94
crates/cuddle-clusters/src/catalog/cluster_vars.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::Component;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub enum ClusterVariable {
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone, Default)]
|
||||||
|
pub struct ClusterEnv {
|
||||||
|
vars: HashMap<String, ClusterVariable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone, Default)]
|
||||||
|
pub struct ClusterVariables {
|
||||||
|
env: ClusterEnv,
|
||||||
|
name: String,
|
||||||
|
namespace: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ClusterVars {}
|
||||||
|
|
||||||
|
impl Component for ClusterVars {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"cluster/vars".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _value: &serde_yaml::Value) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_value(
|
||||||
|
&self,
|
||||||
|
environment: &str,
|
||||||
|
value: &serde_yaml::Value,
|
||||||
|
) -> Option<anyhow::Result<minijinja::Value>> {
|
||||||
|
let mut vars = ClusterVariables::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() {
|
||||||
|
for (name, value) in env_entries {
|
||||||
|
if let (Some(name), Some(value)) = (name.as_str(), value.as_str()) {
|
||||||
|
vars.env
|
||||||
|
.vars
|
||||||
|
.insert(name.to_string(), ClusterVariable::String(value.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.name = environment.into();
|
||||||
|
vars.namespace = environment.into();
|
||||||
|
|
||||||
|
Some(Ok(minijinja::Value::from_object(vars)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minijinja::value::Object for ClusterVariables {
|
||||||
|
fn get_value(self: &std::sync::Arc<Self>, key: &minijinja::Value) -> Option<minijinja::Value> {
|
||||||
|
let out = match key.as_str()? {
|
||||||
|
"env" => minijinja::Value::from_object(self.env.clone()),
|
||||||
|
"name" => minijinja::Value::from_safe_string(self.name.clone()),
|
||||||
|
"namespace" => minijinja::Value::from_safe_string(self.namespace.clone()),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minijinja::value::Object for ClusterEnv {
|
||||||
|
fn get_value(self: &std::sync::Arc<Self>, key: &minijinja::Value) -> Option<minijinja::Value> {
|
||||||
|
let var = self.vars.get(key.as_str()?)?;
|
||||||
|
|
||||||
|
match var {
|
||||||
|
ClusterVariable::String(s) => Some(minijinja::Value::from_safe_string(s.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate(self: &std::sync::Arc<Self>) -> minijinja::value::Enumerator {
|
||||||
|
minijinja::value::Enumerator::Values(
|
||||||
|
self.vars
|
||||||
|
.keys()
|
||||||
|
.map(|key| minijinja::Value::from_safe_string(key.clone()))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -134,7 +134,11 @@ impl Component for CuddleVars {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_value(&self, _value: &serde_yaml::Value) -> Option<anyhow::Result<minijinja::Value>> {
|
fn render_value(
|
||||||
|
&self,
|
||||||
|
environment: &str,
|
||||||
|
_value: &serde_yaml::Value,
|
||||||
|
) -> Option<anyhow::Result<minijinja::Value>> {
|
||||||
Some(Ok(minijinja::Value::from_object(self.variables.clone())))
|
Some(Ok(minijinja::Value::from_object(self.variables.clone())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,20 @@ pub trait Component {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_value(&self, _value: &serde_yaml::Value) -> Option<anyhow::Result<minijinja::Value>> {
|
fn render_value(
|
||||||
|
&self,
|
||||||
|
environment: &str,
|
||||||
|
_value: &serde_yaml::Value,
|
||||||
|
) -> Option<anyhow::Result<minijinja::Value>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// First return is name, second is contents
|
/// First return is name, second is contents
|
||||||
fn render(&self, _value: &serde_yaml::Value) -> Option<anyhow::Result<(String, String)>> {
|
fn render(
|
||||||
|
&self,
|
||||||
|
environment: &str,
|
||||||
|
_value: &serde_yaml::Value,
|
||||||
|
) -> Option<anyhow::Result<(String, String)>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ async fn read_cuddle_section(path: &Path) -> anyhow::Result<CuddleClusters> {
|
|||||||
Ok(cuddle_clusters)
|
Ok(cuddle_clusters)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
struct TemplateFiles {
|
struct TemplateFiles {
|
||||||
templates: HashMap<String, PathBuf>,
|
templates: HashMap<String, PathBuf>,
|
||||||
raw: HashMap<String, PathBuf>,
|
raw: HashMap<String, PathBuf>,
|
||||||
@ -124,27 +124,33 @@ fn load_template_files(path: &Path) -> BoxFuture<'static, anyhow::Result<Templat
|
|||||||
let template_path = path.join(TEMPLATES_PATH_PREFIX);
|
let template_path = path.join(TEMPLATES_PATH_PREFIX);
|
||||||
let path = path.to_path_buf();
|
let path = path.to_path_buf();
|
||||||
|
|
||||||
tracing::info!("reading folder: {}", path.display());
|
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let templates = read_dir(&template_path)
|
if template_path.exists() {
|
||||||
.await?
|
let templates = read_dir(&template_path)
|
||||||
.into_iter()
|
.await?
|
||||||
.filter(|(_, i)| i.extension().and_then(|e| e.to_str()) == Some("jinja2"))
|
.into_iter()
|
||||||
.collect();
|
.filter(|(_, i)| i.extension().and_then(|e| e.to_str()) == Some("jinja2"))
|
||||||
let raw = read_dir(&template_path.join("raw"))
|
.collect();
|
||||||
.await
|
let raw = read_dir(&template_path.join("raw"))
|
||||||
.unwrap_or_default();
|
.await
|
||||||
let mut template_files = TemplateFiles { templates, raw };
|
.unwrap_or_default();
|
||||||
|
let mut template_files = TemplateFiles { templates, raw };
|
||||||
|
|
||||||
let nested_path = path.join(CUDDLE_PLAN_PATH_PREFIX);
|
let nested_path = path.join(CUDDLE_PLAN_PATH_PREFIX);
|
||||||
tracing::info!("trying to read: {}", nested_path.display());
|
if nested_path.exists() {
|
||||||
if nested_path.exists() {
|
let nested = load_template_files(&nested_path).await?;
|
||||||
let nested = load_template_files(&nested_path).await?;
|
template_files.merge(nested);
|
||||||
template_files.merge(nested);
|
}
|
||||||
|
Ok(template_files)
|
||||||
|
} else {
|
||||||
|
let nested_path = path.join(CUDDLE_PLAN_PATH_PREFIX);
|
||||||
|
if nested_path.exists() {
|
||||||
|
let nested = load_template_files(&nested_path).await?;
|
||||||
|
Ok(nested)
|
||||||
|
} else {
|
||||||
|
Ok(TemplateFiles::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(template_files)
|
|
||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
@ -245,7 +251,7 @@ async fn process_template_file(
|
|||||||
for component in components {
|
for component in components {
|
||||||
let name = component.name();
|
let name = component.name();
|
||||||
|
|
||||||
if let Some(value) = component.render_value(value) {
|
if let Some(value) = component.render_value(environment, value) {
|
||||||
let value = value?;
|
let value = value?;
|
||||||
|
|
||||||
variables.insert(name.replace("/", "_"), value);
|
variables.insert(name.replace("/", "_"), value);
|
||||||
|
@ -3,7 +3,10 @@ pub mod common;
|
|||||||
mod can_run_for_env;
|
mod can_run_for_env;
|
||||||
mod cuddle_vars;
|
mod cuddle_vars;
|
||||||
|
|
||||||
use cuddle_clusters::catalog::cuddle_vars::CuddleVars;
|
use cuddle_clusters::{
|
||||||
|
catalog::{cluster_vars::ClusterVars, cuddle_vars::CuddleVars},
|
||||||
|
IntoComponent,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::common::{run_test, run_test_with_components};
|
use crate::common::{run_test, run_test_with_components};
|
||||||
|
|
||||||
@ -60,3 +63,19 @@ async fn with_cuddle_vars() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn with_actual_deployment() -> anyhow::Result<()> {
|
||||||
|
let current_dir = std::env::current_dir()?.join("tests/with_cuddle_vars");
|
||||||
|
|
||||||
|
run_test_with_components(
|
||||||
|
"with_actual_deployment",
|
||||||
|
vec![
|
||||||
|
CuddleVars::new(¤t_dir).await?.into_component(),
|
||||||
|
ClusterVars::default().into_component(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
vars:
|
||||||
|
service: service
|
||||||
|
some:
|
||||||
|
nested:
|
||||||
|
item: something
|
||||||
|
array:
|
||||||
|
- item: item
|
||||||
|
|
||||||
|
|
||||||
|
cuddle/clusters:
|
||||||
|
dev:
|
||||||
|
env:
|
||||||
|
something: thing
|
||||||
|
nested.item: item
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: service-config
|
||||||
|
data:
|
||||||
|
environment:
|
||||||
|
NESTED_ITEM: item
|
||||||
|
SOMETHING: thing
|
@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: service
|
||||||
|
cluster: dev
|
||||||
|
name: service
|
||||||
|
namespace: dev
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: service
|
||||||
|
cluster: dev
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: service
|
||||||
|
cluster: dev
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- args:
|
||||||
|
- serve
|
||||||
|
command:
|
||||||
|
- service
|
||||||
|
image: kasperhermansen/service:main-1715336504
|
||||||
|
name: service
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: service-config
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
name: external-http
|
||||||
|
- containerPort: 3001
|
||||||
|
name: internal-http
|
||||||
|
- containerPort: 3002
|
||||||
|
name: internal-grpc
|
Loading…
Reference in New Issue
Block a user