Compare commits

..

No commits in common. "main" and "v0.1.1" have entirely different histories.
main ... v0.1.1

25 changed files with 210 additions and 4344 deletions

3521
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,5 @@ tracing-subscriber = { version = "0.3.18" }
clap = { version = "4", features = ["derive", "env"] }
dotenv = { version = "0.15" }
flux-releaser = { git = "https://git.front.kjuulh.io/kjuulh/flux-releaser", branch = "main" }
[workspace.package]
version = "0.1.1"

View File

@ -17,11 +17,9 @@ uuid = { version = "1.7.0", features = ["v4"] }
serde_yaml = "0.9.34"
tokio-stream = { version = "0.1.15", features = ["full"] }
walkdir = "2.5.0"
minijinja = { version = "2.0.1", features = ["custom_syntax"] }
minijinja = "2.0.1"
futures = "0.3.30"
flux-releaser.workspace = true
[[test]]
name = "integration"
path = "tests/tests.rs"

View File

@ -1,5 +1,3 @@
pub mod cluster_vars;
pub mod crdb_database;
pub mod cuddle_vars;
pub mod ingress;
pub mod vault_secret;

View File

@ -1,131 +0,0 @@
use std::path::Path;
use minijinja::{value::Object, Value};
use crate::{catalog::cuddle_vars::CuddleVariable, Component};
use super::cuddle_vars::{load_cuddle_file, CuddleVariables};
pub struct CockroachDB {
variables: CuddleVariables,
}
impl CockroachDB {
pub async fn new(path: &Path) -> anyhow::Result<Self> {
let variables = load_cuddle_file(path).await?;
Ok(Self { variables })
}
}
impl Component for CockroachDB {
fn name(&self) -> String {
"cuddle/crdb".into()
}
fn render_value(
&self,
_environment: &str,
_value: &serde_yaml::Value,
) -> Option<anyhow::Result<minijinja::Value>> {
if let Some(true) = self
.variables
.0
.get("database")
.and_then(|v| match v {
CuddleVariable::Object(o) => Some(o),
_ => None,
})
.and_then(|o| o.0.get("crdb"))
.and_then(|o| match o {
CuddleVariable::String(o) => {
if o == "true" {
Some(true)
} else {
None
}
}
_ => None,
})
{
return Some(Ok(minijinja::Value::from_object(CockroachDBValues {
name: self.name(),
enabled: true,
})));
}
Some(Ok(minijinja::Value::from_object(CockroachDBValues {
name: self.name(),
enabled: false,
})))
}
fn render(
&self,
_environment: &str,
_value: &serde_yaml::Value,
) -> Option<anyhow::Result<(String, String)>> {
if let Some(true) = self
.variables
.0
.get("database")
.and_then(|v| match v {
CuddleVariable::Object(o) => Some(o),
_ => None,
})
.and_then(|o| o.0.get("crdb"))
.and_then(|o| match o {
CuddleVariable::String(o) => {
if o == "true" {
Some(true)
} else {
None
}
}
_ => None,
})
{
return Some(Ok((
format!("{}.yaml", self.name().replace("/", "-")),
r#"
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ vars.cuddle_crdb.file_name(vars.cuddle_vars.service) }}
namespace: {{ vars.cluster_vars.namespace }}
data:
DATABASE_URL: postgresql://root@{{environment}}-cluster:26257/{{ vars.cuddle_vars.service | replace("-", "_") }}
"#
.into(),
)));
}
None
}
}
#[derive(Debug)]
struct CockroachDBValues {
name: String,
enabled: bool,
}
impl Object for CockroachDBValues {
fn get_value(self: &std::sync::Arc<Self>, key: &minijinja::Value) -> Option<minijinja::Value> {
let name = self.name.clone();
match key.as_str()? {
"has_values" => {
if self.enabled {
Some(minijinja::Value::from_serialize(true))
} else {
Some(minijinja::Value::from_serialize(false))
}
}
"file_name" => Some(Value::from_function(move |file_name: String| {
format!("{}-{}", file_name, name.replace("/", "-"))
})),
"env" => Some(Value::from_serialize("DATABASE_URL")),
_ => None,
}
}
}

