Files
cuddle-clusters/crates/cuddle-clusters/src/catalog/ingress.rs
kjuulh e5db5d8a0f
Some checks failed
continuous-integration/drone/push Build is failing
feat: add actual grpc service
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-05-29 23:04:52 +02:00

173 lines
5.0 KiB
Rust

use std::path::Path;
use minijinja::{context, syntax::SyntaxConfig};
use crate::Component;
use super::cuddle_vars::{load_cuddle_file, CuddleVariable, CuddleVariables};
pub enum IngressType {
External,
Internal,
ExternalGrpc,
InternalGrpc,
}
pub struct Ingress {
variables: CuddleVariables,
}
impl Ingress {
pub async fn new(path: &Path) -> anyhow::Result<Self> {
let variables = load_cuddle_file(path).await?;
Ok(Self { variables })
}
fn render_ingress_types(
&self,
ingress_types: Vec<IngressType>,
) -> anyhow::Result<(String, String)> {
let mut templates = Vec::new();
let internal_template = r#"
{%- set service_name = vars.cuddle_vars.service %}
{%- set host_name = vars.cuddle_vars.service | replace("_", "-") | replace(".", "-") %}
<%- macro host() -%>
<% if connection_type is defined %><<connection_type>>.<% endif %>{{ host_name }}.{{ environment }}.<< base_host >>
<%- endmacro %>
<%- macro k8s_service() -%>
<%- if connection_type == "grpc" -%>
{{ service_name }}-grpc
<%- else -%>
{{ service_name }}
<%- endif -%>
<%- endmacro %>
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: << issuer >>
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: {{ service_name }}
cluster: {{ vars.cluster_vars.name }}
name: {{ service_name }}-<< name >>
namespace: {{ vars.cluster_vars.namespace }}
spec:
rules:
- host: << host() >>
http:
paths:
- backend:
service:
name: << k8s_service() >>
port:
name: << name >>
path: /
pathType: Prefix
tls:
- hosts:
- << host() >>
secretName: tls-{{ service_name }}-<< issuer >>-<< name >>-ingress-dns
"#;
let get_template = |name, base_host, connection_type| {
let mut env = minijinja::Environment::new();
env.set_syntax(
SyntaxConfig::builder()
.block_delimiters("<%", "%>")
.variable_delimiters("<<", ">>")
.comment_delimiters("<#", "#>")
.build()
.expect("to be able to build minijinja syntax"),
);
env.add_global("name", name);
env.add_global("base_host", base_host);
if let Some(connection_type) = connection_type {
env.add_global("connection_type", connection_type);
}
env.add_global("issuer", "kjuulh-app");
env.render_named_str("ingress.yaml", internal_template, context! {})
};
for ingress_type in ingress_types {
match ingress_type {
IngressType::External => {
templates.push(get_template("external-http", "kjuulh.app", None)?)
}
IngressType::Internal => {
templates.push(get_template("internal-http", "internal.kjuulh.app", None)?)
}
IngressType::ExternalGrpc => {
templates.push(get_template("external-grpc", "kjuulh.app", Some("grpc"))?)
}
IngressType::InternalGrpc => templates.push(get_template(
"internal-grpc",
"internal.kjuulh.app",
Some("grpc"),
)?),
}
}
Ok(("ingress.yaml".into(), templates.join("\n")))
}
}
impl Component for Ingress {
fn name(&self) -> String {
"cuddle/ingress".to_string()
}
fn render(
&self,
_environment: &str,
_value: &serde_yaml::Value,
) -> Option<anyhow::Result<(String, String)>> {
if let Some(ingress_types) = self
.variables
.0
.get("ingress")
.and_then(|v| match v {
CuddleVariable::Array(a) => Some(a),
_ => None,
})
.map(|o| {
let mut types = Vec::new();
for value in o {
match value {
CuddleVariable::Object(o) => {
if o.0.contains_key("external") {
types.push(IngressType::External)
} else if o.0.contains_key("internal") {
types.push(IngressType::Internal)
} else if o.0.contains_key("external_grpc") {
types.push(IngressType::ExternalGrpc)
} else if o.0.contains_key("internal_grpc") {
types.push(IngressType::InternalGrpc)
} else {
continue;
}
}
_ => continue,
}
}
types
})
{
return Some(self.render_ingress_types(ingress_types));
}
None
}
}