feat: add deployment
Some checks failed
continuous-integration/drone/push Build is failing

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
Kasper Juul Hermansen 2024-01-28 20:44:12 +01:00
parent 5378b5f537
commit 3da154882d
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
7 changed files with 272 additions and 67 deletions

22
Cargo.lock generated
View File

@ -331,6 +331,9 @@ dependencies = [
"dagger-sdk", "dagger-sdk",
"eyre", "eyre",
"futures", "futures",
"serde",
"serde_json",
"serde_yaml",
"tokio", "tokio",
] ]
@ -1415,6 +1418,19 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_yaml"
version = "0.9.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.10.8" version = "0.10.8"
@ -1764,6 +1780,12 @@ dependencies = [
"void", "void",
] ]
[[package]]
name = "unsafe-libyaml"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.9.0" version = "0.9.0"

View File

@ -27,3 +27,6 @@ color-eyre = "*"
clap = {version = "4", features = ["derive"]} clap = {version = "4", features = ["derive"]}
futures = "0.3.29" futures = "0.3.29"
async-scoped = { version = "0.8.0", features = ["tokio", "use-tokio"] } async-scoped = { version = "0.8.0", features = ["tokio", "use-tokio"] }
serde_json = { version = "1" }
serde_yaml = {version = "0.9"}
serde = {version = "1", features = ["derive"]}

View File

@ -19,6 +19,9 @@ clap.workspace = true
async-trait.workspace = true async-trait.workspace = true
futures.workspace = true futures.workspace = true
tokio.workspace = true tokio.workspace = true
serde_json.workspace = true
serde_yaml.workspace = true
serde.workspace = true
[dev-dependencies] [dev-dependencies]
tokio.workspace = true tokio.workspace = true

View File