View File

@ -84,7 +84,7 @@ pub struct CuddleVars {
pub variables: CuddleVariables,
}
const PARENT_PLAN_PREFIX: &str = ".cuddle/base";
const PARENT_PLAN_PREFIX: &str = ".cuddle/plan";
const CUDDLE_FILE: &str = "cuddle.yaml";
impl CuddleVars {
@ -95,7 +95,7 @@ impl CuddleVars {
}
}
pub fn load_cuddle_file(path: &Path) -> BoxFuture<'static, anyhow::Result<CuddleVariables>> {
fn load_cuddle_file(path: &Path) -> BoxFuture<'static, anyhow::Result<CuddleVariables>> {
let path = path.to_path_buf();
async move {

View File

@ -1,172 +0,0 @@
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
}
}

View File

@ -68,42 +68,17 @@ impl Component for VaultSecret {
return Some(Ok(minijinja::Value::from_object(vault_values)));
}
Some(Ok(minijinja::Value::from_object(VaultSecretValues {
name: self.name().replace("/", "-"),
secrets: VaultSecretsLookup {
secrets: Vec::default(),
},
})))
None
}
fn render(
&self,
_environment: &str,
value: &serde_yaml::Value,
_value: &serde_yaml::Value,
) -> Option<anyhow::Result<(String, String)>> {
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::<Vec<_>>()
})
.map(|_| {
Ok((
format!("{}.yaml", self.name().replace("/", "_")),
r#"apiVersion: secrets.hashicorp.com/v1beta1
Some(Ok((
format!("{}.yaml", self.name().replace("/", "_")),
r#"apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: {{ vars.vault_secret.file_name(vars.cuddle_vars.service) }}
@ -117,9 +92,8 @@ spec:
refreshAfter: 30s
type: kv-v2
"#
.into(),
))
})
.into(),
)))
}
}

View File

