From 06d856a869e48ec1dbce430df2071449fa6a2d5c Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Thu, 5 Mar 2026 03:51:03 +0100 Subject: [PATCH] WIP --- .gitattributes | 1 + crete/.gitignore | 1 + crete/Cargo.lock | 355 ++++++++++++++++++ crete/Cargo.toml | 17 + crete/src/bin/schemas.rs | 23 ++ crete/src/cluster.rs | 69 ++++ crete/src/lib.rs | 11 + crete/src/main.rs | 10 + crete/src/node.rs | 174 +++++++++ crete/src/patch.rs | 117 ++++++ nodes/testing/_secrets.yaml | Bin 8819 -> 8818 bytes nodes/titan/_secrets.yaml | Bin 8827 -> 8827 bytes schemas/cluster.json | 354 +++++++++++++++++ schemas/node.json | 248 ++++++++++++ secrets.yaml | Bin 93 -> 94 bytes talos/clusters/testing.yaml | 63 ++++ talos/nodes/testing/talos-vm.yaml | 4 + talos/patches/flux/cluster-variables.yaml | 18 + talos/patches/metrics/all.yaml | 5 + talos/patches/metrics/control-plane.yaml | 5 + talos/patches/networking/cilium.yaml | 12 + talos/patches/networking/gateway-api.yaml | 4 + talos/patches/networking/tailscale.yaml | 8 + talos/patches/networking/vip.yaml | 7 + talos/patches/sops.yaml | 18 + talos/patches/spegel.yaml | 8 + talos/patches/storage/limit-ephemeral.yaml | 6 + .../local-path-provisioner/user-volume.yaml | 9 + talos/patches/storage/longhorn.yaml | 11 + .../patches/storage/longhorn/user-volume.yaml | 9 + talos/patches/storage/openebs.yaml | 17 + .../system/allow-control-plane-workloads.yaml | 3 + talos/patches/system/hostname.yaml | 4 + talos/patches/system/install-disk.yaml | 4 + talos/patches/system/network.yaml | 11 + talos/secrets/tailscale.key | Bin 0 -> 71 bytes talos/secrets/testing/age.key | Bin 0 -> 211 bytes talos/secrets/testing/secrets.yaml | Bin 0 -> 8819 bytes 38 files changed, 1606 insertions(+) create mode 100644 crete/.gitignore create mode 100644 crete/Cargo.lock create mode 100644 crete/Cargo.toml create mode 100644 crete/src/bin/schemas.rs create mode 100644 crete/src/cluster.rs create mode 100644 crete/src/lib.rs create mode 100644 crete/src/main.rs create mode 100644 crete/src/node.rs create mode 100644 crete/src/patch.rs create mode 100644 schemas/cluster.json create mode 100644 schemas/node.json create mode 100644 talos/clusters/testing.yaml create mode 100644 talos/nodes/testing/talos-vm.yaml create mode 100644 talos/patches/flux/cluster-variables.yaml create mode 100644 talos/patches/metrics/all.yaml create mode 100644 talos/patches/metrics/control-plane.yaml create mode 100644 talos/patches/networking/cilium.yaml create mode 100644 talos/patches/networking/gateway-api.yaml create mode 100644 talos/patches/networking/tailscale.yaml create mode 100644 talos/patches/networking/vip.yaml create mode 100644 talos/patches/sops.yaml create mode 100644 talos/patches/spegel.yaml create mode 100644 talos/patches/storage/limit-ephemeral.yaml create mode 100644 talos/patches/storage/local-path-provisioner/user-volume.yaml create mode 100644 talos/patches/storage/longhorn.yaml create mode 100644 talos/patches/storage/longhorn/user-volume.yaml create mode 100644 talos/patches/storage/openebs.yaml create mode 100644 talos/patches/system/allow-control-plane-workloads.yaml create mode 100644 talos/patches/system/hostname.yaml create mode 100644 talos/patches/system/install-disk.yaml create mode 100644 talos/patches/system/network.yaml create mode 100644 talos/secrets/tailscale.key create mode 100644 talos/secrets/testing/age.key create mode 100644 talos/secrets/testing/secrets.yaml diff --git a/.gitattributes b/.gitattributes index 9fc5447..10a0988 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ _secrets.yaml filter=git-crypt diff=git-crypt secrets.yaml filter=git-crypt diff=git-crypt *.agekey filter=git-crypt diff=git-crypt +talos/secrets/** filter=git-crypt diff=git-crypt diff --git a/crete/.gitignore b/crete/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/crete/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/crete/Cargo.lock b/crete/Cargo.lock new file mode 100644 index 0000000..3476d09 --- /dev/null +++ b/crete/Cargo.lock @@ -0,0 +1,355 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "crete" +version = "0.1.0" +dependencies = [ + "minijinja", + "optional_struct", + "regress", + "repo_path_lib", + "schemars", + "semver", + "serde", + "serde_json", + "serde_yaml", + "walkdir", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memo-map" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b" + +[[package]] +name = "minijinja" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54f3bcc034dd74496b5ca929fd0b710186672d5ff0b0f255a9ceb259042ece" +dependencies = [ + "memo-map", + "self_cell", + "serde", +] + +[[package]] +name = "optional_struct" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14199f59efce6ed2c5854f0abc725c32eedfbd02c6ef82c9733c726f3fc6dc91" +dependencies = [ + "optional_struct_macro", + "serde", +] + +[[package]] +name = "optional_struct_macro" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5eba042d9efe5e108e0df9ce2f85c540fc4f94f41c6821cbcf70ed47c1221da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "regress" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2057b2325e68a893284d1538021ab90279adac1139957ca2a74426c6f118fb48" +dependencies = [ + "hashbrown", + "memchr", +] + +[[package]] +name = "repo_path_lib" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4f67a73ddc563e6fb8bac035c9c76de29af2e4ad6031dc49bb5a2cd0742fca" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "schemars_derive", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "self_cell" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/crete/Cargo.toml b/crete/Cargo.toml new file mode 100644 index 0000000..e93e0f4 --- /dev/null +++ b/crete/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "crete" +version = "0.1.0" +edition = "2024" +default-run = "crete" + +[dependencies] +minijinja = { version = "2.16.0", features = ["loader"] } +optional_struct = "0.5.2" +regress = "0.10.5" +repo_path_lib = "1.2.4" +schemars = { version = "1.2.1", features = ["semver1"] } +semver = { version = "1.0.27", features = ["serde"] } +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.149" +serde_yaml = "0.9.34" +walkdir = "2.5.0" diff --git a/crete/src/bin/schemas.rs b/crete/src/bin/schemas.rs new file mode 100644 index 0000000..956b716 --- /dev/null +++ b/crete/src/bin/schemas.rs @@ -0,0 +1,23 @@ +use std::{fs::File, io::Write}; + +use crete::{cluster::Cluster, node::OptionalNode}; +use repo_path_lib::repo_dir; +use schemars::{JsonSchema, schema_for}; + +fn write(name: &str) +where + T: JsonSchema, +{ + let mut path = repo_dir().join("schemas").join(name); + path.add_extension("json"); + let mut file = File::create(path).unwrap(); + + let schema = serde_json::to_string_pretty(&schema_for!(T)).unwrap(); + file.write_all(schema.as_bytes()).unwrap(); +} + +// TODO: Create directory if it does not exist +fn main() { + write::("cluster"); + write::("node"); +} diff --git a/crete/src/cluster.rs b/crete/src/cluster.rs new file mode 100644 index 0000000..a604c55 --- /dev/null +++ b/crete/src/cluster.rs @@ -0,0 +1,69 @@ +use std::net::Ipv4Addr; + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::{ + base_dir, + node::{Node, OptionalNode}, + patch::{PatchEnv, Patches}, +}; + +#[derive(Debug, Deserialize, JsonSchema, Clone)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Base { + #[serde(default)] + pub(crate) kernel_args: Vec, + #[serde(default)] + pub(crate) patches: Patches, +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Version { + kubernetes: semver::Version, + talos: semver::Version, +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub enum ClusterEnv { + Production, + Staging, +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Cluster { + #[serde(skip_deserializing)] + name: String, + version: Version, + nodes: Vec, + cluster_env: ClusterEnv, + control_plane_ip: Ipv4Addr, + #[serde(default, skip_serializing)] + pub(crate) default: OptionalNode, + #[serde(skip_serializing)] + pub(crate) base: Base, + // pub secrets_file: PathBuf, +} + +impl Cluster { + pub fn get(cluster_name: &str) -> Self { + let mut path = base_dir().join("clusters").join(cluster_name); + path.add_extension("yaml"); + let content = std::fs::read_to_string(path).unwrap(); + + let mut cluster: Self = serde_yaml::from_str(&content).unwrap(); + cluster.name = cluster_name.to_string(); + + cluster + } + + pub fn nodes(&self, env: PatchEnv) -> Vec { + self.nodes + .iter() + .map(|node_name| Node::get(node_name, &env, self)) + .collect() + } +} diff --git a/crete/src/lib.rs b/crete/src/lib.rs new file mode 100644 index 0000000..d33f0c4 --- /dev/null +++ b/crete/src/lib.rs @@ -0,0 +1,11 @@ +pub mod cluster; +pub mod node; +pub mod patch; + +use std::path::PathBuf; + +use repo_path_lib::repo_dir; + +fn base_dir() -> PathBuf { + repo_dir().join("talos") +} diff --git a/crete/src/main.rs b/crete/src/main.rs new file mode 100644 index 0000000..489f606 --- /dev/null +++ b/crete/src/main.rs @@ -0,0 +1,10 @@ +use crete::{cluster::Cluster, patch::PatchEnv}; + +fn main() { + let cluster = Cluster::get("testing"); + + let patches = PatchEnv::default(); + let nodes = cluster.nodes(patches); + + println!("{:#?}", nodes); +} diff --git a/crete/src/node.rs b/crete/src/node.rs new file mode 100644 index 0000000..f245ed3 --- /dev/null +++ b/crete/src/node.rs @@ -0,0 +1,174 @@ +use std::net::Ipv4Addr; + +use optional_struct::{Applicable, optional_struct}; +use schemars::JsonSchema; +use serde::{Deserialize, Deserializer, Serialize}; + +use crate::{ + base_dir, + cluster::Cluster, + patch::{OptionalPatches, PatchEnv, Patches}, +}; + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +enum NodeType { + Worker, + ControlPlane, +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +enum NodeArch { + Amd64, +} + +#[derive(Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +struct FileSecret { + file: String, +} + +fn deserialize_secret_file<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let secret: FileSecret = Deserialize::deserialize(deserializer)?; + let path = base_dir().join("secrets").join(secret.file); + let content = std::fs::read_to_string(path).unwrap().trim().to_owned(); + + Ok(content) +} + +fn file_secret_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + generator.subschema_for::() +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase", untagged)] +enum Secret { + String(String), + #[serde(deserialize_with = "deserialize_secret_file")] + #[schemars(schema_with = "file_secret_schema")] + File(String), +} + +impl From for String { + fn from(value: Secret) -> Self { + match value { + Secret::String(value) | Secret::File(value) => value, + } + } +} + +#[optional_struct] +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct Tailscale { + auth_key: Secret, + advertise_routes: bool, + #[serde(default)] + server: Option, +} + +#[optional_struct] +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct Network { + interface: String, + ip: Ipv4Addr, + netmask: Ipv4Addr, + gateway: Ipv4Addr, + dns: [Ipv4Addr; 2], + #[optional_rename(OptionalTailscale)] + #[optional_wrap] + tailscale: Tailscale, +} + +#[optional_struct] +#[derive(Debug, Serialize, Deserialize, JsonSchema, Default)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct Install { + auto: bool, + disk: String, + serial: Option, +} + +#[optional_struct] +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Node { + #[serde(skip_deserializing)] + hostname: String, + arch: NodeArch, + r#type: NodeType, + #[optional_rename(OptionalNetwork)] + #[optional_wrap] + network: Network, + ntp: String, + #[optional_rename(OptionalInstall)] + #[optional_wrap] + install: Install, + kernel_args: Vec, + #[optional_rename(OptionalPatches)] + #[optional_wrap] + pub(crate) patches: Patches, + // TODO: Per machine patches, append to global list of patches + // Any patches are specified under default they will get overridden +} + +impl Node { + pub fn get(node_name: &str, env: &PatchEnv, cluster: &Cluster) -> Self { + let mut path = base_dir().join("nodes").join(node_name); + let named = OptionalNode { + hostname: Some( + path.file_name() + .expect("Path should be valid") + .to_string_lossy() + .to_string(), + ), + ..OptionalNode::default() + }; + + path.add_extension("yaml"); + let content = std::fs::read_to_string(path).unwrap(); + + let node: OptionalNode = serde_yaml::from_str(&content).unwrap(); + + // We want all vectors to be empty vectors by default + // Sadly we have to this manually + // TODO: Find a better way of doing this + let default = OptionalNode { + patches: Some(OptionalPatches { + all: Some(vec![]), + control_plane: Some(vec![]), + }), + kernel_args: vec![].into(), + ..Default::default() + }; + + // Combine all the optional node parts into complete struct + let mut node: Node = default + // Apply cluster default settings + .apply(cluster.default.clone()) + // Apply hostname based on filename + .apply(named) + // Override node specific settings + .apply(node) + .try_into() + .unwrap(); + + // Prepend the cluster base values + let mut kernel_args = cluster.base.kernel_args.clone(); + kernel_args.extend(node.kernel_args); + node.kernel_args = kernel_args; + + let patches = cluster.base.patches.clone().extend(node.patches); + node.patches = patches; + + // Render patches + node.patches = node.patches.clone().render(env, cluster, &node); + + node + } +} diff --git a/crete/src/patch.rs b/crete/src/patch.rs new file mode 100644 index 0000000..dfd0846 --- /dev/null +++ b/crete/src/patch.rs @@ -0,0 +1,117 @@ +use std::{ + fmt::{Display, Formatter}, + net::Ipv4Addr, + str::FromStr, +}; + +use minijinja::{Environment, context}; +use optional_struct::optional_struct; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use walkdir::WalkDir; + +use crate::{base_dir, cluster::Cluster, node::Node}; + +pub struct PatchEnv<'e>(Environment<'e>); + +impl<'e> Default for PatchEnv<'e> { + fn default() -> Self { + let mut env = Environment::new(); + env.set_undefined_behavior(minijinja::UndefinedBehavior::Strict); + + let dir = base_dir().join("patches"); + for entry in WalkDir::new(&dir) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.metadata().unwrap().is_file()) + { + let source = std::fs::read_to_string(entry.path()).unwrap(); + let name = entry + .path() + .strip_prefix(&dir) + .unwrap() + .with_extension("") + .to_str() + .unwrap() + .to_owned(); + + env.add_filter("to_prefix", |netmask: String| { + let netmask = Ipv4Addr::from_str(&netmask).map_err(|err| { + minijinja::Error::new(minijinja::ErrorKind::InvalidOperation, err.to_string()) + })?; + let mask = netmask.to_bits(); + let prefix = mask.leading_ones(); + + if mask.checked_shl(prefix).unwrap_or(0) == 0 { + Ok(prefix as u8) + } else { + Err(minijinja::Error::new( + minijinja::ErrorKind::InvalidOperation, + "invalid IP prefix length", + )) + } + }); + + env.add_template_owned(name, source).unwrap(); + } + + Self(env) + } +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq)] +#[serde(untagged)] +pub(crate) enum Patch { + Name(String), + #[serde(skip)] + Resolved(serde_yaml::Value), +} + +#[optional_struct] +#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Default)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Patches { + pub(crate) all: Vec, + pub(crate) control_plane: Vec, +} + +fn render(patches: Vec, env: &PatchEnv, cluster: &Cluster, node: &Node) -> Vec { + patches + .into_iter() + .map(|patch| { + if let Patch::Name(name) = patch { + Patch::Resolved( + serde_yaml::from_str( + &env.0 + .get_template(&name) + .unwrap() + .render(context!(node, cluster)) + .unwrap(), + ) + .unwrap(), + ) + } else { + patch + } + }) + .collect() +} + +impl Patches { + pub(crate) fn extend(mut self, other: Self) -> Self { + self.all.extend(other.all); + self.control_plane.extend(other.control_plane); + + Self { + all: self.all, + control_plane: self.control_plane, + } + } + + pub(crate) fn render(self, env: &PatchEnv, cluster: &Cluster, node: &Node) -> Self { + Self { + all: render(self.all.clone(), env, cluster, node), + control_plane: render(self.control_plane.clone(), env, cluster, node), + } + } +} diff --git a/nodes/testing/_secrets.yaml b/nodes/testing/_secrets.yaml index d0f2eb5b19c8250b0dc3d3753df7aea5378d1695..0da02daec372d8794ec5d5b862dcd8745fa600a8 100644 GIT binary patch delta 19 bcmezD^2uexXR*y+#E!6S-YL6_g^>#YYl;Z~ delta 21 dcmez5^4Vp>XE8>e&7Z}NurYFO-Y&a~1psgm2?+oI diff --git a/nodes/titan/_secrets.yaml b/nodes/titan/_secrets.yaml index 7690821437d69d089ab017991129fb4dfb337892..8a6bbe985ac7710f06d74bf4ab0dd8598a81a870 100644 GIT binary patch delta 13 UcmezE^4n#Dq|#(5r9?(904n|jr2qf` delta 13 UcmezE^4n#Dq!OdTWJ#q&04X&Dx&QzG diff --git a/schemas/cluster.json b/schemas/cluster.json new file mode 100644 index 0000000..baf43a2 --- /dev/null +++ b/schemas/cluster.json @@ -0,0 +1,354 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Cluster", + "type": "object", + "properties": { + "base": { + "$ref": "#/$defs/Base", + "writeOnly": true + }, + "clusterEnv": { + "$ref": "#/$defs/ClusterEnv" + }, + "controlPlaneIp": { + "type": "string", + "format": "ipv4" + }, + "default": { + "$ref": "#/$defs/OptionalNode", + "writeOnly": true + }, + "nodes": { + "type": "array", + "items": { + "type": "string" + } + }, + "version": { + "$ref": "#/$defs/Version" + } + }, + "additionalProperties": false, + "required": [ + "version", + "nodes", + "clusterEnv", + "controlPlaneIp", + "base" + ], + "$defs": { + "Base": { + "type": "object", + "properties": { + "kernelArgs": { + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "patches": { + "$ref": "#/$defs/Patches", + "default": { + "all": [], + "controlPlane": [] + } + } + }, + "additionalProperties": false + }, + "ClusterEnv": { + "type": "string", + "enum": [ + "production", + "staging" + ] + }, + "FileSecret": { + "type": "object", + "properties": { + "file": { + "type": "string" + } + }, + "required": [ + "file" + ] + }, + "NodeArch": { + "type": "string", + "enum": [ + "amd64" + ] + }, + "NodeType": { + "type": "string", + "enum": [ + "worker", + "controlPlane" + ] + }, + "OptionalInstall": { + "type": "object", + "properties": { + "auto": { + "type": [ + "boolean", + "null" + ] + }, + "disk": { + "type": [ + "string", + "null" + ] + }, + "serial": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "OptionalNetwork": { + "type": "object", + "properties": { + "dns": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string", + "format": "ipv4" + }, + "maxItems": 2, + "minItems": 2 + }, + "gateway": { + "type": [ + "string", + "null" + ], + "format": "ipv4" + }, + "interface": { + "type": [ + "string", + "null" + ] + }, + "ip": { + "type": [ + "string", + "null" + ], + "format": "ipv4" + }, + "netmask": { + "type": [ + "string", + "null" + ], + "format": "ipv4" + }, + "tailscale": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalTailscale" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "OptionalNode": { + "type": "object", + "properties": { + "arch": { + "anyOf": [ + { + "$ref": "#/$defs/NodeArch" + }, + { + "type": "null" + } + ] + }, + "install": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalInstall" + }, + { + "type": "null" + } + ] + }, + "kernelArgs": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "network": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalNetwork" + }, + { + "type": "null" + } + ] + }, + "ntp": { + "type": [ + "string", + "null" + ] + }, + "patches": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalPatches" + }, + { + "type": "null" + } + ] + }, + "type": { + "anyOf": [ + { + "$ref": "#/$defs/NodeType" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "OptionalPatches": { + "type": "object", + "properties": { + "all": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/$defs/Patch" + } + }, + "controlPlane": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/$defs/Patch" + } + } + }, + "additionalProperties": false + }, + "OptionalTailscale": { + "type": "object", + "properties": { + "advertiseRoutes": { + "type": [ + "boolean", + "null" + ] + }, + "authKey": { + "anyOf": [ + { + "$ref": "#/$defs/Secret" + }, + { + "type": "null" + } + ] + }, + "server": { + "type": [ + "string", + "null" + ], + "default": null + } + }, + "additionalProperties": false + }, + "Patch": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "Patches": { + "type": "object", + "properties": { + "all": { + "type": "array", + "items": { + "$ref": "#/$defs/Patch" + } + }, + "controlPlane": { + "type": "array", + "items": { + "$ref": "#/$defs/Patch" + } + } + }, + "additionalProperties": false, + "required": [ + "all", + "controlPlane" + ] + }, + "Secret": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/FileSecret" + } + ] + }, + "SemVer": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + }, + "Version": { + "type": "object", + "properties": { + "kubernetes": { + "$ref": "#/$defs/SemVer" + }, + "talos": { + "$ref": "#/$defs/SemVer" + } + }, + "additionalProperties": false, + "required": [ + "kubernetes", + "talos" + ] + } + } +} diff --git a/schemas/node.json b/schemas/node.json new file mode 100644 index 0000000..e0ae660 --- /dev/null +++ b/schemas/node.json @@ -0,0 +1,248 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "OptionalNode", + "type": "object", + "properties": { + "arch": { + "anyOf": [ + { + "$ref": "#/$defs/NodeArch" + }, + { + "type": "null" + } + ] + }, + "install": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalInstall" + }, + { + "type": "null" + } + ] + }, + "kernelArgs": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "network": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalNetwork" + }, + { + "type": "null" + } + ] + }, + "ntp": { + "type": [ + "string", + "null" + ] + }, + "patches": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalPatches" + }, + { + "type": "null" + } + ] + }, + "type": { + "anyOf": [ + { + "$ref": "#/$defs/NodeType" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false, + "$defs": { + "FileSecret": { + "type": "object", + "properties": { + "file": { + "type": "string" + } + }, + "required": [ + "file" + ] + }, + "NodeArch": { + "type": "string", + "enum": [ + "amd64" + ] + }, + "NodeType": { + "type": "string", + "enum": [ + "worker", + "controlPlane" + ] + }, + "OptionalInstall": { + "type": "object", + "properties": { + "auto": { + "type": [ + "boolean", + "null" + ] + }, + "disk": { + "type": [ + "string", + "null" + ] + }, + "serial": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "OptionalNetwork": { + "type": "object", + "properties": { + "dns": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string", + "format": "ipv4" + }, + "maxItems": 2, + "minItems": 2 + }, + "gateway": { + "type": [ + "string", + "null" + ], + "format": "ipv4" + }, + "interface": { + "type": [ + "string", + "null" + ] + }, + "ip": { + "type": [ + "string", + "null" + ], + "format": "ipv4" + }, + "netmask": { + "type": [ + "string", + "null" + ], + "format": "ipv4" + }, + "tailscale": { + "anyOf": [ + { + "$ref": "#/$defs/OptionalTailscale" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "OptionalPatches": { + "type": "object", + "properties": { + "all": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/$defs/Patch" + } + }, + "controlPlane": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/$defs/Patch" + } + } + }, + "additionalProperties": false + }, + "OptionalTailscale": { + "type": "object", + "properties": { + "advertiseRoutes": { + "type": [ + "boolean", + "null" + ] + }, + "authKey": { + "anyOf": [ + { + "$ref": "#/$defs/Secret" + }, + { + "type": "null" + } + ] + }, + "server": { + "type": [ + "string", + "null" + ], + "default": null + } + }, + "additionalProperties": false + }, + "Patch": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "Secret": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/FileSecret" + } + ] + } + } +} diff --git a/secrets.yaml b/secrets.yaml index 5ff35445d12a9a04ad5ccd230b27f194e93511e6..bd7d7304d4cfa14146e31beeba313aa2f73b3a3c 100644 GIT binary patch delta 6 Ncma!zn-I&$1po(a0ki-B delta 4 Lcma!xoe&EE1P}qK diff --git a/talos/clusters/testing.yaml b/talos/clusters/testing.yaml new file mode 100644 index 0000000..057fca0 --- /dev/null +++ b/talos/clusters/testing.yaml @@ -0,0 +1,63 @@ +# yaml-language-server: $schema=../../schemas/cluster.json +version: + kubernetes: 1.34.1 + talos: 1.11.3 +clusterEnv: staging +controlPlaneIp: 192.168.1.100 +nodes: + - testing/talos-vm +# secrets: +# age: !file testing/age.key +# talos: testing/secrets.yaml + +base: + kernelArgs: + - talos.platform=metal + - console=tty0 + - init_on_alloc=1 + - init_on_free=1 + - slab_nomerge + - pti=on + - consoleblank=0 + - nvme_core.io_timeout=4294967295 + - printk.devkmsg=on + - selinux=1 + - lockdown=confidentiality + patches: + all: + - system/hostname + - system/install-disk + - system/network + - networking/vip + - networking/tailscale + - networking/cilium + - spegel + - storage/longhorn + - storage/longhorn/user-volume + - storage/local-path-provisioner/user-volume + - storage/limit-ephemeral + - metrics/all + controlPlane: + - system/allow-control-plane-workloads + # - sops + - flux/cluster-variables + - metrics/control-plane + - networking/gateway-api +default: + arch: amd64 + network: + interface: enp1s0 + netmask: 255.255.252.0 + gateway: 192.168.1.1 + dns: + - 1.1.1.1 + - 8.8.8.8 + tailscale: + server: https://headscale.huizinga.dev + authKey: + file: tailscale.key + advertiseRoutes: true + ntp: nl.pool.ntp.org + install: + auto: true + disk: /dev/vda diff --git a/talos/nodes/testing/talos-vm.yaml b/talos/nodes/testing/talos-vm.yaml new file mode 100644 index 0000000..9a01e75 --- /dev/null +++ b/talos/nodes/testing/talos-vm.yaml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=../../../schemas/node.json +type: controlPlane +network: + ip: 192.168.1.2 diff --git a/talos/patches/flux/cluster-variables.yaml b/talos/patches/flux/cluster-variables.yaml new file mode 100644 index 0000000..ca48e14 --- /dev/null +++ b/talos/patches/flux/cluster-variables.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +cluster: + inlineManifests: + - name: cluster-variables + contents: | + --- + apiVersion: v1 + kind: Namespace + metadata: + name: flux-system + --- + apiVersion: v1 + kind: ConfigMap + metadata: + name: cluster-variables + namespace: flux-system + data: + cluster_env: {{ cluster.clusterEnv }} diff --git a/talos/patches/metrics/all.yaml b/talos/patches/metrics/all.yaml new file mode 100644 index 0000000..027ecd7 --- /dev/null +++ b/talos/patches/metrics/all.yaml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + kubelet: + extraArgs: + rotate-server-certificates: "true" diff --git a/talos/patches/metrics/control-plane.yaml b/talos/patches/metrics/control-plane.yaml new file mode 100644 index 0000000..72637bb --- /dev/null +++ b/talos/patches/metrics/control-plane.yaml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +cluster: + extraManifests: + - https://raw.githubusercontent.com/alex1989hu/kubelet-serving-cert-approver/main/deploy/standalone-install.yaml + - https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml diff --git a/talos/patches/networking/cilium.yaml b/talos/patches/networking/cilium.yaml new file mode 100644 index 0000000..5ce0d69 --- /dev/null +++ b/talos/patches/networking/cilium.yaml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + features: + hostDNS: + # This option is enabled by default and causes issues with cilium + forwardKubeDNSToHost: false +cluster: + network: + cni: + name: none + proxy: + disabled: true diff --git a/talos/patches/networking/gateway-api.yaml b/talos/patches/networking/gateway-api.yaml new file mode 100644 index 0000000..bb9f3be --- /dev/null +++ b/talos/patches/networking/gateway-api.yaml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +cluster: + extraManifests: + - https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml diff --git a/talos/patches/networking/tailscale.yaml b/talos/patches/networking/tailscale.yaml new file mode 100644 index 0000000..b00fb0e --- /dev/null +++ b/talos/patches/networking/tailscale.yaml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +apiVersion: v1alpha1 +kind: ExtensionServiceConfig +name: tailscale +environment: + - TS_AUTHKEY={{ node.network.tailscale.authKey }} + - TS_EXTRA_ARGS={% if node.network.tailscale.server %}--login-server {{ node.network.tailscale.server }} {% endif %}--advertise-tags=tag:cluster-{{ cluster.name }} + - TS_ROUTES={% if node.network.tailscale.advertiseRoutes -%} {{node.network.ip}}/{{ node.network.netmask | to_prefix }} {%- endif %} diff --git a/talos/patches/networking/vip.yaml b/talos/patches/networking/vip.yaml new file mode 100644 index 0000000..c9db9b9 --- /dev/null +++ b/talos/patches/networking/vip.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + network: + interfaces: + - interface: "{{node.network.interface}}" + vip: + ip: "{{cluster.controlPlaneIp}}" diff --git a/talos/patches/sops.yaml b/talos/patches/sops.yaml new file mode 100644 index 0000000..7449275 --- /dev/null +++ b/talos/patches/sops.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +cluster: + inlineManifests: + - name: sops-key + contents: | + apiVersion: v1 + kind: Namespace + metadata: + name: flux-system + --- + apiVersion: v1 + kind: Secret + metadata: + name: sops-gpg + namespace: flux-system + data: + age.agekey: | + {{ helper.load_secret(node.cluster.sopsKeyFile) }} diff --git a/talos/patches/spegel.yaml b/talos/patches/spegel.yaml new file mode 100644 index 0000000..2faef74 --- /dev/null +++ b/talos/patches/spegel.yaml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + files: + - path: /etc/cri/conf.d/20-customization.part + op: create + content: | + [plugins."io.containerd.cri.v1.images"] + discard_unpacked_layers = false diff --git a/talos/patches/storage/limit-ephemeral.yaml b/talos/patches/storage/limit-ephemeral.yaml new file mode 100644 index 0000000..0ae73ce --- /dev/null +++ b/talos/patches/storage/limit-ephemeral.yaml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +apiVersion: v1alpha1 +kind: VolumeConfig +name: EPHEMERAL +provisioning: + maxSize: 30GB diff --git a/talos/patches/storage/local-path-provisioner/user-volume.yaml b/talos/patches/storage/local-path-provisioner/user-volume.yaml new file mode 100644 index 0000000..4fc940a --- /dev/null +++ b/talos/patches/storage/local-path-provisioner/user-volume.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +apiVersion: v1alpha1 +kind: UserVolumeConfig +name: local-path-provisioner +provisioning: + diskSelector: + match: system_disk + grow: true + maxSize: 10GB diff --git a/talos/patches/storage/longhorn.yaml b/talos/patches/storage/longhorn.yaml new file mode 100644 index 0000000..328e700 --- /dev/null +++ b/talos/patches/storage/longhorn.yaml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + kubelet: + extraMounts: + - destination: /var/lib/longhorn + type: bind + source: /var/lib/longhorn + options: + - bind + - rshared + - rw diff --git a/talos/patches/storage/longhorn/user-volume.yaml b/talos/patches/storage/longhorn/user-volume.yaml new file mode 100644 index 0000000..e94577f --- /dev/null +++ b/talos/patches/storage/longhorn/user-volume.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +apiVersion: v1alpha1 +kind: UserVolumeConfig +name: longhorn +provisioning: + diskSelector: + match: system_disk + grow: true + maxSize: 2000GB diff --git a/talos/patches/storage/openebs.yaml b/talos/patches/storage/openebs.yaml new file mode 100644 index 0000000..676f22c --- /dev/null +++ b/talos/patches/storage/openebs.yaml @@ -0,0 +1,17 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + # This is only needed on nodes that will have storage + sysctls: + vm.nr_hugepages: "1024" + nodeLabels: + openebs.io/engine: mayastor + # This is needed on ALL nodes + kubelet: + extraMounts: + - destination: /var/local + type: bind + source: /var/local + options: + - bind + - rshared + - rw diff --git a/talos/patches/system/allow-control-plane-workloads.yaml b/talos/patches/system/allow-control-plane-workloads.yaml new file mode 100644 index 0000000..d9ac291 --- /dev/null +++ b/talos/patches/system/allow-control-plane-workloads.yaml @@ -0,0 +1,3 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +cluster: + allowSchedulingOnControlPlanes: true diff --git a/talos/patches/system/hostname.yaml b/talos/patches/system/hostname.yaml new file mode 100644 index 0000000..2506b2e --- /dev/null +++ b/talos/patches/system/hostname.yaml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + network: + hostname: "{{node.hostname}}" diff --git a/talos/patches/system/install-disk.yaml b/talos/patches/system/install-disk.yaml new file mode 100644 index 0000000..227efb7 --- /dev/null +++ b/talos/patches/system/install-disk.yaml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + install: + disk: "{{node.install.disk}}" diff --git a/talos/patches/system/network.yaml b/talos/patches/system/network.yaml new file mode 100644 index 0000000..db0f37c --- /dev/null +++ b/talos/patches/system/network.yaml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json +machine: + network: + interfaces: + - interface: "{{node.network.interface}}" + dhcp: false + addresses: + - "{{node.network.ip}}" + routes: + - network: 0.0.0.0/0 + gateway: "{{node.network.gateway}}" diff --git a/talos/secrets/tailscale.key b/talos/secrets/tailscale.key new file mode 100644 index 0000000000000000000000000000000000000000..89f0b3a52753eb1cd856133a1c1f1784bba5d5f9 GIT binary patch literal 71 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 literal 0 HcmV?d00001