diff --git a/kube/resources/components/shulker-operator/rbac/workload_cluster_role.yaml b/kube/resources/components/shulker-operator/rbac/workload_cluster_role.yaml index 23cf3fc4..8badfb91 100644 --- a/kube/resources/components/shulker-operator/rbac/workload_cluster_role.yaml +++ b/kube/resources/components/shulker-operator/rbac/workload_cluster_role.yaml @@ -38,6 +38,11 @@ rules: - serviceaccounts - events verbs: [create, delete, get, list, patch, update, watch] + - apiGroups: + - apps + resources: + - statefulsets + verbs: [create, delete, get, list, patch, update, watch] - apiGroups: - rbac.authorization.k8s.io resources: diff --git a/kube/resources/crd/bases/shulkermc.io_minecraftclusters.yaml b/kube/resources/crd/bases/shulkermc.io_minecraftclusters.yaml index f629eba6..ceed6f12 100644 --- a/kube/resources/crd/bases/shulkermc.io_minecraftclusters.yaml +++ b/kube/resources/crd/bases/shulkermc.io_minecraftclusters.yaml @@ -22,6 +22,17 @@ spec: description: Auto-generated derived type for MinecraftClusterSpec via `CustomResource` properties: spec: + properties: + redis: + nullable: true + properties: + type: + enum: + - ManagedSingleNode + type: string + required: + - type + type: object type: object status: description: The status object of `MinecraftCluster` diff --git a/packages/google-agones-sdk/bindings/java/src/main/java/dev/agones/AgonesSDKImpl.java b/packages/google-agones-sdk/bindings/java/src/main/java/dev/agones/AgonesSDKImpl.java index fa3dfba5..5847c858 100644 --- a/packages/google-agones-sdk/bindings/java/src/main/java/dev/agones/AgonesSDKImpl.java +++ b/packages/google-agones-sdk/bindings/java/src/main/java/dev/agones/AgonesSDKImpl.java @@ -34,11 +34,12 @@ public void onError(Throwable t) {} public void onCompleted() {} }; - private final Alpha alphaSdk = new AlphaImpl(); + private final Alpha alphaSdk; private AgonesSDKImpl(ManagedChannel channel) { this.channel = channel; this.asyncStub = SDKGrpc.newFutureStub(channel); + this.alphaSdk = new AlphaImpl(); } @Override diff --git a/packages/shulker-crds/src/v1alpha1/minecraft_cluster.rs b/packages/shulker-crds/src/v1alpha1/minecraft_cluster.rs index 57c62620..483ad198 100644 --- a/packages/shulker-crds/src/v1alpha1/minecraft_cluster.rs +++ b/packages/shulker-crds/src/v1alpha1/minecraft_cluster.rs @@ -1,6 +1,7 @@ use kube::CustomResource; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use strum::{Display, IntoStaticStr}; #[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)] #[kube( @@ -12,7 +13,25 @@ use serde::{Deserialize, Serialize}; printcolumn = r#"{"name": "Age", "type": "date", "jsonPath": ".metadata.creationTimestamp"}"# )] #[serde(rename_all = "camelCase")] -pub struct MinecraftClusterSpec {} +pub struct MinecraftClusterSpec { + #[serde(skip_serializing_if = "Option::is_none")] + pub redis: Option, +} + +#[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct MinecraftClusterRedisSpec { + pub type_: MinecraftClusterRedisDeploymentType, +} + +#[derive( + PartialEq, Deserialize, Serialize, Clone, Debug, Default, JsonSchema, IntoStaticStr, Display, +)] +pub enum MinecraftClusterRedisDeploymentType { + #[default] + ManagedSingleNode, + Provided, +} /// The status object of `MinecraftCluster` #[derive(Deserialize, Serialize, Clone, Debug, JsonSchema)] diff --git a/packages/shulker-operator/src/reconcilers/builder.rs b/packages/shulker-operator/src/reconcilers/builder.rs index a9b4edda..23c38490 100644 --- a/packages/shulker-operator/src/reconcilers/builder.rs +++ b/packages/shulker-operator/src/reconcilers/builder.rs @@ -134,6 +134,10 @@ pub async fn reconcile_builder< } } + if !builder.is_needed(owner) { + return Ok(None); + } + let mut new_resource = builder .build(owner, &name, existing_resource.as_ref()) .await diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/fixtures.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/fixtures.rs index 6f7eda72..e4fd1e63 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/fixtures.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/fixtures.rs @@ -10,7 +10,7 @@ lazy_static! { name: Some("my-cluster".to_string()), ..ObjectMeta::default() }, - spec: MinecraftClusterSpec {}, + spec: MinecraftClusterSpec { redis: None }, status: None, }; } diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/forwarding_secret.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/forwarding_secret.rs index 63b3a3d4..08b66073 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/forwarding_secret.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/forwarding_secret.rs @@ -42,11 +42,11 @@ impl ResourceBuilder for ForwardingSecretBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(cluster.namespace().unwrap().clone()), - labels: Some( - MinecraftClusterReconciler::get_common_labels(cluster) - .into_iter() - .collect(), - ), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "forwarding-secret".to_string(), + "proxy".to_string(), + )), ..ObjectMeta::default() }, type_: Some("Opaque".to_string()), diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs index fc9ba1c5..942fef51 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role.rs @@ -36,11 +36,11 @@ impl ResourceBuilder for MinecraftServerRoleBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(cluster.namespace().unwrap().clone()), - labels: Some( - MinecraftClusterReconciler::get_common_labels(cluster) - .into_iter() - .collect(), - ), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "role".to_string(), + "minecraft-server-rbac".to_string(), + )), ..ObjectMeta::default() }, rules: Some(vec![ diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role_binding.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role_binding.rs index bd765688..4a94ec59 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role_binding.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_role_binding.rs @@ -43,11 +43,11 @@ impl ResourceBuilder for MinecraftServerRoleBindingBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(cluster.namespace().unwrap().clone()), - labels: Some( - MinecraftClusterReconciler::get_common_labels(cluster) - .into_iter() - .collect(), - ), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "role-binding".to_string(), + "mincraft-server-rbac".to_string(), + )), ..ObjectMeta::default() }, role_ref: RoleRef { diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_service_account.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_service_account.rs index e60dd919..f7bab3b3 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_service_account.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/minecraft_server_service_account.rs @@ -35,11 +35,11 @@ impl ResourceBuilder for MinecraftServerServiceAccountBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(cluster.namespace().unwrap().clone()), - labels: Some( - MinecraftClusterReconciler::get_common_labels(cluster) - .into_iter() - .collect(), - ), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "service-account".to_string(), + "minecraft-server-rbac".to_string(), + )), ..ObjectMeta::default() }, ..ServiceAccount::default() diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/mod.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/mod.rs index 26c95462..555dbd22 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/mod.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/mod.rs @@ -2,7 +2,8 @@ use std::{collections::BTreeMap, sync::Arc, time::Duration}; use futures::StreamExt; use k8s_openapi::api::{ - core::v1::{Secret, ServiceAccount}, + apps::v1::StatefulSet, + core::v1::{Secret, Service, ServiceAccount}, rbac::v1::{Role, RoleBinding}, }; use kube::{ @@ -24,7 +25,8 @@ use self::{ minecraft_server_role_binding::MinecraftServerRoleBindingBuilder, minecraft_server_service_account::MinecraftServerServiceAccountBuilder, proxy_role::ProxyRoleBuilder, proxy_role_binding::ProxyRoleBindingBuilder, - proxy_service_account::ProxyServiceAccountBuilder, + proxy_service_account::ProxyServiceAccountBuilder, redis_service::RedisServiceBuilder, + redis_stateful_set::RedisStatefulSetBuilder, }; use super::{builder::reconcile_builder, ReconcilerError, Result}; @@ -36,6 +38,8 @@ mod minecraft_server_service_account; mod proxy_role; mod proxy_role_binding; mod proxy_service_account; +mod redis_service; +mod redis_stateful_set; #[cfg(test)] mod fixtures; @@ -53,6 +57,8 @@ struct MinecraftClusterReconciler { minecraft_server_service_account_builder: MinecraftServerServiceAccountBuilder, minecraft_server_role_builder: MinecraftServerRoleBuilder, minecraft_server_role_binding_builder: MinecraftServerRoleBindingBuilder, + redis_service_builder: RedisServiceBuilder, + redis_stateful_set_builder: RedisStatefulSetBuilder, } impl MinecraftClusterReconciler { @@ -76,6 +82,8 @@ impl MinecraftClusterReconciler { cluster.as_ref(), ) .await?; + reconcile_builder(&self.redis_service_builder, cluster.as_ref()).await?; + reconcile_builder(&self.redis_stateful_set_builder, cluster.as_ref()).await?; Ok(Action::requeue(Duration::from_secs(5 * 60))) } @@ -90,12 +98,25 @@ impl MinecraftClusterReconciler { Ok(Action::await_change()) } - fn get_common_labels(cluster: &MinecraftCluster) -> BTreeMap { + fn get_labels( + cluster: &MinecraftCluster, + name: String, + component: String, + ) -> BTreeMap { BTreeMap::from([ - ("app.kubernetes.io/name".to_string(), cluster.name_any()), + ("app.kubernetes.io/name".to_string(), name.clone()), ( - "app.kubernetes.io/component".to_string(), - "cluster".to_string(), + "app.kubernetes.io/instance".to_string(), + format!("{}-{}", name, cluster.name_any()), + ), + ("app.kubernetes.io/component".to_string(), component), + ( + "app.kubernetes.io/part-of".to_string(), + format!("cluster-{}", cluster.name_any()), + ), + ( + "app.kubernetes.io/managed-by".to_string(), + "shulker-operator".to_string(), ), ( "minecraftcluster.shulkermc.io/name".to_string(), @@ -159,6 +180,8 @@ pub async fn run(client: Client) { minecraft_server_role_binding_builder: MinecraftServerRoleBindingBuilder::new( client.clone(), ), + redis_service_builder: RedisServiceBuilder::new(client.clone()), + redis_stateful_set_builder: RedisStatefulSetBuilder::new(client.clone()), }; Controller::new(clusters_api, Config::default().any_semantic()) @@ -178,6 +201,14 @@ pub async fn run(client: Client) { Api::::all(client.clone()), Config::default().any_semantic(), ) + .owns( + Api::::all(client.clone()), + Config::default().any_semantic(), + ) + .owns( + Api::::all(client.clone()), + Config::default().any_semantic(), + ) .shutdown_on_signal() .run(reconcile, error_policy, context.into()) .filter_map(|x| async move { std::result::Result::ok(x) }) diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role.rs index 34669f74..789f51ba 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role.rs @@ -36,11 +36,11 @@ impl ResourceBuilder for ProxyRoleBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(cluster.namespace().unwrap().clone()), - labels: Some( - MinecraftClusterReconciler::get_common_labels(cluster) - .into_iter() - .collect(), - ), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "role".to_string(), + "proxy-rbac".to_string(), + )), ..ObjectMeta::default() }, rules: Some(vec![ @@ -94,12 +94,10 @@ mod tests { // G let client = create_client_mock(); let builder = super::ProxyRoleBuilder::new(client); + let name = super::ProxyRoleBuilder::name(&TEST_CLUSTER); // W - let role = builder - .build(&TEST_CLUSTER, "my-cluster-proxy", None) - .await - .unwrap(); + let role = builder.build(&TEST_CLUSTER, &name, None).await.unwrap(); // T insta::assert_yaml_snapshot!(role); @@ -110,12 +108,10 @@ mod tests { // G let client = create_client_mock(); let builder = super::ProxyRoleBuilder::new(client); + let name = super::ProxyRoleBuilder::name(&TEST_CLUSTER); // W - let role = builder - .build(&TEST_CLUSTER, "my-cluster-proxy", None) - .await - .unwrap(); + let role = builder.build(&TEST_CLUSTER, &name, None).await.unwrap(); // T assert!(role.rules.as_ref().unwrap().iter().any(|rule| { @@ -130,12 +126,10 @@ mod tests { // G let client = create_client_mock(); let builder = super::ProxyRoleBuilder::new(client); + let name = super::ProxyRoleBuilder::name(&TEST_CLUSTER); // W - let role = builder - .build(&TEST_CLUSTER, "my-cluster-proxy", None) - .await - .unwrap(); + let role = builder.build(&TEST_CLUSTER, &name, None).await.unwrap(); // T assert!(role.rules.as_ref().unwrap().iter().any(|rule| { @@ -155,12 +149,10 @@ mod tests { // G let client = create_client_mock(); let builder = super::ProxyRoleBuilder::new(client); + let name = super::ProxyRoleBuilder::name(&TEST_CLUSTER); // W - let role = builder - .build(&TEST_CLUSTER, "my-cluster-proxy", None) - .await - .unwrap(); + let role = builder.build(&TEST_CLUSTER, &name, None).await.unwrap(); // T assert!(role.rules.as_ref().unwrap().iter().any(|rule| { diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role_binding.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role_binding.rs index 30f5e3fa..094b88f1 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role_binding.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_role_binding.rs @@ -43,11 +43,11 @@ impl ResourceBuilder for ProxyRoleBindingBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(cluster.namespace().unwrap().clone()), - labels: Some( - MinecraftClusterReconciler::get_common_labels(cluster) - .into_iter() - .collect(), - ), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "role-binding".to_string(), + "proxy-rbac".to_string(), + )), ..ObjectMeta::default() }, role_ref: RoleRef { diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_service_account.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_service_account.rs index 37c69c35..aa7cdef0 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_service_account.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/proxy_service_account.rs @@ -35,11 +35,11 @@ impl ResourceBuilder for ProxyServiceAccountBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(cluster.namespace().unwrap().clone()), - labels: Some( - MinecraftClusterReconciler::get_common_labels(cluster) - .into_iter() - .collect(), - ), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "service-account".to_string(), + "proxy-rbac".to_string(), + )), ..ObjectMeta::default() }, ..ServiceAccount::default() @@ -76,12 +76,10 @@ mod tests { // G let client = create_client_mock(); let builder = super::ProxyServiceAccountBuilder::new(client); + let name = super::ProxyServiceAccountBuilder::name(&TEST_CLUSTER); // W - let service_account = builder - .build(&TEST_CLUSTER, "my-cluster-proxy", None) - .await - .unwrap(); + let service_account = builder.build(&TEST_CLUSTER, &name, None).await.unwrap(); // T insta::assert_yaml_snapshot!(service_account); diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_service.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_service.rs new file mode 100644 index 00000000..cd9626e8 --- /dev/null +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_service.rs @@ -0,0 +1,165 @@ +use k8s_openapi::api::core::v1::Service; +use k8s_openapi::api::core::v1::ServicePort; +use k8s_openapi::api::core::v1::ServiceSpec; +use k8s_openapi::apimachinery::pkg::util::intstr::IntOrString; +use kube::core::ObjectMeta; +use kube::Api; +use kube::Client; +use kube::ResourceExt; +use shulker_crds::v1alpha1::minecraft_cluster::MinecraftClusterRedisDeploymentType; + +use crate::reconcilers::builder::ResourceBuilder; +use shulker_crds::v1alpha1::minecraft_cluster::MinecraftCluster; + +use super::MinecraftClusterReconciler; + +pub struct RedisServiceBuilder { + client: Client, +} + +#[async_trait::async_trait] +impl ResourceBuilder for RedisServiceBuilder { + type OwnerType = MinecraftCluster; + type ResourceType = Service; + + fn name(cluster: &Self::OwnerType) -> String { + format!("{}-redis-managed", cluster.name_any()) + } + + fn api(&self, cluster: &Self::OwnerType) -> kube::Api { + Api::namespaced(self.client.clone(), cluster.namespace().as_ref().unwrap()) + } + + fn is_needed(&self, cluster: &Self::OwnerType) -> bool { + cluster.spec.redis.as_ref().map_or(true, |redis| { + redis.type_ == MinecraftClusterRedisDeploymentType::ManagedSingleNode + }) + } + + async fn build( + &self, + cluster: &Self::OwnerType, + name: &str, + _existing_service: Option<&Self::ResourceType>, + ) -> Result { + let service = Service { + metadata: ObjectMeta { + name: Some(name.to_string()), + namespace: Some(cluster.namespace().unwrap().clone()), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "redis".to_string(), + "redis".to_string(), + )), + ..ObjectMeta::default() + }, + spec: Some(ServiceSpec { + selector: Some(MinecraftClusterReconciler::get_labels( + cluster, + "redis".to_string(), + "redis".to_string(), + )), + type_: Some("ClusterIP".to_string()), + ports: Some(vec![ServicePort { + name: Some("redis".to_string()), + protocol: Some("TCP".to_string()), + port: 6379, + target_port: Some(IntOrString::String("redis".to_string())), + ..ServicePort::default() + }]), + ..ServiceSpec::default() + }), + ..Service::default() + }; + + Ok(service) + } +} + +impl RedisServiceBuilder { + pub fn new(client: Client) -> Self { + RedisServiceBuilder { client } + } +} + +#[cfg(test)] +mod tests { + use shulker_crds::v1alpha1::minecraft_cluster::{ + MinecraftClusterRedisDeploymentType, MinecraftClusterRedisSpec, + }; + + use crate::reconcilers::{ + builder::ResourceBuilder, + minecraft_cluster::fixtures::{create_client_mock, TEST_CLUSTER}, + }; + + #[test] + fn name_contains_fleet_name() { + // W + let name = super::RedisServiceBuilder::name(&TEST_CLUSTER); + + // T + assert_eq!(name, "my-cluster-redis-managed"); + } + + #[tokio::test] + async fn is_needed_without_config() { + // G + let client = create_client_mock(); + let builder = super::RedisServiceBuilder::new(client); + + // W + let is_needed = builder.is_needed(&TEST_CLUSTER); + + // T + assert!(is_needed); + } + + #[tokio::test] + async fn is_needed_with_managed_type() { + // G + let client = create_client_mock(); + let builder = super::RedisServiceBuilder::new(client); + let mut cluster = TEST_CLUSTER.clone(); + cluster.spec.redis = Some(MinecraftClusterRedisSpec { + type_: MinecraftClusterRedisDeploymentType::ManagedSingleNode, + }); + + // W + let is_needed = builder.is_needed(&cluster); + + // T + assert!(is_needed); + } + + #[tokio::test] + async fn is_needed_with_provided_type() { + // G + let client = create_client_mock(); + let builder = super::RedisServiceBuilder::new(client); + let mut cluster = TEST_CLUSTER.clone(); + cluster.spec.redis = Some(MinecraftClusterRedisSpec { + type_: MinecraftClusterRedisDeploymentType::Provided, + }); + + // W + let is_needed = builder.is_needed(&cluster); + + // T + assert!(!is_needed); + } + + #[tokio::test] + async fn build_snapshot() { + // G + let client = create_client_mock(); + let builder = super::RedisServiceBuilder::new(client); + let name = super::RedisServiceBuilder::name(&TEST_CLUSTER); + + // W + let service = builder.build(&TEST_CLUSTER, &name, None).await.unwrap(); + + // T + insta::assert_yaml_snapshot!(service); + } +} diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_stateful_set.rs b/packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_stateful_set.rs new file mode 100644 index 00000000..c04acfcb --- /dev/null +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_stateful_set.rs @@ -0,0 +1,258 @@ +use std::collections::BTreeMap; + +use k8s_openapi::api::apps::v1::StatefulSet; +use k8s_openapi::api::apps::v1::StatefulSetSpec; +use k8s_openapi::api::core::v1::Capabilities; +use k8s_openapi::api::core::v1::Container; +use k8s_openapi::api::core::v1::ContainerPort; +use k8s_openapi::api::core::v1::EnvVar; +use k8s_openapi::api::core::v1::PersistentVolumeClaim; +use k8s_openapi::api::core::v1::PersistentVolumeClaimSpec; +use k8s_openapi::api::core::v1::PodSpec; +use k8s_openapi::api::core::v1::PodTemplateSpec; +use k8s_openapi::api::core::v1::ResourceRequirements; +use k8s_openapi::api::core::v1::SecurityContext; +use k8s_openapi::api::core::v1::VolumeMount; +use k8s_openapi::apimachinery::pkg::api::resource::Quantity; +use k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector; +use kube::core::ObjectMeta; +use kube::Api; +use kube::Client; +use kube::ResourceExt; +use shulker_crds::v1alpha1::minecraft_cluster::MinecraftClusterRedisDeploymentType; + +use super::redis_service::RedisServiceBuilder; +use super::MinecraftClusterReconciler; +use crate::reconcilers::builder::ResourceBuilder; +use shulker_crds::v1alpha1::minecraft_cluster::MinecraftCluster; + +const REDIS_IMAGE: &str = "redis:7-alpine"; +const REDIS_DATA_DIR: &str = "/data"; + +lazy_static! { + static ref REDIS_SECURITY_CONTEXT: SecurityContext = SecurityContext { + allow_privilege_escalation: Some(false), + read_only_root_filesystem: Some(true), + run_as_non_root: Some(true), + run_as_user: Some(1000), + capabilities: Some(Capabilities { + drop: Some(vec!["ALL".to_string()]), + ..Capabilities::default() + }), + ..SecurityContext::default() + }; +} + +pub struct RedisStatefulSetBuilder { + client: Client, +} + +#[async_trait::async_trait] +impl ResourceBuilder for RedisStatefulSetBuilder { + type OwnerType = MinecraftCluster; + type ResourceType = StatefulSet; + + fn name(cluster: &Self::OwnerType) -> String { + format!("{}-redis-managed", cluster.name_any()) + } + + fn api(&self, cluster: &Self::OwnerType) -> kube::Api { + Api::namespaced(self.client.clone(), cluster.namespace().as_ref().unwrap()) + } + + fn is_needed(&self, cluster: &Self::OwnerType) -> bool { + cluster.spec.redis.as_ref().map_or(true, |redis| { + redis.type_ == MinecraftClusterRedisDeploymentType::ManagedSingleNode + }) + } + + async fn build( + &self, + cluster: &Self::OwnerType, + name: &str, + _existing_stateful_set: Option<&Self::ResourceType>, + ) -> Result { + let stateful_set = StatefulSet { + metadata: ObjectMeta { + name: Some(name.to_string()), + namespace: Some(cluster.namespace().unwrap().clone()), + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "redis".to_string(), + "redis".to_string(), + )), + ..ObjectMeta::default() + }, + spec: Some(StatefulSetSpec { + selector: LabelSelector { + match_labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "redis".to_string(), + "redis".to_string(), + )), + ..LabelSelector::default() + }, + service_name: RedisServiceBuilder::name(cluster), + replicas: Some(1), + template: RedisStatefulSetBuilder::get_pod_template_spec(cluster), + volume_claim_templates: Some(RedisStatefulSetBuilder::get_volume_claim_templates()), + ..StatefulSetSpec::default() + }), + ..StatefulSet::default() + }; + + Ok(stateful_set) + } +} + +impl RedisStatefulSetBuilder { + pub fn new(client: Client) -> Self { + RedisStatefulSetBuilder { client } + } + + fn get_pod_template_spec(cluster: &MinecraftCluster) -> PodTemplateSpec { + let pod_spec = PodSpec { + containers: vec![Container { + image: Some(REDIS_IMAGE.to_string()), + name: "redis".to_string(), + command: Some(vec![ + "redis-server".to_string(), + format!("--dir {}", REDIS_DATA_DIR), + ]), + env: Some(vec![EnvVar { + name: "MASTER".to_string(), + value: Some("true".to_string()), + ..EnvVar::default() + }]), + ports: Some(vec![ContainerPort { + name: Some("redis".to_string()), + container_port: 6379, + ..ContainerPort::default() + }]), + security_context: Some(REDIS_SECURITY_CONTEXT.clone()), + volume_mounts: Some(vec![VolumeMount { + name: "data".to_string(), + mount_path: REDIS_DATA_DIR.to_string(), + ..VolumeMount::default() + }]), + ..Container::default() + }], + ..PodSpec::default() + }; + + PodTemplateSpec { + metadata: Some(ObjectMeta { + labels: Some(MinecraftClusterReconciler::get_labels( + cluster, + "redis".to_string(), + "redis".to_string(), + )), + ..ObjectMeta::default() + }), + spec: Some(pod_spec), + } + } + + fn get_volume_claim_templates() -> Vec { + vec![PersistentVolumeClaim { + metadata: ObjectMeta { + name: Some("data".to_string()), + ..ObjectMeta::default() + }, + spec: Some(PersistentVolumeClaimSpec { + access_modes: Some(vec!["ReadWriteOnce".to_string()]), + resources: Some(ResourceRequirements { + requests: Some(BTreeMap::from([( + "storage".to_string(), + Quantity("1Gi".to_string()), + )])), + ..ResourceRequirements::default() + }), + ..PersistentVolumeClaimSpec::default() + }), + ..PersistentVolumeClaim::default() + }] + } +} + +#[cfg(test)] +mod tests { + use shulker_crds::v1alpha1::minecraft_cluster::{ + MinecraftClusterRedisDeploymentType, MinecraftClusterRedisSpec, + }; + + use crate::reconcilers::{ + builder::ResourceBuilder, + minecraft_cluster::fixtures::{create_client_mock, TEST_CLUSTER}, + }; + + #[test] + fn name_contains_cluster_name() { + // W + let name = super::RedisStatefulSetBuilder::name(&TEST_CLUSTER); + + // T + assert_eq!(name, "my-cluster-redis-managed"); + } + + #[tokio::test] + async fn is_needed_without_config() { + // G + let client = create_client_mock(); + let builder = super::RedisStatefulSetBuilder::new(client); + + // W + let is_needed = builder.is_needed(&TEST_CLUSTER); + + // T + assert!(is_needed); + } + + #[tokio::test] + async fn is_needed_with_managed_type() { + // G + let client = create_client_mock(); + let builder = super::RedisStatefulSetBuilder::new(client); + let mut cluster = TEST_CLUSTER.clone(); + cluster.spec.redis = Some(MinecraftClusterRedisSpec { + type_: MinecraftClusterRedisDeploymentType::ManagedSingleNode, + }); + + // W + let is_needed = builder.is_needed(&cluster); + + // T + assert!(is_needed); + } + + #[tokio::test] + async fn is_needed_with_provided_type() { + // G + let client = create_client_mock(); + let builder = super::RedisStatefulSetBuilder::new(client); + let mut cluster = TEST_CLUSTER.clone(); + cluster.spec.redis = Some(MinecraftClusterRedisSpec { + type_: MinecraftClusterRedisDeploymentType::Provided, + }); + + // W + let is_needed = builder.is_needed(&cluster); + + // T + assert!(!is_needed); + } + + #[tokio::test] + async fn build_snapshot() { + // G + let client = create_client_mock(); + let builder = super::RedisStatefulSetBuilder::new(client); + let name = super::RedisStatefulSetBuilder::name(&TEST_CLUSTER); + + // W + let role = builder.build(&TEST_CLUSTER, &name, None).await.unwrap(); + + // T + insta::assert_yaml_snapshot!(role); + } +} diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__forwarding_secret__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__forwarding_secret__tests__build_snapshot.snap index b9b29541..42e458dc 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__forwarding_secret__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__forwarding_secret__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: v1 kind: Secret metadata: labels: - app.kubernetes.io/component: cluster - app.kubernetes.io/name: my-cluster + app.kubernetes.io/component: proxy + app.kubernetes.io/instance: forwarding-secret-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: forwarding-secret + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster name: my-cluster-forwarding-secret namespace: default diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap index 9835e99b..ea604425 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - app.kubernetes.io/component: cluster - app.kubernetes.io/name: my-cluster + app.kubernetes.io/component: minecraft-server-rbac + app.kubernetes.io/instance: role-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: role + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster name: "shulker:my-cluster:server" namespace: default diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role_binding__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role_binding__tests__build_snapshot.snap index c45002f5..91bfa8fe 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role_binding__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_role_binding__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: cluster - app.kubernetes.io/name: my-cluster + app.kubernetes.io/component: mincraft-server-rbac + app.kubernetes.io/instance: role-binding-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: role-binding + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster name: "shulker:my-cluster:server" namespace: default diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_service_account__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_service_account__tests__build_snapshot.snap index 7d1bbaab..5f5ec8ee 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_service_account__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__minecraft_server_service_account__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - app.kubernetes.io/component: cluster - app.kubernetes.io/name: my-cluster + app.kubernetes.io/component: minecraft-server-rbac + app.kubernetes.io/instance: service-account-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: service-account + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster name: shulker-my-cluster-server namespace: default diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role__tests__build_snapshot.snap index fb108089..0ff54bfd 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role__tests__build_snapshot.snap @@ -6,10 +6,13 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - app.kubernetes.io/component: cluster - app.kubernetes.io/name: my-cluster + app.kubernetes.io/component: proxy-rbac + app.kubernetes.io/instance: role-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: role + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster - name: my-cluster-proxy + name: "shulker:my-cluster:proxy" namespace: default rules: - apiGroups: diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role_binding__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role_binding__tests__build_snapshot.snap index 4bf92c3e..19d62342 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role_binding__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_role_binding__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: cluster - app.kubernetes.io/name: my-cluster + app.kubernetes.io/component: proxy-rbac + app.kubernetes.io/instance: role-binding-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: role-binding + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster name: "shulker:my-cluster:proxy" namespace: default diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_service_account__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_service_account__tests__build_snapshot.snap index 2c451091..2c1465f7 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_service_account__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__proxy_service_account__tests__build_snapshot.snap @@ -6,9 +6,12 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - app.kubernetes.io/component: cluster - app.kubernetes.io/name: my-cluster + app.kubernetes.io/component: proxy-rbac + app.kubernetes.io/instance: service-account-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: service-account + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster - name: my-cluster-proxy + name: shulker-my-cluster-proxy namespace: default diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__redis_service__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__redis_service__tests__build_snapshot.snap new file mode 100644 index 00000000..6e722460 --- /dev/null +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__redis_service__tests__build_snapshot.snap @@ -0,0 +1,31 @@ +--- +source: packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_service.rs +expression: service +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: redis + app.kubernetes.io/instance: redis-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: redis + app.kubernetes.io/part-of: cluster-my-cluster + minecraftcluster.shulkermc.io/name: my-cluster + name: my-cluster-redis-managed + namespace: default +spec: + ports: + - name: redis + port: 6379 + protocol: TCP + targetPort: redis + selector: + app.kubernetes.io/component: redis + app.kubernetes.io/instance: redis-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: redis + app.kubernetes.io/part-of: cluster-my-cluster + minecraftcluster.shulkermc.io/name: my-cluster + type: ClusterIP + diff --git a/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__redis_stateful_set__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__redis_stateful_set__tests__build_snapshot.snap new file mode 100644 index 00000000..4cb66c08 --- /dev/null +++ b/packages/shulker-operator/src/reconcilers/minecraft_cluster/snapshots/shulker_operator__reconcilers__minecraft_cluster__redis_stateful_set__tests__build_snapshot.snap @@ -0,0 +1,72 @@ +--- +source: packages/shulker-operator/src/reconcilers/minecraft_cluster/redis_stateful_set.rs +expression: role +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app.kubernetes.io/component: redis + app.kubernetes.io/instance: redis-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: redis + app.kubernetes.io/part-of: cluster-my-cluster + minecraftcluster.shulkermc.io/name: my-cluster + name: my-cluster-redis-managed + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: redis + app.kubernetes.io/instance: redis-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: redis + app.kubernetes.io/part-of: cluster-my-cluster + minecraftcluster.shulkermc.io/name: my-cluster + serviceName: my-cluster-redis-managed + template: + metadata: + labels: + app.kubernetes.io/component: redis + app.kubernetes.io/instance: redis-my-cluster + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: redis + app.kubernetes.io/part-of: cluster-my-cluster + minecraftcluster.shulkermc.io/name: my-cluster + spec: + containers: + - command: + - redis-server + - "--dir /data" + env: + - name: MASTER + value: "true" + image: "redis:7-alpine" + name: redis + ports: + - containerPort: 6379 + name: redis + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + volumeMounts: + - mountPath: /data + name: data + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/config_map.rs b/packages/shulker-operator/src/reconcilers/minecraft_server/config_map.rs index 3e242175..6a7698b0 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server/config_map.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server/config_map.rs @@ -50,11 +50,11 @@ impl ResourceBuilder for ConfigMapBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(minecraft_server.namespace().unwrap().clone()), - labels: Some( - MinecraftServerReconciler::get_common_labels(minecraft_server) - .into_iter() - .collect(), - ), + labels: Some(MinecraftServerReconciler::get_labels( + minecraft_server, + "config".to_string(), + "minecraft-server".to_string(), + )), ..ObjectMeta::default() }, data: Some(Self::get_data_from_spec(&minecraft_server.spec.config)), diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs b/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs index 03691629..699cba5b 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs @@ -88,11 +88,11 @@ impl ResourceBuilder for GameServerBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(minecraft_server.namespace().unwrap().clone()), - labels: Some( - MinecraftServerReconciler::get_common_labels(minecraft_server) - .into_iter() - .collect(), - ), + labels: Some(MinecraftServerReconciler::get_labels( + minecraft_server, + "minecraft-server".to_string(), + "minecraft-server".to_string(), + )), ..ObjectMeta::default() }, spec: Self::get_game_server_spec(&self.resourceref_resolver, minecraft_server).await?, @@ -194,7 +194,7 @@ impl GameServerBuilder { ..Container::default() }], service_account_name: Some(format!( - "{}-server", + "shulker-{}-server", &minecraft_server.spec.cluster_ref.name )), restart_policy: Some("Never".to_string()), @@ -255,8 +255,10 @@ impl GameServerBuilder { Ok(PodTemplateSpec { metadata: Some(ObjectMeta { - labels: Some(MinecraftServerReconciler::get_common_labels( + labels: Some(MinecraftServerReconciler::get_labels( minecraft_server, + "minecraft-server".to_string(), + "minecraft-server".to_string(), )), annotations: Some(BTreeMap::::from([( "minecraftserver.shulkermc.io/tags".to_string(), diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/mod.rs b/packages/shulker-operator/src/reconcilers/minecraft_server/mod.rs index 789e3a4c..9bf34444 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server/mod.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server/mod.rs @@ -5,12 +5,7 @@ use google_agones_crds::v1::game_server::GameServer; use k8s_openapi::api::core::v1::ConfigMap; use kube::{ api::{DeleteParams, ListParams, PatchParams}, - runtime::{ - controller::Action, - finalizer::{finalizer, Event as Finalizer}, - watcher::Config, - Controller, - }, + runtime::{controller::Action, watcher::Config, Controller}, Api, Client, ResourceExt, }; use tracing::*; @@ -30,8 +25,6 @@ pub mod gameserver; #[cfg(test)] mod fixtures; -static FINALIZER: &str = "minecraftservers.shulkermc.io"; - struct MinecraftServerReconciler { client: kube::Client, @@ -108,40 +101,31 @@ impl MinecraftServerReconciler { Ok(Action::await_change()) } - fn get_common_labels(minecraft_server: &MinecraftServer) -> BTreeMap { - let fleet_owner = minecraft_server - .owner_references() - .iter() - .find(|owner| owner.kind == "MinecraftServerFleet"); - - let mut labels = BTreeMap::from([ + fn get_labels( + minecraft_server: &MinecraftServer, + name: String, + component: String, + ) -> BTreeMap { + BTreeMap::from([ + ("app.kubernetes.io/name".to_string(), name.to_string()), ( - "app.kubernetes.io/name".to_string(), - minecraft_server.name_any(), + "app.kubernetes.io/instance".to_string(), + format!("{}-{}", name, minecraft_server.name_any()), ), + ("app.kubernetes.io/component".to_string(), component), ( - "app.kubernetes.io/component".to_string(), - "minecraftserver".to_string(), + "app.kubernetes.io/part-of".to_string(), + format!("cluster-{}", minecraft_server.spec.cluster_ref.name.clone()), + ), + ( + "app.kubernetes.io/managed-by".to_string(), + "shulker-operator".to_string(), ), ( "minecraftcluster.shulkermc.io/name".to_string(), minecraft_server.spec.cluster_ref.name.clone(), ), - ]); - - if let Some(owner) = &fleet_owner { - labels.insert("app.kubernetes.io/name".to_string(), owner.name.clone()); - labels.insert( - "app.kubernetes.io/instance".to_string(), - minecraft_server.name_any(), - ); - labels.insert( - "minecraftcluster.shulkermc.io/name".to_string(), - owner.name.clone(), - ); - } - - labels + ]) } } @@ -159,22 +143,12 @@ async fn reconcile( "reconciling MinecraftServer", ); - finalizer( - &minecraft_servers_api, - FINALIZER, - minecraft_server, - |event| async { - match event { - Finalizer::Apply(minecraft_server) => { - ctx.reconcile(minecraft_servers_api.clone(), minecraft_server.clone()) - .await - } - Finalizer::Cleanup(minecraft_server) => ctx.cleanup(minecraft_server.clone()).await, - } - }, - ) - .await - .map_err(|e| ReconcilerError::FinalizerError(Box::new(e))) + if minecraft_server.metadata.deletion_timestamp.is_none() { + ctx.reconcile(minecraft_servers_api.clone(), minecraft_server.clone()) + .await + } else { + ctx.cleanup(minecraft_server.clone()).await + } } fn error_policy( diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__config_map__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__config_map__tests__build_snapshot.snap index 076a0a3a..e9a405b3 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__config_map__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__config_map__tests__build_snapshot.snap @@ -12,8 +12,11 @@ data: spigot-config.yml: "settings:\n bungeecord: false\n restart-on-crash: false\nadvancements:\n disable-saving: true\nplayers:\n disable-saving: true\nstats:\n disable-saving: true\nsave-user-cache-on-stop-only: true\n\n" metadata: labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: config-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: config + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster name: my-server-config namespace: default diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap index c83c6fb4..cf36d810 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_server/snapshots/shulker_operator__reconcilers__minecraft_server__gameserver__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: agones.dev/v1 kind: GameServer metadata: labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: minecraft-server-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: minecraft-server + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster name: my-server namespace: default @@ -26,8 +29,11 @@ spec: annotations: minecraftserver.shulkermc.io/tags: lobby labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: minecraft-server-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: minecraft-server + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster spec: containers: @@ -127,7 +133,7 @@ spec: nodeSelector: beta.kubernetes.io/os: linux restartPolicy: Never - serviceAccountName: my-cluster-server + serviceAccountName: shulker-my-cluster-server volumes: - configMap: name: my-server-config diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/config_map.rs b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/config_map.rs index 7c2169aa..0593293b 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/config_map.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/config_map.rs @@ -40,9 +40,7 @@ impl ResourceBuilder for ConfigMapBuilder { name: Some(name.to_string()), namespace: Some(minecraft_server_fleet.namespace().unwrap().clone()), labels: Some( - MinecraftServerFleetReconciler::get_common_labels(minecraft_server_fleet) - .into_iter() - .collect(), + MinecraftServerFleetReconciler::get_labels(minecraft_server_fleet, "config".to_string(), "minecraft-server".to_string()), ), ..ObjectMeta::default() }, diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet.rs b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet.rs index d4145ceb..58116678 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet.rs @@ -77,8 +77,12 @@ impl ResourceBuilder for FleetBuilder { None => minecraft_server_fleet.spec.replicas as i32, }; - let mut labels = MinecraftServerFleetReconciler::get_common_labels(minecraft_server_fleet); - labels.extend( + let mut template_labels = MinecraftServerFleetReconciler::get_labels( + minecraft_server_fleet, + "minecraft-server".to_string(), + "minecraft-server".to_string(), + ); + template_labels.extend( game_server_spec .template .metadata @@ -88,8 +92,8 @@ impl ResourceBuilder for FleetBuilder { }), ); - let mut annotations = BTreeMap::::new(); - annotations.extend( + let mut template_annotations = BTreeMap::::new(); + template_annotations.extend( game_server_spec .template .metadata @@ -101,11 +105,11 @@ impl ResourceBuilder for FleetBuilder { if let Some(metadata) = &minecraft_server_fleet.spec.template.metadata { if let Some(additional_labels) = metadata.labels.clone() { - labels.extend(additional_labels); + template_labels.extend(additional_labels); } if let Some(additional_annotations) = metadata.annotations.clone() { - annotations.extend(additional_annotations); + template_annotations.extend(additional_annotations); } } @@ -113,11 +117,11 @@ impl ResourceBuilder for FleetBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(minecraft_server_fleet.namespace().unwrap().clone()), - labels: Some( - MinecraftServerFleetReconciler::get_common_labels(minecraft_server_fleet) - .into_iter() - .collect(), - ), + labels: Some(MinecraftServerFleetReconciler::get_labels( + minecraft_server_fleet, + "minecraft-server".to_string(), + "minecraft-server".to_string(), + )), ..ObjectMeta::default() }, spec: FleetSpec { @@ -129,8 +133,8 @@ impl ResourceBuilder for FleetBuilder { scheduling: Some("Packed".to_string()), template: FleetTemplate { metadata: Some(ObjectMeta { - labels: Some(labels), - annotations: Some(annotations), + labels: Some(template_labels), + annotations: Some(template_annotations), ..ObjectMeta::default() }), spec: game_server_spec, @@ -190,10 +194,11 @@ mod tests { // G let client = create_client_mock(); let builder = super::FleetBuilder::new(client); + let name = super::FleetBuilder::name(&TEST_SERVER_FLEET); // W let fleet = builder - .build(&TEST_SERVER_FLEET, "my-server", None) + .build(&TEST_SERVER_FLEET, &name, None) .await .unwrap(); @@ -230,10 +235,11 @@ mod tests { // G let client = create_client_mock(); let builder = super::FleetBuilder::new(client); + let name = super::FleetBuilder::name(&TEST_SERVER_FLEET); // W let fleet = builder - .build(&TEST_SERVER_FLEET, "my-server", None) + .build(&TEST_SERVER_FLEET, &name, None) .await .unwrap(); @@ -270,10 +276,11 @@ mod tests { // G let client = create_client_mock(); let builder = super::FleetBuilder::new(client); + let name = super::FleetBuilder::name(&TEST_SERVER_FLEET); // W let fleet = builder - .build(&TEST_SERVER_FLEET, "my-server", None) + .build(&TEST_SERVER_FLEET, &name, None) .await .unwrap(); diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet_autoscaler.rs b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet_autoscaler.rs index 182242d1..5431b30f 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet_autoscaler.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/fleet_autoscaler.rs @@ -48,11 +48,11 @@ impl ResourceBuilder for FleetAutoscalerBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(minecraft_server_fleet.namespace().unwrap().clone()), - labels: Some( - MinecraftServerFleetReconciler::get_common_labels(minecraft_server_fleet) - .into_iter() - .collect(), - ), + labels: Some(MinecraftServerFleetReconciler::get_labels( + minecraft_server_fleet, + "fleet-autoscaler".to_string(), + "minecraft-server".to_string(), + )), ..ObjectMeta::default() }, spec: FleetAutoscalerSpec { diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/mod.rs b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/mod.rs index 9b93bf91..8a8b2374 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/mod.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/mod.rs @@ -5,12 +5,7 @@ use google_agones_crds::v1::{fleet::Fleet, fleet_autoscaler::FleetAutoscaler}; use k8s_openapi::api::core::v1::ConfigMap; use kube::{ api::{ListParams, PatchParams}, - runtime::{ - controller::Action, - finalizer::{finalizer, Event as Finalizer}, - watcher::Config, - Controller, - }, + runtime::{controller::Action, watcher::Config, Controller}, Api, Client, ResourceExt, }; use tracing::*; @@ -33,8 +28,6 @@ mod fleet_autoscaler; #[cfg(test)] mod fixtures; -static FINALIZER: &str = "minecraftserverfleets.shulkermc.io"; - struct MinecraftServerFleetReconciler { client: kube::Client, @@ -109,17 +102,28 @@ impl MinecraftServerFleetReconciler { Ok(Action::await_change()) } - fn get_common_labels( + fn get_labels( minecraft_server_fleet: &MinecraftServerFleet, + name: String, + component: String, ) -> BTreeMap { BTreeMap::from([ + ("app.kubernetes.io/name".to_string(), name.clone()), ( - "app.kubernetes.io/name".to_string(), - minecraft_server_fleet.name_any(), + "app.kubernetes.io/instance".to_string(), + format!("{}-{}", name, minecraft_server_fleet.name_any()), + ), + ("app.kubernetes.io/component".to_string(), component), + ( + "app.kubernetes.io/part-of".to_string(), + format!( + "cluster-{}", + minecraft_server_fleet.spec.cluster_ref.name.clone() + ), ), ( - "app.kubernetes.io/component".to_string(), - "minecraftserver".to_string(), + "app.kubernetes.io/managed-by".to_string(), + "shulker-operator".to_string(), ), ( "minecraftcluster.shulkermc.io/name".to_string(), @@ -148,27 +152,15 @@ async fn reconcile( "reconciling MinecraftServerFleet", ); - finalizer( - &minecraft_server_fleets_api, - FINALIZER, - minecraft_server_fleet, - |event| async { - match event { - Finalizer::Apply(minecraft_server_fleet) => { - ctx.reconcile( - minecraft_server_fleets_api.clone(), - minecraft_server_fleet.clone(), - ) - .await - } - Finalizer::Cleanup(minecraft_server_fleet) => { - ctx.cleanup(minecraft_server_fleet.clone()).await - } - } - }, - ) - .await - .map_err(|e| ReconcilerError::FinalizerError(Box::new(e))) + if minecraft_server_fleet.metadata.deletion_timestamp.is_none() { + ctx.reconcile( + minecraft_server_fleets_api.clone(), + minecraft_server_fleet.clone(), + ) + .await + } else { + ctx.cleanup(minecraft_server_fleet.clone()).await + } } fn error_policy( diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__config_map__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__config_map__tests__build_snapshot.snap index 272ee2c2..9b550d72 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__config_map__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__config_map__tests__build_snapshot.snap @@ -12,8 +12,11 @@ data: spigot-config.yml: "settings:\n bungeecord: false\n restart-on-crash: false\nadvancements:\n disable-saving: true\nplayers:\n disable-saving: true\nstats:\n disable-saving: true\nsave-user-cache-on-stop-only: true\n\n" metadata: labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: config-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: config + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster minecraftserverfleet.shulkermc.io/name: my-server name: my-server-config diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap index 939bee91..7f3624cd 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: agones.dev/v1 kind: Fleet metadata: labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: minecraft-server-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: minecraft-server + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster minecraftserverfleet.shulkermc.io/name: my-server name: my-server @@ -23,8 +26,11 @@ spec: minecraftserver.shulkermc.io/tags: lobby test-annotation/shulkermc.io: my-value labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: minecraft-server-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: minecraft-server + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster minecraftserverfleet.shulkermc.io/name: my-server test-label/shulkermc.io: my-value @@ -43,8 +49,11 @@ spec: annotations: minecraftserver.shulkermc.io/tags: lobby labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: minecraft-server-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: minecraft-server + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster spec: containers: @@ -138,7 +147,7 @@ spec: nodeSelector: beta.kubernetes.io/os: linux restartPolicy: Never - serviceAccountName: my-cluster-server + serviceAccountName: shulker-my-cluster-server volumes: - configMap: name: my-server-config diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet_autoscaler__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet_autoscaler__tests__build_snapshot.snap index aed0f2c7..232e5b43 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet_autoscaler__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/minecraft_server_fleet/snapshots/shulker_operator__reconcilers__minecraft_server_fleet__fleet_autoscaler__tests__build_snapshot.snap @@ -6,8 +6,11 @@ apiVersion: autoscaling.agones.dev/v1 kind: FleetAutoscaler metadata: labels: - app.kubernetes.io/component: minecraftserver - app.kubernetes.io/name: my-server + app.kubernetes.io/component: minecraft-server + app.kubernetes.io/instance: fleet-autoscaler-my-server + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: fleet-autoscaler + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster minecraftserverfleet.shulkermc.io/name: my-server name: my-server diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/config_map.rs b/packages/shulker-operator/src/reconcilers/proxy_fleet/config_map.rs index f13f5620..00718bec 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/config_map.rs +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/config_map.rs @@ -74,11 +74,11 @@ impl ResourceBuilder for ConfigMapBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(proxy_fleet.namespace().unwrap().clone()), - labels: Some( - ProxyFleetReconciler::get_common_labels(proxy_fleet) - .into_iter() - .collect(), - ), + labels: Some(ProxyFleetReconciler::get_labels( + proxy_fleet, + "config".to_string(), + "proxy".to_string(), + )), ..ObjectMeta::default() }, data: Some(data), diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs b/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs index b7556e3d..e46c99fe 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs @@ -101,11 +101,11 @@ impl ResourceBuilder for FleetBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(proxy_fleet.namespace().unwrap().clone()), - labels: Some( - ProxyFleetReconciler::get_common_labels(proxy_fleet) - .into_iter() - .collect(), - ), + labels: Some(ProxyFleetReconciler::get_labels( + proxy_fleet, + "proxy".to_string(), + "proxy".to_string(), + )), ..ObjectMeta::default() }, spec: FleetSpec { @@ -237,7 +237,10 @@ impl FleetBuilder { ]), ..Container::default() }], - service_account_name: Some(format!("{}-proxy", &proxy_fleet.spec.cluster_ref.name)), + service_account_name: Some(format!( + "shulker-{}-proxy", + &proxy_fleet.spec.cluster_ref.name + )), restart_policy: Some("Never".to_string()), volumes: Some(vec![ Volume { @@ -305,22 +308,23 @@ impl FleetBuilder { pod_spec.tolerations = pod_overrides.tolerations.clone(); } - let mut labels = ProxyFleetReconciler::get_common_labels(proxy_fleet); - let mut annotations = BTreeMap::::new(); + let mut pod_labels = + ProxyFleetReconciler::get_labels(proxy_fleet, "proxy".to_string(), "proxy".to_string()); + let mut pod_annotations = BTreeMap::::new(); if let Some(metadata) = &proxy_fleet.spec.template.metadata { if let Some(additional_labels) = metadata.labels.clone() { - labels.extend(additional_labels); + pod_labels.extend(additional_labels); } if let Some(additional_annotations) = metadata.annotations.clone() { - annotations.extend(additional_annotations); + pod_annotations.extend(additional_annotations); } } Ok(PodTemplateSpec { metadata: Some(ObjectMeta { - labels: Some(labels), - annotations: Some(annotations), + labels: Some(pod_labels), + annotations: Some(pod_annotations), ..ObjectMeta::default() }), spec: Some(pod_spec), diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet_autoscaler.rs b/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet_autoscaler.rs index 526daef8..499fdcb5 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet_autoscaler.rs +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet_autoscaler.rs @@ -48,11 +48,11 @@ impl ResourceBuilder for FleetAutoscalerBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(proxy_fleet.namespace().unwrap().clone()), - labels: Some( - ProxyFleetReconciler::get_common_labels(proxy_fleet) - .into_iter() - .collect(), - ), + labels: Some(ProxyFleetReconciler::get_labels( + proxy_fleet, + "fleet-autoscaler".to_string(), + "proxy".to_string(), + )), ..ObjectMeta::default() }, spec: FleetAutoscalerSpec { diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/mod.rs b/packages/shulker-operator/src/reconcilers/proxy_fleet/mod.rs index 44850829..99dfcdd9 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/mod.rs +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/mod.rs @@ -5,12 +5,7 @@ use google_agones_crds::v1::{fleet::Fleet, fleet_autoscaler::FleetAutoscaler}; use k8s_openapi::api::core::v1::{ConfigMap, Service}; use kube::{ api::{ListParams, PatchParams}, - runtime::{ - controller::Action, - finalizer::{finalizer, Event as Finalizer}, - watcher::Config, - Controller, - }, + runtime::{controller::Action, watcher::Config, Controller}, Api, Client, ResourceExt, }; use tracing::*; @@ -35,8 +30,6 @@ mod service; #[cfg(test)] mod fixtures; -static FINALIZER: &str = "proxyfleets.shulkermc.io"; - struct ProxyFleetReconciler { client: kube::Client, @@ -109,12 +102,25 @@ impl ProxyFleetReconciler { Ok(Action::await_change()) } - fn get_common_labels(proxy_fleet: &ProxyFleet) -> BTreeMap { + fn get_labels( + proxy_fleet: &ProxyFleet, + name: String, + component: String, + ) -> BTreeMap { BTreeMap::from([ - ("app.kubernetes.io/name".to_string(), proxy_fleet.name_any()), + ("app.kubernetes.io/name".to_string(), name.clone()), + ( + "app.kubernetes.io/instance".to_string(), + format!("{}-{}", name, proxy_fleet.name_any()), + ), + ("app.kubernetes.io/component".to_string(), component), + ( + "app.kubernetes.io/part-of".to_string(), + format!("cluster-{}", proxy_fleet.spec.cluster_ref.name.clone()), + ), ( - "app.kubernetes.io/component".to_string(), - "proxy".to_string(), + "app.kubernetes.io/managed-by".to_string(), + "shulker-operator".to_string(), ), ( "minecraftcluster.shulkermc.io/name".to_string(), @@ -139,17 +145,12 @@ async fn reconcile(proxy_fleet: Arc, ctx: Arc) "reconciling ProxyFleet", ); - finalizer(&proxy_fleets_api, FINALIZER, proxy_fleet, |event| async { - match event { - Finalizer::Apply(proxy_fleet) => { - ctx.reconcile(proxy_fleets_api.clone(), proxy_fleet.clone()) - .await - } - Finalizer::Cleanup(proxy_fleet) => ctx.cleanup(proxy_fleet.clone()).await, - } - }) - .await - .map_err(|e| ReconcilerError::FinalizerError(Box::new(e))) + if proxy_fleet.metadata.deletion_timestamp.is_none() { + ctx.reconcile(proxy_fleets_api.clone(), proxy_fleet.clone()) + .await + } else { + ctx.cleanup(proxy_fleet.clone()).await + } } fn error_policy( diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/service.rs b/packages/shulker-operator/src/reconcilers/proxy_fleet/service.rs index 2b697784..77f463bb 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/service.rs +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/service.rs @@ -47,19 +47,19 @@ impl ResourceBuilder for ServiceBuilder { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(proxy_fleet.namespace().unwrap().clone()), - labels: Some( - ProxyFleetReconciler::get_common_labels(proxy_fleet) - .into_iter() - .collect(), - ), + labels: Some(ProxyFleetReconciler::get_labels( + proxy_fleet, + "proxy".to_string(), + "proxy".to_string(), + )), ..ObjectMeta::default() }, spec: Some(ServiceSpec { - selector: Some( - ProxyFleetReconciler::get_common_labels(proxy_fleet) - .into_iter() - .collect(), - ), + selector: Some(ProxyFleetReconciler::get_labels( + proxy_fleet, + "proxy".to_string(), + "proxy".to_string(), + )), type_: Some(service_config.type_.to_string()), external_traffic_policy: service_config .external_traffic_policy @@ -69,7 +69,7 @@ impl ResourceBuilder for ServiceBuilder { name: Some("minecraft".to_string()), protocol: Some("TCP".to_string()), port: 25565, - target_port: Some(IntOrString::Int(25577)), + target_port: Some(IntOrString::String("minecraft".to_string())), ..ServicePort::default() }]), ..ServiceSpec::default() diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__config_map__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__config_map__tests__build_snapshot.snap index 5d5b15b0..d8d5c655 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__config_map__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__config_map__tests__build_snapshot.snap @@ -12,7 +12,10 @@ data: metadata: labels: app.kubernetes.io/component: proxy - app.kubernetes.io/name: my-proxy + app.kubernetes.io/instance: config-my-proxy + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: config + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster proxyfleet.shulkermc.io/name: my-proxy name: my-proxy-config diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet__tests__build_snapshot.snap index 45c4fd37..ec642535 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet__tests__build_snapshot.snap @@ -7,7 +7,10 @@ kind: Fleet metadata: labels: app.kubernetes.io/component: proxy - app.kubernetes.io/name: my-proxy + app.kubernetes.io/instance: proxy-my-proxy + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: proxy + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster proxyfleet.shulkermc.io/name: my-proxy name: my-proxy @@ -26,7 +29,10 @@ spec: test-annotation/shulkermc.io: my-value labels: app.kubernetes.io/component: proxy - app.kubernetes.io/name: my-proxy + app.kubernetes.io/instance: proxy-my-proxy + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: proxy + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster proxyfleet.shulkermc.io/name: my-proxy test-label/shulkermc.io: my-value @@ -43,7 +49,10 @@ spec: test-annotation/shulkermc.io: my-value labels: app.kubernetes.io/component: proxy - app.kubernetes.io/name: my-proxy + app.kubernetes.io/instance: proxy-my-proxy + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: proxy + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster proxyfleet.shulkermc.io/name: my-proxy test-label/shulkermc.io: my-value @@ -138,7 +147,7 @@ spec: nodeSelector: beta.kubernetes.io/os: linux restartPolicy: Never - serviceAccountName: my-cluster-proxy + serviceAccountName: shulker-my-cluster-proxy volumes: - configMap: name: my-proxy-config diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet_autoscaler__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet_autoscaler__tests__build_snapshot.snap index 69bb617a..024de31a 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet_autoscaler__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__fleet_autoscaler__tests__build_snapshot.snap @@ -7,7 +7,10 @@ kind: FleetAutoscaler metadata: labels: app.kubernetes.io/component: proxy - app.kubernetes.io/name: my-proxy + app.kubernetes.io/instance: fleet-autoscaler-my-proxy + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: fleet-autoscaler + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster proxyfleet.shulkermc.io/name: my-proxy name: my-proxy diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__service__tests__build_snapshot.snap b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__service__tests__build_snapshot.snap index 259d33c9..4dcd5fcc 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__service__tests__build_snapshot.snap +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/snapshots/shulker_operator__reconcilers__proxy_fleet__service__tests__build_snapshot.snap @@ -7,7 +7,10 @@ kind: Service metadata: labels: app.kubernetes.io/component: proxy - app.kubernetes.io/name: my-proxy + app.kubernetes.io/instance: proxy-my-proxy + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: proxy + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster proxyfleet.shulkermc.io/name: my-proxy name: my-proxy @@ -18,10 +21,13 @@ spec: - name: minecraft port: 25565 protocol: TCP - targetPort: 25577 + targetPort: minecraft selector: app.kubernetes.io/component: proxy - app.kubernetes.io/name: my-proxy + app.kubernetes.io/instance: proxy-my-proxy + app.kubernetes.io/managed-by: shulker-operator + app.kubernetes.io/name: proxy + app.kubernetes.io/part-of: cluster-my-cluster minecraftcluster.shulkermc.io/name: my-cluster proxyfleet.shulkermc.io/name: my-proxy type: LoadBalancer