@ -1,4 +1,4 @@
use std::sync::Arc;
use std::rc::Rc;
pub trait Component {
fn name(&self) -> String;
@ -27,11 +27,11 @@ pub trait Component {
#[derive(Clone)]
pub struct ConcreteComponent {
inner: Arc<dyn Component + Sync + Send + 'static>,
inner: Rc<dyn Component + 'static>,
}
impl std::ops::Deref for ConcreteComponent {
type Target = Arc<dyn Component + Sync + Send + 'static>;
type Target = Rc<dyn Component + 'static>;
fn deref(&self) -> &Self::Target {
&self.inner
@ -39,8 +39,8 @@ impl std::ops::Deref for ConcreteComponent {
}
impl ConcreteComponent {
pub fn new<T: Component + Sync + Send + 'static>(t: T) -> Self {
Self { inner: Arc::new(t) }
pub fn new<T: Component + 'static>(t: T) -> Self {
Self { inner: Rc::new(t) }
}
}
@ -54,7 +54,7 @@ impl IntoComponent for ConcreteComponent {
}
}
impl<T: Component + Sync + Send + 'static> IntoComponent for T {
impl<T: Component + 'static> IntoComponent for T {
fn into_component(self) -> ConcreteComponent {
ConcreteComponent::new(self)
}

View File

@ -7,5 +7,3 @@ pub mod catalog;
pub mod process;
pub use process::{process, process_opts};
pub mod releaser;

View File

@ -13,32 +13,12 @@ use tokio_stream::{wrappers::ReadDirStream, StreamExt};
use crate::components::{ConcreteComponent, IntoComponent};
pub async fn process() -> anyhow::Result<()> {
process_opts(
Vec::<ConcreteComponent>::new(),
ProcessOpts::default(),
None::<NoUploadStrategy>,
)
.await
}
pub trait UploadStrategy {
fn upload(&self, input_path: &Path) -> BoxFuture<'_, anyhow::Result<()>>;
}
#[derive(Default)]
pub struct NoUploadStrategy {}
impl UploadStrategy for NoUploadStrategy {
fn upload(&self, _input_path: &Path) -> BoxFuture<'_, anyhow::Result<()>> {
async move { Ok(()) }.boxed()
}
process_opts(Vec::<ConcreteComponent>::new(), ProcessOpts::default()).await
}
pub struct ProcessOpts {
pub path: PathBuf,
pub output: PathBuf,
pub variables: HashMap<String, String>,
}
impl Default for ProcessOpts {
@ -49,18 +29,16 @@ impl Default for ProcessOpts {
.expect("to be able to get current dir")
.join("cuddle-clusters")
.join("k8s"),
variables: HashMap::default(),
}
}
}
const TEMPLATES_PATH_PREFIX: &str = "templates/clusters";
const CUDDLE_PLAN_PATH_PREFIX: &str = ".cuddle/base";
const CUDDLE_PLAN_PATH_PREFIX: &str = ".cuddle/plan";
pub async fn process_opts(
components: impl IntoIterator<Item = impl IntoComponent>,
opts: ProcessOpts,
upload_strategy: Option<impl UploadStrategy>,
) -> anyhow::Result<()> {
let components = components
.into_iter()
@ -83,21 +61,10 @@ pub async fn process_opts(
let template_files = load_template_files(&path).await?;
tracing::debug!("found files: {:?}", template_files);
let _ = tokio::fs::remove_dir_all(&opts.output).await;
tokio::fs::remove_dir_all(&opts.output).await?;
tokio::fs::create_dir_all(&opts.output).await?;
process_templates(
&components,
&clusters,
&template_files,
&opts.output,
&opts.variables,
)
.await?;
if let Some(upload_strategy) = upload_strategy {
upload_strategy.upload(&opts.output).await?;
}
process_templates(&components, &clusters, &template_files, &opts.output).await?;
Ok(())
}
@ -217,7 +184,6 @@ async fn process_templates(
clusters: &CuddleClusters,
template_files: &TemplateFiles,
dest: &Path,
variables: &HashMap<String, String>,
) -> anyhow::Result<()> {
for (environment, value) in clusters.iter() {
process_cluster(
@ -226,7 +192,6 @@ async fn process_templates(
environment,
template_files,
&dest.join(environment),
variables,
)
.await?;
}
@ -240,18 +205,9 @@ async fn process_cluster(
environment: &str,
template_files: &TemplateFiles,
dest: &Path,
variables: &HashMap<String, String>,
) -> anyhow::Result<()> {
for (_, template_file) in &template_files.templates {
process_template_file(
components,
value,
environment,
template_file,
dest,
variables,
)
.await?;
process_template_file(components, value, environment, template_file, dest).await?;
}
for (template_file_name, template_content) in components
@ -272,7 +228,6 @@ async fn process_cluster(
&template_file_name,
&template_content,
dest,
variables,
)
.await?;
}
@ -290,7 +245,6 @@ async fn process_template_file(
environment: &str,
template_file: &PathBuf,
dest: &Path,
variables: &HashMap<String, String>,
) -> anyhow::Result<()> {
let file = tokio::fs::read_to_string(template_file)
.await
@ -306,7 +260,6 @@ async fn process_template_file(
&file_name.to_string_lossy(),
&file,
dest,
variables,
)
.await?;
@ -320,7 +273,6 @@ async fn process_render_template(
file_name: &str,
file_content: &str,
dest: &Path,
user_vars: &HashMap<String, String>,
) -> anyhow::Result<()> {
if !dest.exists() {
tokio::fs::create_dir_all(dest).await?;
@ -334,7 +286,6 @@ async fn process_render_template(
env.add_global("environment", environment);
let mut variables = HashMap::new();
for component in components {
let name = component.name();
@ -344,10 +295,6 @@ async fn process_render_template(
variables.insert(name.replace("/", "_"), value);
}
}
variables.insert(
"user_vars".into(),
minijinja::Value::from_serialize(user_vars),
);
let tmpl = env.get_template(file_name)?;
let rendered = tmpl.render(context! {

View File

@ -1,108 +0,0 @@
use std::{
path::{Path, PathBuf},
process::Command,
};
use anyhow::Context;
use flux_releaser::{
app::{LocalApp, SharedLocalApp},
services::flux_local_cluster::extensions::FluxLocalClusterManagerExt,
};
use futures::{future::BoxFuture, FutureExt};
use crate::process::UploadStrategy;
#[derive(Default, Clone)]
pub struct Releaser {
registry: String,
service: String,
}
impl Releaser {
pub fn with_registry(&mut self, registry: impl Into<String>) -> &mut Self {
self.registry = registry.into();
self
}
pub fn with_service(&mut self, service: impl Into<String>) -> &mut Self {
self.service = service.into();
self
}
pub async fn release(&self, input_path: impl Into<PathBuf>) -> anyhow::Result<()> {
let input_path = input_path.into();
let branch = self.get_branch()?.ok_or(anyhow::anyhow!(
"failed to find branch, required for triggering release"
))?;
tracing::trace!("triggering release for: {}", input_path.display());
let local_app =
SharedLocalApp::new(LocalApp::new(&self.registry).await?).flux_local_cluster_manager();
let upload_id = local_app
.package_clusters(input_path)
.await
.context("failed to package clusters")?;
local_app
.commit_artifact(&self.service, &branch, upload_id)
.await
.context("failed to commit artifact")?;
local_app
.trigger_release(&self.service, &branch)
.await
.context("failed to trigger release")?;
Ok(())
}
pub fn get_branch(&self) -> anyhow::Result<Option<String>> {
let output = Command::new("git")
.args(["rev-parse", "--abbrev-ref", "HEAD"])
.output()?;
if output.status.success() {
let branch = std::str::from_utf8(&output.stdout)?.trim().to_string();
Ok(Some(branch))
} else {
let err = std::str::from_utf8(&output.stderr)?;
anyhow::bail!("Failed to get branch name: {}", err)
}
}
}
impl UploadStrategy for Releaser {
fn upload(&self, input_path: &Path) -> BoxFuture<'_, anyhow::Result<()>> {
let input_path = input_path.to_path_buf();
async move {
self.release(input_path).await?;
Ok(())
}
.boxed()
}
}
#[cfg(test)]
mod test {
use crate::releaser::Releaser;
#[tokio::test]
async fn can_upload_test() -> anyhow::Result<()> {
return Ok(());
let releaser = Releaser::default();
releaser
.release(
"/home/kjuulh/git/git.front.kjuulh.io/kjuulh/cuddle-rust-service-plan/.cuddle/tmp/cuddle-clusters",
)
.await?;
Ok(())
}
}

View File

@ -1,9 +1,6 @@
use std::{cmp::Ordering, collections::HashMap, path::Path};
use std::{cmp::Ordering, path::Path};
use cuddle_clusters::{
process::{NoUploadStrategy, ProcessOpts},
ConcreteComponent, IntoComponent,
};
use cuddle_clusters::{process::ProcessOpts, ConcreteComponent, IntoComponent};
use walkdir::DirEntry;
pub(crate) async fn run_test_with_components(
@ -30,9 +27,7 @@ pub(crate) async fn run_test_with_components(
ProcessOpts {
path: test_folder.clone(),
output: actual.clone(),
variables: HashMap::default(),
},
None::<NoUploadStrategy>,
)
.await?;
@ -42,9 +37,7 @@ pub(crate) async fn run_test_with_components(
ProcessOpts {
path: test_folder,
output: expected.clone(),
variables: HashMap::default(),
},
None::<NoUploadStrategy>,
)
.await?;
}

View File

@ -4,10 +4,7 @@ mod can_run_for_env;
mod cuddle_vars;
use cuddle_clusters::{
catalog::{
cluster_vars::ClusterVars, crdb_database::CockroachDB, cuddle_vars::CuddleVars,
ingress::Ingress, vault_secret::VaultSecret,
},
catalog::{cluster_vars::ClusterVars, cuddle_vars::CuddleVars, vault_secret::VaultSecret},
IntoComponent,
};
@ -99,38 +96,3 @@ async fn with_vault_secrets() -> anyhow::Result<()> {
Ok(())
}
#[tokio::test]
async fn with_crdb() -> anyhow::Result<()> {
let current_dir = std::env::current_dir()?.join("tests/with_crdb");
run_test_with_components(
"with_crdb",
vec![
CuddleVars::new(&current_dir).await?.into_component(),
ClusterVars::default().into_component(),
VaultSecret::default().into_component(),
CockroachDB::new(&current_dir).await?.into_component(),
],
)
.await?;
Ok(())
}
#[tokio::test]
async fn with_ingress() -> anyhow::Result<()> {
let current_dir = std::env::current_dir()?.join("tests/with_ingress");
run_test_with_components(
"with_ingress",
vec![
CuddleVars::new(&current_dir).await?.into_component(),
ClusterVars::default().into_component(),
Ingress::new(&current_dir).await?.into_component(),
],
)
.await?;
Ok(())
}

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ vars.cuddle_vars.service }}-config
data:
{%- if (vars.cluster_vars.env | items | length) > 0 %}
environment:
{%- for (name, value) in vars.cluster_vars.env | dictsort %}
{{name | upper | replace(".", "_") | replace("-", "_") }}: {{value}}
{%- endfor %}
{%- endif %}

View File

@ -1,20 +1,26 @@
{%- set service_name = vars.cuddle_vars.service -%}
{%- set cluster_name = vars.cluster_vars.name -%}
{%- set cluster_namespace = vars.cluster_vars.namespace -%}
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: {{ service_name }}
cluster: {{ cluster_name }}
name: {{ service_name }}
namespace: {{ cluster_namespace }}
spec:
replicas: 3
selector:
matchLabels:
app: {{ service_name }}
cluster: {{ cluster_name }}
template:
metadata:
labels:
app: {{ service_name }}
cluster: {{ cluster_name }}
spec:
containers:
- args:
@ -23,6 +29,9 @@ spec:
- {{ service_name }}
image: kasperhermansen/{{ service_name }}:main-1715336504
name: {{ service_name }}
envFrom:
- configMapRef:
name: {{service_name}}-config
ports:
- containerPort: 3000
name: external-http

View File

@ -1,7 +0,0 @@
vars:
service: service
database:
crdb: "true"
cuddle/clusters:
dev:

View File

@ -1,9 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: service-cuddle-crdb
namespace: dev
data:
DATABASE_URL: postgresql://root@dev-cluster:26257/service

View File

@ -1,39 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: service
name: service
spec:
replicas: 3
selector:
matchLabels:
app: service
template:
metadata:
labels:
app: service
spec:
containers:
- args:
- serve
command:
- service
image: kasperhermansen/service:main-1715336504
name: service
envFrom:
- configMapRef:
name: service-config
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: service-cuddle-crdb
key: DATABASE_URL
ports:
- containerPort: 3000
name: external-http
- containerPort: 3001
name: internal-http
- containerPort: 3002
name: internal-grpc

View File

@ -1,54 +0,0 @@
{%- set service_name = vars.cuddle_vars.service -%}
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: {{ service_name }}
name: {{ service_name }}
spec:
replicas: 3
selector:
matchLabels:
app: {{ service_name }}
template:
metadata:
labels:
app: {{ service_name }}
spec:
containers:
- args:
- serve
command:
- {{ service_name }}
image: kasperhermansen/{{ service_name }}:main-1715336504
name: {{ service_name }}
envFrom:
- configMapRef:
name: {{service_name}}-config
{%- if vars.vault_secret.has_values or vars.cuddle_crdb.has_values %}
env:
{%- if vars.vault_secret.has_values %}
{%- for secret in vars.vault_secret.secrets %}
- name: {{secret | upper | replace(".", "_") | replace("-", "_") }}
valueFrom:
secretKeyRef:
name: {{ vars.vault_secret.file_name(service_name) }}
key: {{ secret }}
{%- endfor %}
{%- endif %}
{%- if vars.cuddle_crdb.has_values %}
- name: {{vars.cuddle_crdb.env }}
valueFrom:
secretKeyRef:
name: {{ vars.cuddle_crdb.file_name(service_name) }}
key: {{ vars.cuddle_crdb.env }}
{%- endif %}
{%- endif %}
ports:
- containerPort: 3000
name: external-http
- containerPort: 3001
name: internal-http
- containerPort: 3002
name: internal-grpc

View File

@ -1,11 +0,0 @@
vars:
service: service
ingress:
- external: "true"
- internal: "true"
- external_grpc: "true"
- internal_grpc: "true"
cuddle/clusters:
dev:
prod:

View File

@ -1,121 +0,0 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: dev
name: service-external-http
namespace: dev
spec:
rules:
- host: service.dev.kjuulh.app
http:
paths:
- backend:
service:
name: service
port:
name: external-http
path: /
pathType: Prefix
tls:
- hosts:
- service.dev.kjuulh.app
secretName: tls-service-kjuulh-app-external-http-ingress-dns
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: dev
name: service-internal-http
namespace: dev
spec:
rules:
- host: service.dev.internal.kjuulh.app
http:
paths:
- backend:
service:
name: service
port:
name: internal-http
path: /
pathType: Prefix
tls:
- hosts:
- service.dev.internal.kjuulh.app
secretName: tls-service-kjuulh-app-internal-http-ingress-dns
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: dev
name: service-external-grpc
namespace: dev
spec:
rules:
- host: grpc.service.dev.kjuulh.app
http:
paths:
- backend:
service:
name: service-grpc
port:
name: external-grpc
path: /
pathType: Prefix
tls:
- hosts:
- grpc.service.dev.kjuulh.app
secretName: tls-service-kjuulh-app-external-grpc-ingress-dns
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: dev
name: service-internal-grpc
namespace: dev
spec:
rules:
- host: grpc.service.dev.internal.kjuulh.app
http:
paths:
- backend:
service:
name: service-grpc
port:
name: internal-grpc
path: /
pathType: Prefix
tls:
- hosts:
- grpc.service.dev.internal.kjuulh.app
secretName: tls-service-kjuulh-app-internal-grpc-ingress-dns

View File

@ -1,30 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: service
name: service
spec:
replicas: 3
selector:
matchLabels:
app: service
template:
metadata:
labels:
app: service
spec:
containers:
- args:
- serve
command:
- service
image: kasperhermansen/service:main-1715336504
name: service
ports:
- containerPort: 3000
name: external-http
- containerPort: 3001
name: internal-http
- containerPort: 3002
name: internal-grpc

View File

@ -1,121 +0,0 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: prod
name: service-external-http
namespace: prod
spec:
rules:
- host: service.prod.kjuulh.app
http:
paths:
- backend:
service:
name: service
port:
name: external-http
path: /
pathType: Prefix
tls:
- hosts:
- service.prod.kjuulh.app
secretName: tls-service-kjuulh-app-external-http-ingress-dns
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: prod
name: service-internal-http
namespace: prod
spec:
rules:
- host: service.prod.internal.kjuulh.app
http:
paths:
- backend:
service:
name: service
port:
name: internal-http
path: /
pathType: Prefix
tls:
- hosts:
- service.prod.internal.kjuulh.app
secretName: tls-service-kjuulh-app-internal-http-ingress-dns
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: prod
name: service-external-grpc
namespace: prod
spec:
rules:
- host: grpc.service.prod.kjuulh.app
http:
paths:
- backend:
service:
name: service-grpc
port:
name: external-grpc
path: /
pathType: Prefix
tls:
- hosts:
- grpc.service.prod.kjuulh.app
secretName: tls-service-kjuulh-app-external-grpc-ingress-dns
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/issuer: kjuulh-app
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.tls: "true"
labels:
app: service
cluster: prod
name: service-internal-grpc
namespace: prod
spec:
rules:
- host: grpc.service.prod.internal.kjuulh.app
http:
paths:
- backend:
service:
name: service-grpc
port:
name: internal-grpc
path: /
pathType: Prefix
tls:
- hosts:
- grpc.service.prod.internal.kjuulh.app
secretName: tls-service-kjuulh-app-internal-grpc-ingress-dns

View File

@ -1,30 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: service
name: service
spec:
replicas: 3
selector:
matchLabels:
app: service
template:
metadata:
labels:
app: service
spec:
containers:
- args:
- serve
command:
- service
image: kasperhermansen/service:main-1715336504
name: service
ports:
- containerPort: 3000
name: external-http
- containerPort: 3001
name: internal-http
- containerPort: 3002
name: internal-grpc