Services and ingresses

Seriously, if I catch you using this, I will bite >:(
This commit is contained in:
Gabriel Simmer 2024-07-03 22:59:01 +01:00
parent 938f558962
commit 30d241ea4e
Signed by: arch
SSH key fingerprint: SHA256:m3OEcdtrnBpMX+2BDGh/byv3hrCekCLzDYMdvGEKPPQ
8 changed files with 218 additions and 10 deletions

6
Cargo.lock generated
View file

@ -29,6 +29,8 @@ name = "infra-rs"
version = "0.1.0"
dependencies = [
"k8s-openapi",
"serde",
"serde_json",
]
[[package]]
@ -124,9 +126,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.118"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"ryu",

View file

@ -5,3 +5,5 @@ edition = "2021"
[dependencies]
k8s-openapi = { version = "0.22.0", features = ["v1_30"] }
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.120"

69
src/infra_rs/ingress.rs Normal file
View file

@ -0,0 +1,69 @@
use k8s_openapi::{
api::{
core::v1::Service,
networking::v1::{
self as api, HTTPIngressPath, HTTPIngressRuleValue, IngressBackend, IngressRule,
IngressServiceBackend, IngressSpec, IngressTLS, ServiceBackendPort,
},
},
apimachinery::pkg::apis::meta::v1::ObjectMeta,
};
#[derive(Default)]
pub struct Ingress {
pub name: String,
pub hostname: String,
pub tls_secret: Option<String>,
}
pub fn new(ingress: Ingress, service: &Service) -> api::Ingress {
api::Ingress {
metadata: ObjectMeta {
name: Some(ingress.name.clone()),
..Default::default()
},
spec: Some(IngressSpec {
rules: Some(vec![IngressRule {
host: Some(ingress.hostname.clone()),
http: Some(HTTPIngressRuleValue {
paths: vec![HTTPIngressPath {
path: Some(String::from("/")),
path_type: String::from("Prefix"),
backend: IngressBackend {
service: Some(IngressServiceBackend {
name: service.metadata.clone().name.unwrap(),
port: Some(ServiceBackendPort {
number: Some(
service
.spec
.clone()
.unwrap()
.ports
.unwrap()
.first()
.unwrap()
.port,
),
..Default::default()
}),
..Default::default()
}),
..Default::default()
},
..Default::default()
}],
}),
}]),
tls: if let Some(tls_secret) = ingress.tls_secret {
Some(vec![IngressTLS {
hosts: Some(vec![ingress.hostname]),
secret_name: Some(tls_secret),
}])
} else {
None
},
..Default::default()
}),
..Default::default()
}
}

View file

@ -1 +1,22 @@
use serde::{self, Deserialize, Serialize};
use serde_json::Value;
pub mod deployment;
pub mod ingress;
pub mod service;
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum Resource {
Deployment(k8s_openapi::api::apps::v1::Deployment),
Ingress(k8s_openapi::api::networking::v1::Ingress),
Service(k8s_openapi::api::core::v1::Service),
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ResourceList {
#[serde(rename = "apiVersion")]
pub api_version: String,
pub kind: String,
pub items: Vec<Value>,
}

75
src/infra_rs/service.rs Normal file
View file

@ -0,0 +1,75 @@
use std::collections::BTreeMap;
use k8s_openapi::{
api::{
apps::v1::Deployment,
core::v1::{self as api, ServicePort, ServiceSpec},
},
apimachinery::pkg::apis::meta::v1::ObjectMeta,
};
#[derive(Default)]
pub struct Service {
pub name: String,
pub port: i32,
}
pub fn new(service: Service) -> api::Service {
api::Service {
metadata: ObjectMeta {
name: Some(service.name.clone()),
namespace: Some(service.name.clone()),
..Default::default()
},
spec: Some(ServiceSpec {
ports: Some(vec![ServicePort {
name: Some(format!("{}-{}", service.name, service.port)),
port: service.port,
..Default::default()
}]),
..Default::default()
}),
..Default::default()
}
}
pub fn from(deployment: &Deployment) -> api::Service {
let d = deployment.clone();
let containers = d.spec.unwrap().template.clone().spec.unwrap().containers;
let ports: Vec<ServicePort> = containers
.into_iter()
.map(|c| {
c.ports.unwrap().into_iter().map(|p| ServicePort {
port: p.container_port,
name: Some(format!(
"{}-{}",
d.metadata.name.clone().unwrap(),
p.container_port
)),
..Default::default()
})
})
.flatten()
.collect();
api::Service {
metadata: ObjectMeta {
name: Some(d.metadata.name.clone().unwrap()),
namespace: Some(d.metadata.name.clone().unwrap()),
labels: Some(BTreeMap::from([(
String::from("app"),
d.metadata.name.clone().unwrap(),
)])),
..Default::default()
},
spec: Some(ServiceSpec {
ports: Some(ports),
selector: Some(BTreeMap::from([(
String::from("app"),
d.metadata.name.clone().unwrap(),
)])),
..Default::default()
}),
..Default::default()
}
}

View file

@ -1,10 +1,10 @@
use k8s_openapi::serde_json;
use serde_json;
mod infra_rs;
mod manifests;
fn main() {
let test = manifests::vaultwarden::render();
let test = manifests::render();
println!("{}", serde_json::to_string(&test).unwrap());
}

View file

@ -1 +1,13 @@
pub mod vaultwarden;
use crate::infra_rs::ResourceList;
mod vaultwarden;
pub fn render() -> ResourceList {
let resources = vec![vaultwarden::render()].into_iter().flatten().collect();
ResourceList {
items: resources,
api_version: String::from("v1"),
kind: String::from("List"),
}
}

View file

@ -1,9 +1,14 @@
use k8s_openapi::api::apps::v1 as api;
use serde_json::Value;
use crate::infra_rs::deployment::{self, Deployment, DeploymentEnv};
use crate::infra_rs::{
deployment::{self, Deployment, DeploymentEnv},
ingress::{self, Ingress},
service::{self, Service},
Resource,
};
pub fn render() -> api::Deployment {
deployment::new(Deployment {
pub fn render() -> Vec<Value> {
let deployment = deployment::new(Deployment {
name: String::from("vaultwarden"),
image: String::from("vaultwarden/server:testing"),
ports: vec![80],
@ -18,5 +23,27 @@ pub fn render() -> api::Deployment {
..Default::default()
},
],
})
});
let service = service::from(&deployment);
let ingress = ingress::new(
Ingress {
name: String::from("vaultwarden"),
hostname: String::from("pw.gmem.ca"),
tls_secret: Some(String::from("gmem-ca-wildcard")),
},
&service,
);
let resources = vec![
Resource::Deployment(deployment),
Resource::Service(service),
Resource::Ingress(ingress),
];
resources
.into_iter()
.map(|res| serde_json::to_value(res).unwrap())
.collect()
}