From beba05a56d9ef4b4fc6270e9637456a4a69609f8 Mon Sep 17 00:00:00 2001 From: Tamipes Date: Wed, 3 Jun 2026 11:47:22 +0200 Subject: [PATCH 1/3] feat: add `forgejo actions` yaml to auto build and push a container image --- .forgejo/workflows/build.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .forgejo/workflows/build.yaml diff --git a/.forgejo/workflows/build.yaml b/.forgejo/workflows/build.yaml new file mode 100644 index 0000000..32e5622 --- /dev/null +++ b/.forgejo/workflows/build.yaml @@ -0,0 +1,21 @@ +on: + push: + branches: + - main +jobs: + build: + runs-on: [ nix ] + steps: + - uses: actions/checkout@v4 + - name: Nix build + run: nix build --extra-experimental-features "flakes nix-command" .#docker-image + - name: Setup skopeo + run: curl -o /etc/containers/policy.json --create-dirs https://raw.githubusercontent.com/containers/skopeo/refs/heads/main/default-policy.json + - name: Push Image + run: | + skopeo copy --dest-password "$UPLOAD_TOKEN" --dest-username "$USERNAME" "docker-archive://$(realpath result)" "docker://$IMG_URL:${{ github.sha }}" && \ + skopeo copy --dest-password "$UPLOAD_TOKEN" --dest-username "$USERNAME" "docker-archive://$(realpath result)" "docker://$IMG_URL" + env: + USERNAME: tamipes + UPLOAD_TOKEN: ${{ secrets.UPLOAD_TOKEN }} + IMG_URL: git.tami.moe/tamipes/minecraft-ingress From b5f9c5e81cbc291db30a83ee662eea46fbd329a7 Mon Sep 17 00:00:00 2001 From: Tamipes Date: Wed, 3 Jun 2026 13:23:37 +0200 Subject: [PATCH 2/3] fix: could not initilaize `kube-rs` inside cluster, should infer config now --- src/kube_cache.rs | 9 ++++----- src/main.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/kube_cache.rs b/src/kube_cache.rs index c8be2e5..ea76a90 100644 --- a/src/kube_cache.rs +++ b/src/kube_cache.rs @@ -29,9 +29,8 @@ pub struct KubeCache { impl KubeCache { /// This initializes the creation of a "kubernetes client" /// and if it is not possible returns a None. - pub fn create() -> Option { - let kubeconfig = kube::config::Kubeconfig::read().unwrap(); - let client = Client::try_from(kubeconfig).unwrap(); + pub async fn create() -> Option { + let client = Client::try_default().await.unwrap(); let deployments: Api = Api::default_namespaced(client.clone()); let services: Api = Api::default_namespaced(client); @@ -209,9 +208,9 @@ impl MinecraftAPI for McApi { } impl McApi { - pub fn create() -> Option { + pub async fn create() -> Option { Some(Self { - cache: KubeCache::create()?, + cache: KubeCache::create().await?, map: Arc::new(tokio::sync::Mutex::new(HashMap::new())), }) } diff --git a/src/main.rs b/src/main.rs index 80c5a3c..044cbc9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,7 @@ async fn main() { let revision: &'static str = env!("COMMIT_HASH"); tracing::info!(revision); - let api = kube_cache::McApi::create().unwrap(); + let api = kube_cache::McApi::create().await.unwrap(); tracing::info!("initialized kube api"); let config: Config = Default::default(); From 00e0e7479e63dd9f19952c6584ec6dbc6f57cce1 Mon Sep 17 00:00:00 2001 From: Tamipes Date: Wed, 3 Jun 2026 23:25:54 +0200 Subject: [PATCH 3/3] feat: handle internall address differntly if running inside a cluster --- kube/roles.yaml | 2 +- src/kube_cache.rs | 78 +++++++++++++++++++++++++++++++++++------------ src/mc_server.rs | 7 ++--- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/kube/roles.yaml b/kube/roles.yaml index 09111bf..0c90cc6 100644 --- a/kube/roles.yaml +++ b/kube/roles.yaml @@ -47,7 +47,7 @@ spec: serviceAccountName: minecraft-ingress containers: - name: minecraft-ingress - image: git.tami.moe/tamipes/minecraft-ingress:latest + image: git.tami.moe/tamipes/minecraft-ingress:testing env: - name: FILTER_CONN value: '(addr == "87.229.85.222") || (addr == "") || (addr == "ogmur.xyz") || (addr == "@mat:matdoes.dev (hi honeypots) ") || (addr == "@mat:matdoes.dev ") || (addr == "slowstack.tv")' diff --git a/src/kube_cache.rs b/src/kube_cache.rs index ea76a90..9b9e671 100644 --- a/src/kube_cache.rs +++ b/src/kube_cache.rs @@ -1,6 +1,9 @@ use std::{collections::HashMap, fmt, sync::Arc, time::Duration}; -use k8s_openapi::api::{apps::v1::Deployment, core::v1::Service}; +use k8s_openapi::{ + api::{apps::v1::Deployment, core::v1::Service}, + apimachinery::pkg::util::intstr::IntOrString, +}; use kube::{ api::{ListParams, ObjectList, Patch, PatchParams}, runtime::reflector::Lookup, @@ -25,11 +28,16 @@ use crate::{ pub struct KubeCache { deployments: Api, services: Api, + in_cluster: bool, } impl KubeCache { /// This initializes the creation of a "kubernetes client" /// and if it is not possible returns a None. pub async fn create() -> Option { + let in_cluster = match std::env::var("KUBERNETES_SERVICE_HOST") { + Ok(x) => true, + Err(e) => false, + }; let client = Client::try_default().await.unwrap(); let deployments: Api = Api::default_namespaced(client.clone()); @@ -38,6 +46,7 @@ impl KubeCache { return Some(KubeCache { deployments, services, + in_cluster, }); } async fn get_dep(&self, name: &str) -> Result { @@ -63,10 +72,17 @@ impl KubeCache { Some(result.name()?.to_string()) } - pub async fn query_srv_addr(&self, addr: &str, port: &str) -> Option { + pub async fn query_srv(&self, addr: &str, port: &str) -> Option { let deploys = self.get_srvs().await; - let result = deploys.iter().find(|x| filter_label_value(x, addr, port))?; - Some(result.name()?.to_string()) + let result = deploys.into_iter().find(|x| { + let in_cluster = match x.spec.as_ref().unwrap().type_.as_ref() { + Some(t) => t == "ClusterIP", + None => false, + }; + let incorrect_type = in_cluster ^ self.in_cluster; + !incorrect_type && filter_label_value(&x, addr, port) + })?; + Some(result) } async fn set_dep_scale(&self, name: &str, num: i32) -> Result { @@ -100,11 +116,11 @@ impl MinecraftAPI for McApi { )) } }; - let srv_name = match self.cache.query_srv_addr(&addr, &port).await { + let service = match self.cache.query_srv(&addr, &port).await { Some(x) => x, None => { return Err(OpaqueError::create_with_kind( - "Failed to find service name by addr", + "Failed to find service by addr and port", "SrvNameLookupFailed", )) } @@ -116,20 +132,46 @@ impl MinecraftAPI for McApi { x.to_string() ) })?; - let service = self.cache.get_srv(&srv_name).await.map_err(|x| { - format!( - "Failed to query cache for service with dep_name err:{}", - x.to_string() - ) - })?; tracing::debug!("found kubernetes deployment & service"); + let service_port_spec = service.clone().spec.unwrap().ports.unwrap(); + let port = service_port_spec + .iter() + .find(|x| x.name.clone().unwrap() == "mc-router") + .ok_or(OpaqueError::create( + "Could not find \"mc-router\" nodePort for server", + ))?; + let port_string; + let inter_addr = match self.cache.in_cluster { + false => { + let node_port = port + .node_port + .map(|x| x.to_string()) + .ok_or(OpaqueError::create("Could not map nodePort to port string"))?; + port_string = node_port.clone(); + format!("localhost:{}", node_port) + } + true => { + let target_port = port.port; + let a = format!( + "{}.default.svc.cluster.local:{}", + service + .name() + .ok_or("Could not get name of ClusterIP service")?, + target_port + ); + port_string = a.clone(); + a + } + }; + tracing::info!(inter_addr = inter_addr); return Ok(Server { dep: deployment, srv: service, server_addr: addr.to_string(), - server_port: port.to_string(), + server_port: port_string, cache: self.cache.clone(), + inter_addr: inter_addr, }); } @@ -223,6 +265,7 @@ pub struct Server { server_addr: String, server_port: String, cache: KubeCache, + inter_addr: String, } impl fmt::Debug for Server { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -308,8 +351,8 @@ impl MinecraftServerHandle for Server { } } - fn get_internal_address(&self) -> Option { - Some(format!("localhost:{}", self.get_internal_port()?)) + fn get_internal_address(&self) -> &str { + self.inter_addr.as_str() } fn get_addr(&self) -> Option { @@ -358,11 +401,6 @@ impl MinecraftServerHandle for Server { } } - fn get_internal_port(&self) -> Option { - let a = self.srv.clone().spec.unwrap().ports.unwrap(); - let port = a.iter().find(|x| x.name.clone().unwrap() == "mc-router")?; - port.node_port.map(|x| x.to_string()) - } fn get_port(&self) -> Option { Some(self.server_port.clone()) } diff --git a/src/mc_server.rs b/src/mc_server.rs index 03b6a9d..88e6e8b 100644 --- a/src/mc_server.rs +++ b/src/mc_server.rs @@ -64,16 +64,13 @@ pub trait MinecraftServerHandle: Clone { async fn start(&self) -> Result<(), OpaqueError>; async fn stop(&self) -> Result<(), OpaqueError>; async fn query_status(&self) -> Result; - fn get_internal_address(&self) -> Option; - fn get_internal_port(&self) -> Option; + fn get_internal_address(&self) -> &str; fn get_addr(&self) -> Option; fn get_port(&self) -> Option; fn get_motd(&self) -> Option; async fn query_server_connectable(&self) -> Result { - let address = self - .get_internal_address() - .ok_or_else(|| "failed to get internal address from server")?; + let address = self.get_internal_address(); let server_stream = TcpStream::connect(address) .await .map_err(|_| "failed to connect to minecraft server")?;