From b787fa1dde8acf98eea309e940cd66227c44382c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Levilain?= Date: Sat, 5 Mar 2022 19:43:38 +0100 Subject: [PATCH] feat: force proxy deployment to have a cluster ref, download plugins on start --- api/v1alpha1/minecraftcluster_types.go | 4 + api/v1alpha1/proxydeployment_types.go | 3 +- api/v1alpha1/zz_generated.deepcopy.go | 6 +- build.gradle | 13 +- .../bases/shulkermc.io_minecraftclusters.yaml | 5 + controllers/proxydeployment_controller.go | 15 +- internal/resource/cluster/builder.go | 9 +- internal/resource/proxy/builder.go | 22 +-- internal/resource/proxy/configmap.go | 6 + internal/resource/proxy/deployment.go | 139 +++++++++++++----- test/test.yml | 21 ++- 11 files changed, 175 insertions(+), 68 deletions(-) diff --git a/api/v1alpha1/minecraftcluster_types.go b/api/v1alpha1/minecraftcluster_types.go index e0a309eb..ae50cc4a 100644 --- a/api/v1alpha1/minecraftcluster_types.go +++ b/api/v1alpha1/minecraftcluster_types.go @@ -42,6 +42,10 @@ type MinecraftCluster struct { // say all, fields configurable in a Minecraft Cluster can be // configured in this CRD. type MinecraftClusterSpec struct { + // Name of the Kubernetes Secret contaning the Maven secret to + // use. It must contains a `username` and `password` fields. + //+kubebuilder:validation:Required + MavenSecretName string `json:"mavenSecretName,omitempty"` } type MinecraftClusterStatusCondition string diff --git a/api/v1alpha1/proxydeployment_types.go b/api/v1alpha1/proxydeployment_types.go index 2b8c0b03..6bd726b2 100644 --- a/api/v1alpha1/proxydeployment_types.go +++ b/api/v1alpha1/proxydeployment_types.go @@ -42,7 +42,8 @@ type ProxyDeployment struct { type ProxyDeploymentSpec struct { // Reference to a Minecraft Cluster. Adding this will enroll // this Proxy Deployment to be part of a Minecraft Cluster. - ClusterRef *MinecraftClusterRef `json:"minecraftClusterRef"` + //+kubebuilder:validation:Required + ClusterRef MinecraftClusterRef `json:"minecraftClusterRef"` // Version the Proxy Deployment has to run. //+kubebuilder:validation:Required diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 3e137a4d..811cfd72 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -560,11 +560,7 @@ func (in *ProxyDeploymentServiceSpec) DeepCopy() *ProxyDeploymentServiceSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProxyDeploymentSpec) DeepCopyInto(out *ProxyDeploymentSpec) { *out = *in - if in.ClusterRef != nil { - in, out := &in.ClusterRef, &out.ClusterRef - *out = new(MinecraftClusterRef) - **out = **in - } + out.ClusterRef = in.ClusterRef out.Version = in.Version if in.MaxPlayers != nil { in, out := &in.MaxPlayers, &out.MaxPlayers diff --git a/build.gradle b/build.gradle index a4f4c460..91c07222 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,15 @@ configure(subprojects.findAll { withSourcesJar() } + jar { + from (configurations.compile.collect { entry -> zipTree(entry) }) { + exclude 'META-INF/MANIFEST.MF' + exclude 'META-INF/*.SF' + exclude 'META-INF/*.DSA' + exclude 'META-INF/*.RSA' + } + } + publishing { publications { mavenJava(MavenPublication) { @@ -75,8 +84,8 @@ configure(subprojects.findAll { name = "GitHubPackages" url = "https://maven.pkg.github.com/IamBlueSlime/Shulker" credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") + username = project.findProperty("gpr.user") ?: System.getenv("GITHUB_ACTOR") + password = project.findProperty("gpr.key") ?: System.getenv("GITHUB_TOKEN") } } } diff --git a/config/crd/bases/shulkermc.io_minecraftclusters.yaml b/config/crd/bases/shulkermc.io_minecraftclusters.yaml index 6e21e185..4a4b6af6 100644 --- a/config/crd/bases/shulkermc.io_minecraftclusters.yaml +++ b/config/crd/bases/shulkermc.io_minecraftclusters.yaml @@ -53,6 +53,11 @@ spec: description: Defines the defired state of a MinecraftCluster. Most, to not say all, fields configurable in a Minecraft Cluster can be configured in this CRD. + properties: + mavenSecretName: + description: Name of the Kubernetes Secret contaning the Maven secret + to use. It must contains a `username` and `password` fields. + type: string type: object status: description: MinecraftClusterStatus defines the observed state of MinecraftCluster diff --git a/controllers/proxydeployment_controller.go b/controllers/proxydeployment_controller.go index c6b07261..d1290812 100644 --- a/controllers/proxydeployment_controller.go +++ b/controllers/proxydeployment_controller.go @@ -67,8 +67,18 @@ func (r *ProxyDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } + minecraftCluster := &shulkermciov1alpha1.MinecraftCluster{} + err = r.Get(ctx, types.NamespacedName{ + Namespace: proxyDeployment.Namespace, + Name: proxyDeployment.Spec.ClusterRef.Name, + }, minecraftCluster) + if err != nil { + return ctrl.Result{}, err + } + resourceBuilder := resource.ProxyDeploymentResourceBuilder{ Instance: proxyDeployment, + Cluster: minecraftCluster, Scheme: r.Scheme, } builders, dirtyBuilders := resourceBuilder.ResourceBuilders() @@ -116,11 +126,6 @@ func (r *ProxyDeploymentReconciler) getProxyDeployment(ctx context.Context, name func (r *ProxyDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error { err := mgr.GetFieldIndexer().IndexField(context.Background(), &shulkermciov1alpha1.ProxyDeployment{}, ".spec.minecraftClusterRef.name", func(object client.Object) []string { proxyDeployment := object.(*shulkermciov1alpha1.ProxyDeployment) - - if proxyDeployment.Spec.ClusterRef == nil { - return nil - } - return []string{proxyDeployment.Spec.ClusterRef.Name} }) diff --git a/internal/resource/cluster/builder.go b/internal/resource/cluster/builder.go index 36c72045..0cc5a568 100644 --- a/internal/resource/cluster/builder.go +++ b/internal/resource/cluster/builder.go @@ -20,10 +20,9 @@ func (b *MinecraftClusterResourceBuilder) ResourceBuilders() ([]common.ResourceB // func (b *MinecraftClusterResourceBuilder) getLabels() map[string]string { // return map[string]string{ -// "app.kubernetes.io/name": b.Instance.Name, -// "app.kubernetes.io/component": "minecraft-cluster", -// "app.kubernetes.io/part-of": "shulker", -// "app.kubernetes.io/created-by": "shulker", -// "minecraftcluster.shulker.io/name": b.Instance.Name, +// "app.kubernetes.io/name": b.Instance.Name, +// "app.kubernetes.io/component": "minecraft-cluster", +// "app.kubernetes.io/part-of": "shulker", +// "app.kubernetes.io/created-by": "shulker", // } // } diff --git a/internal/resource/proxy/builder.go b/internal/resource/proxy/builder.go index 3240677b..a664ae68 100644 --- a/internal/resource/proxy/builder.go +++ b/internal/resource/proxy/builder.go @@ -10,6 +10,7 @@ import ( type ProxyDeploymentResourceBuilder struct { Instance *shulkermciov1alpha1.ProxyDeployment + Cluster *shulkermciov1alpha1.MinecraftCluster Scheme *runtime.Scheme } @@ -25,11 +26,7 @@ func (b *ProxyDeploymentResourceBuilder) ResourceBuilders() ([]common.ResourceBu } func (b *ProxyDeploymentResourceBuilder) getResourcePrefix() string { - if b.Instance.Spec.ClusterRef != nil { - return b.Instance.Spec.ClusterRef.Name - } else { - return "minecraft" - } + return b.Instance.Spec.ClusterRef.Name } func (b *ProxyDeploymentResourceBuilder) GetDeploymentName() string { @@ -46,15 +43,12 @@ func (b *ProxyDeploymentResourceBuilder) getServiceName() string { func (b *ProxyDeploymentResourceBuilder) getLabels() map[string]string { labels := map[string]string{ - "app.kubernetes.io/name": b.Instance.Name, - "app.kubernetes.io/component": "proxy", - "app.kubernetes.io/part-of": "shulker", - "app.kubernetes.io/created-by": "shulker", - "proxydeployment.shulker.io/name": b.Instance.Name, - } - - if b.Instance.Spec.ClusterRef != nil { - labels["proxydeployment.shulker.io/cluster-name"] = b.Instance.Spec.ClusterRef.Name + "app.kubernetes.io/name": b.Instance.Name, + "app.kubernetes.io/component": "proxy", + "app.kubernetes.io/part-of": "shulker", + "app.kubernetes.io/created-by": "shulker", + "proxydeployment.shulker.io/name": b.Instance.Name, + "proxydeployment.shulker.io/cluster-name": b.Instance.Spec.ClusterRef.Name, } return labels diff --git a/internal/resource/proxy/configmap.go b/internal/resource/proxy/configmap.go index b894b597..80a66cd7 100644 --- a/internal/resource/proxy/configmap.go +++ b/internal/resource/proxy/configmap.go @@ -40,6 +40,12 @@ cp -H -r $SHULKER_CONFIG_DIR/* $SHULKER_DATA_DIR/; if [ -e "$SHULKER_CONFIG_DIR/server-icon.png" ]; then cat $SHULKER_CONFIG_DIR/server-icon.png | base64 -d > $SHULKER_DATA_DIR/server-icon.png; fi `, "\n ") + configMapData["init-plugins.sh"] = strings.Trim(` +mkdir -p $SHULKER_DATA_DIR/plugins +function plugin { curl -L -o "$SHULKER_DATA_DIR/plugins/$2-$3.jar" -u "${SHULKER_MAVEN_USERNAME}:${SHULKER_MAVEN_PASSWORD}" https://maven.pkg.github.com/IamBlueSlime/Shulker/$1/$2/$3/$2-$3.jar; } +if [ ! -z "$SHULKER_PROXY_DIRECTORY_VERSION" ]; then plugin io.shulkermc shulker-proxy-directory "$SHULKER_PROXY_DIRECTORY_VERSION"; fi + `, "\n ") + if b.Instance.Spec.ServerIcon != "" { configMapData["server-icon.png"] = b.Instance.Spec.ServerIcon } else { diff --git a/internal/resource/proxy/deployment.go b/internal/resource/proxy/deployment.go index 80b979a6..134ceff8 100644 --- a/internal/resource/proxy/deployment.go +++ b/internal/resource/proxy/deployment.go @@ -49,42 +49,62 @@ func (b *ProxyDeploymentDeploymentBuilder) Update(object client.Object) error { Labels: b.getLabels(), }, Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{{ - Image: "busybox:stable", - Name: "init-proxy-fs", - Command: []string{"ash", fmt.Sprintf("%s/init-fs.sh", proxyConfigDir)}, - Env: []corev1.EnvVar{ - { - Name: "SHULKER_CONFIG_DIR", - Value: proxyConfigDir, - }, - { - Name: "SHULKER_DATA_DIR", - Value: proxyServerDir, - }, - }, - Resources: corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - "cpu": k8sresource.MustParse("500m"), - "memory": k8sresource.MustParse("128Mi"), + InitContainers: []corev1.Container{ + { + Image: "busybox:stable", + Name: "init-proxy-fs", + Command: []string{"ash", fmt.Sprintf("%s/init-fs.sh", proxyConfigDir)}, + Env: b.getDeploymentInitFsEnv(), + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + "cpu": k8sresource.MustParse("500m"), + "memory": k8sresource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + "cpu": k8sresource.MustParse("10m"), + "memory": k8sresource.MustParse("512Ki"), + }, }, - Requests: corev1.ResourceList{ - "cpu": k8sresource.MustParse("10m"), - "memory": k8sresource.MustParse("512Ki"), + VolumeMounts: []corev1.VolumeMount{ + { + Name: "proxy-server-dir", + MountPath: proxyServerDir, + }, + { + Name: "proxy-config-dir", + MountPath: proxyConfigDir, + ReadOnly: true, + }, }, }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "proxy-server-dir", - MountPath: proxyServerDir, + { + Image: "curlimages/curl:latest", + Name: "init-proxy-plugins", + Command: []string{"ash", fmt.Sprintf("%s/init-plugins.sh", proxyConfigDir)}, + Env: b.getDeploymentInitPluginsEnv(), + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + "cpu": k8sresource.MustParse("500m"), + "memory": k8sresource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + "cpu": k8sresource.MustParse("10m"), + "memory": k8sresource.MustParse("512Ki"), + }, }, - { - Name: "proxy-config-dir", - MountPath: proxyConfigDir, - ReadOnly: true, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "proxy-server-dir", + MountPath: proxyServerDir, + }, + { + Name: "proxy-config-dir", + MountPath: proxyConfigDir, + ReadOnly: true, + }, }, }, - }}, + }, Containers: []corev1.Container{{ Image: "itzg/bungeecord:latest", Name: "proxy", @@ -155,6 +175,58 @@ func (b *ProxyDeploymentDeploymentBuilder) CanBeUpdated() bool { return true } +func (b *ProxyDeploymentDeploymentBuilder) getDeploymentInitFsEnv() []corev1.EnvVar { + env := []corev1.EnvVar{ + { + Name: "SHULKER_CONFIG_DIR", + Value: proxyConfigDir, + }, + { + Name: "SHULKER_DATA_DIR", + Value: proxyServerDir, + }, + } + + return env +} + +func (b *ProxyDeploymentDeploymentBuilder) getDeploymentInitPluginsEnv() []corev1.EnvVar { + env := []corev1.EnvVar{ + { + Name: "SHULKER_DATA_DIR", + Value: proxyServerDir, + }, + { + Name: "SHULKER_MAVEN_USERNAME", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: b.Cluster.Spec.MavenSecretName, + }, + Key: "username", + }, + }, + }, + { + Name: "SHULKER_MAVEN_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: b.Cluster.Spec.MavenSecretName, + }, + Key: "password", + }, + }, + }, + { + Name: "SHULKER_PROXY_DIRECTORY_VERSION", + Value: "0.0.1", + }, + } + + return env +} + func (b *ProxyDeploymentDeploymentBuilder) getDeploymentEnv() []corev1.EnvVar { env := []corev1.EnvVar{ { @@ -173,13 +245,10 @@ func (b *ProxyDeploymentDeploymentBuilder) getDeploymentEnv() []corev1.EnvVar { Name: "MAX_MEMORY", Value: fmt.Sprintf("%dM", b.Instance.Spec.Resources.Limits.Memory().ScaledValue(resource.Mega)-1000), }, - } - - if b.Instance.Spec.ClusterRef != nil { - env = append(env, corev1.EnvVar{ + { Name: "SHULKER_CLUSTER_NAME", Value: b.Instance.Spec.ClusterRef.Name, - }) + }, } env = append(env, b.Instance.Spec.PodOverrides.Env...) diff --git a/test/test.yml b/test/test.yml index 4246fb1c..7876e070 100644 --- a/test/test.yml +++ b/test/test.yml @@ -2,7 +2,26 @@ apiVersion: shulkermc.io/v1alpha1 kind: MinecraftCluster metadata: name: test -spec: {} +spec: + mavenSecretName: ss-maven-secret + +--- +kind: SealedSecret +apiVersion: bitnami.com/v1alpha1 +metadata: + name: ss-maven-secret + namespace: shulker-test + creationTimestamp: null +spec: + template: + metadata: + name: ss-maven-secret + namespace: shulker-test + creationTimestamp: null + data: null + encryptedData: + password: AgCBHHwHYKL4DOmCi4S3Y2V5CZw4B84AuNYdAlLhfDp9Iwk3OuC5kYcNkrnkog7rhUlsLdTCh4tlaQfhVOaywaghqe6L/VWRDcNgU2YKYT8Q+stm5rpdg5l+JbR5fBxiKhnPtsDn5WPo6SHW2v3QSfu+EEW7YCBbuSRfNjbJnbeXb+gO4/W1cTuMblftBW34xK+a6WSk1fAs3b3ku4SpHXn1+pbIgcWbBgpRb7c6WblKvGDF/3H6ehjiu3gNVq9dUIwEP0CvgZOBO6AueKZ0BsRgOnKytFfUUzQe6o+yVROJryWQg7WW0nFr/D4ykCsniOIweee4iS5viOkBavzk85BpvrX67YyUtUT1ioW6/PmoQA/a5ZwXxAaidAKMAdJ7DaWds5vkaRk2f05al3skNPWwNKX2QtyvCuZBj20Aunth+PbySlnChBVamrFjueKxeoeRx5xfTP6IrBQoY4SGQxUmL6Zqz8nqspfAw+k/4pt6zjnBjSnvUkoYmhYyWb2oMKZVQiYRc0XvyTWVG6LL2gF2wLHlhmJAxdQkk42Qx/JFNXKAunUHRberb4azFiPKhvWMHSqWOLV1ovD8UBG4PsQGOxc2ejkn7qT3Sl8XpWDTUqFjH+RondgR4MIW4QFp+NlaQCy76jRSuDAkJgKek0VU21WZe80DRnI6Q4c/Q+6mK88LB8QQFqJlbfH0h611RHOnd6BiHuuqpmVVKf3q9pAypW6piPTgyswbOr2+S4KnyWJf3yF8FLNT + username: AgCLdKeNwh/qp4OMzfHG/lroNUnXp0YUcsxi3mokp8Ue/50PElkOLeIuFN4sNFmE5N/buIyW8clQtcSyuluzpCNrhthA4xuBQ6NnS5Olaben9ZwkYdmQis6R0sdZv3JSAuj+9gKlfhcDNRCzKpbVF3gLHU7ztWJLTckA6Po1MLHHCNuUqcSOwQ50R4Gl+xHSfycTufdRLKR5fo83l/QFMhBt7VoC/urYWbDGg55e231xD9MY0h0l5n55XFbmZ9/EDTqZXLRCvwQDUiAJ1uLVWhDmsufavw7sO2DMNaPYv+LFcwbermDFCjfK6ykgXXueiMip1TftfEcnudfzB6FUgKQzJxoXERXa3lQCAsqGc4qfEWHcp3sAmJSfbnW7jU4+ptFH+H2ySk87eH6TVnguCMvcPKm+WHy248rgSllNjFUWEtlkG7CRsLzDFAkg4fF0CCpfenKZV9zlkuPhjnnuq0Kmg+yqKAzmwnf0zg5oOQdygspfo0T8qSlanJsYkd+PehbnPiplO5oY/nAcG+SH95Okm4XSp8mr1wV3j44JBcPtojWOiclzSE3cQ0RmeLgUzGehpKw9A/lfm61hqE6M4hcFBtPb5NkwGY4xckjF1JmzIh8P28e/N6o3WDu5x8NOqtC5yiwpXJbaSAQ/lqGk3MGI0x5JGoXHygxZskue/EipBncShc/kKVFB9ECbd6nS6dUyPy9r/cNP4qwFjh8= --- apiVersion: shulkermc.io/v1alpha1