@ -0,0 +1,129 @@
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleFile {
pub vars: CuddleVars,
pub deployment: Option<CuddleDeployment>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleVars {
pub service: String,
pub registry: String,
pub clusters: CuddleClusters,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeployment {
pub registry: String,
pub env: CuddleDeploymentEnv,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeploymentEnv(pub BTreeMap<String, CuddleDeploymentCluster>);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeploymentCluster {
pub clusters: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleClusters(pub BTreeMap<String, CuddleCluster>);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleCluster {
pub namespace: String,
}
impl CuddleFile {
pub async fn from_cuddle_file() -> eyre::Result<Self> {
let cuddle_file_content = tokio::fs::read_to_string("cuddle.yaml").await?;
Self::parse_cuddle_file(&cuddle_file_content)
}
pub fn parse_cuddle_file(content: &str) -> eyre::Result<Self> {
let cuddle_file: CuddleFile = serde_yaml::from_str(content)?;
Ok(cuddle_file)
}
}
#[cfg(test)]
mod test {
use std::collections::BTreeMap;
use crate::cuddle_file::{
CuddleCluster, CuddleClusters, CuddleDeploymentCluster, CuddleDeploymentEnv, CuddleVars,
};
use super::CuddleFile;
#[test]
fn parse_file() {
let cuddle_file = r#"
base: "git@git.front.kjuulh.io:kjuulh/cuddle-base.git"
vars:
service: "infrastructure-example"
registry: kasperhermansen
clusters:
clank_prod:
replicas: "3"
namespace: clank_prod
deployment:
registry: git@git.front.kjuulh.io:kjuulh/clank-clusters
env:
prod:
clusters:
- clank_prod
scripts:
render:
type: shell
args:
cluster:
name: cluster
type: flag
image_tag:
name: image_tag
type: flag"#;
let res = CuddleFile::parse_cuddle_file(cuddle_file).expect("to parse file");
let mut clusters = BTreeMap::new();
clusters.insert(
"clank_prod".into(),
CuddleCluster {
namespace: "clank_prod".into(),
},
);
let mut deployment = BTreeMap::new();
deployment.insert(
"prod".into(),
CuddleDeploymentCluster {
clusters: vec!["clank_prod".into()],
},
);
let expected = CuddleFile {
vars: CuddleVars {
service: "infrastructure-example".into(),
registry: "kasperhermansen".into(),
clusters: CuddleClusters(clusters),
},
deployment: Some(crate::cuddle_file::CuddleDeployment {
registry: "git@git.front.kjuulh.io:kjuulh/clank-cluster".into(),
env: CuddleDeploymentEnv(deployment),
}),
};
assert_eq!(expected, res)
}
}

View File

@ -0,0 +1,103 @@
use async_trait::async_trait;
use eyre::Context;
use crate::{cuddle_file::CuddleFile, MainAction};
pub struct CuddleReleaser {
client: dagger_sdk::Query,
env: String,
cuddle_file: CuddleFile,
folder: String,
}
pub struct CuddleReleaserOptions {
upstream: String,
cluster: String,
namespace: String,
app: String,
}
impl CuddleReleaser {
pub async fn new(client: dagger_sdk::Query) -> eyre::Result<Self> {
let cuddle_file = CuddleFile::from_cuddle_file().await?;
let env = std::env::var("CUDDLE_ENV").context("CUDDLE_ENV was not set")?;
Ok(Self {
client,
cuddle_file,
env,
folder: ".cuddle/tmp/k8s".into(),
})
}
}
#[async_trait]
impl MainAction for CuddleReleaser {
async fn execute_main(&self) -> eyre::Result<()> {
let client = self.client.clone();
if self.cuddle_file.deployment.is_none() {
return Ok(());
}
let chosen_cluster = match self
.cuddle_file
.deployment
.as_ref()
.unwrap()
.env
.0
.get(&self.env.to_string())
{
Some(c) => match c.clusters.first().take() {
Some(c) => c,
None => return Ok(()),
},
None => return Ok(()),
};
let cluster = match self.cuddle_file.vars.clusters.0.get(chosen_cluster) {
Some(c) => c,
None => eyre::bail!("no cluster found for: {}", chosen_cluster),
};
let options = CuddleReleaserOptions {
cluster: chosen_cluster.clone(),
namespace: cluster.namespace.clone(),
app: self.cuddle_file.vars.service.clone(),
upstream: self
.cuddle_file
.deployment
.as_ref()
.unwrap()
.registry
.clone(),
};
let cuddle_releaser_image = "docker.io/kasperhermansen:cuddle-releaser:main-1706438736";
let folder = client.host().directory(&self.folder);
let cuddle_releaser = client
.container()
.from(cuddle_releaser_image)
.with_mounted_directory("/mnt/templates", folder);
cuddle_releaser
.with_exec(vec![
"cuddle-releaser",
"release",
&format!("--upstream={}", options.upstream),
&format!("--folder={}", "/mnt/templates"),
&format!("--cluster={}", options.cluster),
&format!("--namespace={}", options.namespace),
&format!("--app={}", options.app),
])
.sync()
.await?;
Ok(())
}
}

View File

@ -1,67 +1,12 @@
pub mod cli; pub mod cli;
pub mod leptos_service;
pub use cli::*; pub use cli::*;
pub mod cuddle_please; pub mod leptos_service;
pub mod dagger_middleware;
pub mod node_service; pub mod node_service;
pub mod rust_lib; pub mod rust_lib;
pub mod rust_service; pub mod rust_service;
pub mod cuddle_releaser { pub mod cuddle_file;
use async_trait::async_trait; pub mod cuddle_please;
pub mod cuddle_releaser;
use crate::{rust_service::RustService, MainAction}; pub mod dagger_middleware;
pub struct CuddleReleaser {
client: dagger_sdk::Query,
options: CuddleReleaserOptions,
}
pub struct CuddleReleaserOptions {
upstream: String,
folder: String,
cluster: String,
namespace: String,
app: String,
}
impl CuddleReleaser {
pub async fn new(
client: dagger_sdk::Query,
options: CuddleReleaserOptions,
) -> eyre::Result<Self> {
Ok(Self { client, options })
}
}
#[async_trait]
impl MainAction for CuddleReleaser {
async fn execute_main(&self) -> eyre::Result<()> {
let client = self.client;
let cuddle_releaser_image = "docker.io/kasperhermansen:cuddle-releaser:main-1706438736";
let folder = client.host().directory(self.options.folder);
let cuddle_releaser = client
.container()
.from(cuddle_releaser_image)
.with_mounted_directory("/mnt/templates", folder);
cuddle_releaser
.with_exec(vec![
"cuddle-releaser",
"release",
&format!("--upstream={}", self.options.upstream),
&format!("--folder={}", "/mnt/templates"),
&format!("--cluster={}", self.options.cluster),
&format!("--namespace={}", self.options.namespace),
&format!("--app={}", self.options.app),
])
.sync()?;
Ok(())
}
}
}

View File

@ -466,13 +466,13 @@ mod test {
.with_apt(&["git"]) .with_apt(&["git"])
.with_cargo_binstall("latest", ["sqlx-cli"]) .with_cargo_binstall("latest", ["sqlx-cli"])
.with_mold("2.3.3") .with_mold("2.3.3")
.with_stage(RustServiceStage::BeforeDeps(middleware(|c| { // .with_stage(RustServiceStage::BeforeDeps(middleware(|c| {
async move { // async move {
// Noop // // Noop
Ok(c) // Ok(c)
} // }
.boxed() // .boxed()
}))) // })))
.with_clap_sanity_test() .with_clap_sanity_test()
.build_release() .build_release()
.await?; .await?;