diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 02276f70..89757e07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,7 @@ name: release on: + workflow_dispatch: push: branches: - main diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml index 9be27abd..d3b3c5b0 100644 --- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml +++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.bungeecord.iml @@ -81,8 +81,8 @@ - + @@ -102,30 +102,8 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -151,15 +129,37 @@ + + + + + + + + + + + + + + + + + + + + - + + + diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml index 1ed2809f..fb49f910 100644 --- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml +++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.common.iml @@ -73,8 +73,8 @@ - + @@ -84,22 +84,8 @@ - - - - - - - - - - - - - - @@ -121,16 +107,30 @@ + + + + + + + + + + + + + + diff --git a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml index 5eb27cf4..56fa7f5a 100644 --- a/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml +++ b/.idea/modules/packages/shulker-proxy-agent/shulker.packages.shulker-proxy-agent.velocity.iml @@ -82,8 +82,8 @@ - + @@ -105,25 +105,8 @@ - - - - - - - - - - - - - - - - - @@ -150,10 +133,27 @@ + + + + + + + + + + + + + + + + + diff --git a/Cargo.lock b/Cargo.lock index 96ba0b31..1e01a2ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1203,6 +1203,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itertools" version = "0.11.0" @@ -1944,6 +1950,46 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + [[package]] name = "ring" version = "0.16.20" @@ -2150,6 +2196,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-xml-rs" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" +dependencies = [ + "log", + "serde", + "thiserror", + "xml-rs", +] + [[package]] name = "serde_derive" version = "1.0.193" @@ -2333,7 +2391,9 @@ dependencies = [ "kube", "lazy_static", "rand", + "reqwest", "serde", + "serde-xml-rs", "serde_json", "serde_yaml", "shulker-crds", @@ -2479,6 +2539,27 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.8.1" @@ -3014,6 +3095,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -3053,6 +3146,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + [[package]] name = "which" version = "4.4.2" @@ -3237,6 +3336,22 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index effb50fe..55f27fb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,9 +51,11 @@ pbjson-types = "0.6.0" prometheus = "0.13.3" prost = "0.12.3" rand = "0.8.5" +reqwest = { version = "0.11.22", default-features = false, features = ["rustls-tls"] } schemars = { version = "0.8.16", features = ["chrono"] } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" +serde-xml-rs = "0.6.0" serde_yaml = "0.9.27" strum = { version = "0.25.0", features = ["derive"] } tempfile = "3.8.1" diff --git a/README.md b/README.md index 337d9cae..86a1f09f 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ in the cloud with Kubernetes. ## Getting started -See the **[Getting Started](https://shulker.jeremylvln.fr/guide/getting-started/prerequisites.html)** +See the **[Getting Started](https://shulker.jeremylvln.fr/latest/guide/getting-started/prerequisites.html)** section of the documentation to start using Shulker! ## License diff --git a/kube/helm/.gitignore b/kube/helm/.gitignore new file mode 100644 index 00000000..1e0ef302 --- /dev/null +++ b/kube/helm/.gitignore @@ -0,0 +1 @@ +values.test.yaml diff --git a/kube/helm/charts/shulker-addon-matchmaking/templates/director_deployment.yaml b/kube/helm/charts/shulker-addon-matchmaking/templates/director_deployment.yaml index 57d71515..bce34c31 100644 --- a/kube/helm/charts/shulker-addon-matchmaking/templates/director_deployment.yaml +++ b/kube/helm/charts/shulker-addon-matchmaking/templates/director_deployment.yaml @@ -28,6 +28,9 @@ spec: imagePullPolicy: {{ .Values.director.image.pullPolicy }} args: - --metrics-bind-address=0.0.0.0:8080 + {{- with .Values.director.extraArgs }} + {{- toYaml . | nindent 12 }} + {{- end }} ports: - containerPort: 8080 protocol: TCP diff --git a/kube/helm/charts/shulker-addon-matchmaking/templates/mmf_deployment.yaml b/kube/helm/charts/shulker-addon-matchmaking/templates/mmf_deployment.yaml index 912cf97f..f12f8d85 100644 --- a/kube/helm/charts/shulker-addon-matchmaking/templates/mmf_deployment.yaml +++ b/kube/helm/charts/shulker-addon-matchmaking/templates/mmf_deployment.yaml @@ -29,6 +29,9 @@ spec: command: ['/shulker-addon-matchmaking-mmf'] args: - --metrics-bind-address=0.0.0.0:8080 + {{- with .Values.mmf.extraArgs }} + {{- toYaml . | nindent 12 }} + {{- end }} ports: - containerPort: 8080 protocol: TCP diff --git a/kube/helm/templates/NOTES.txt b/kube/helm/templates/NOTES.txt index a3fd35c0..5da4d253 100644 --- a/kube/helm/templates/NOTES.txt +++ b/kube/helm/templates/NOTES.txt @@ -3,4 +3,4 @@ Shulker Operator {{ .Chart.AppVersion }} has been deployed successfully! You are now able to create your first MinecraftCluster. See the Getting Started guide in the documentation: -https://shulker.jeremylvln.fr/guide/getting-started/your-first-cluster.html +https://shulker.jeremylvln.fr/latest/guide/getting-started/your-first-cluster.html diff --git a/kube/helm/templates/deployment.yaml b/kube/helm/templates/deployment.yaml index dc5d2138..e8a96dd7 100644 --- a/kube/helm/templates/deployment.yaml +++ b/kube/helm/templates/deployment.yaml @@ -30,8 +30,11 @@ spec: - --metrics-bind-address=0.0.0.0:8080 - --api-bind-address=0.0.0.0:9090 {{- if .Values.operator.agones.allocator.mtlsSecretName }} - - --agones-allocation-tls-client-crt=/mnt/shulker/agones-allocation-client-tls/tls.crt - - --agones-allocation-tls-client-key=/mnt/shulker/agones-allocation-client-tls/tls.key + - --agones-allocator-tls-client-crt=/mnt/shulker/agones-allocator-client-tls/tls.crt + - --agones-allocator-tls-client-key=/mnt/shulker/agones-allocator-client-tls/tls.key + {{- end }} + {{- with .Values.operator.extraArgs }} + {{- toYaml . | nindent 12 }} {{- end }} ports: - containerPort: 8080 @@ -86,9 +89,9 @@ spec: {{- if .Values.operator.agones.allocator.mtlsSecretName }} volumeMounts: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls readOnly: true - mountPath: "/mnt/shulker/agones-allocation-client-tls" + mountPath: "/mnt/shulker/agones-allocator-client-tls" {{- with .Values.operator.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} @@ -126,7 +129,7 @@ spec: {{- if .Values.operator.agones.allocator.mtlsSecretName }} volumes: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls secret: secretName: allocator-client.default {{- with .Values.operator.volumes }} diff --git a/kube/manifests/generate_from_helm.sh b/kube/manifests/generate_from_helm.sh index 2affe4fe..64554942 100755 --- a/kube/manifests/generate_from_helm.sh +++ b/kube/manifests/generate_from_helm.sh @@ -35,10 +35,11 @@ generate next-with-prometheus \ --set operator.metrics.enabled=true \ --set operator.metrics.servicemonitor.enabled=true \ --set shulker-addon-matchmaking.enabled=true \ - --set shulker-addon-matchmaking.image.tag=next \ + --set shulker-addon-matchmaking.director.image.tag=next \ --set shulker-addon-matchmaking.director.metrics.enabled=true \ --set shulker-addon-matchmaking.director.metrics.servicemonitor.enabled=true \ + --set shulker-addon-matchmaking.mmf.image.tag=next \ --set shulker-addon-matchmaking.mmf.metrics.enabled=true \ --set shulker-addon-matchmaking.mmf.metrics.servicemonitor.enabled=true -(cd .. && npx prettier --write 'kube/manifests/*.yaml') +(cd ../.. && npx prettier --write 'kube/manifests/*.yaml') diff --git a/kube/manifests/next-with-prometheus.yaml b/kube/manifests/next-with-prometheus.yaml index 42e441bc..796bcd8c 100644 --- a/kube/manifests/next-with-prometheus.yaml +++ b/kube/manifests/next-with-prometheus.yaml @@ -3974,8 +3974,8 @@ spec: args: - --metrics-bind-address=0.0.0.0:8080 - --api-bind-address=0.0.0.0:9090 - - --agones-allocation-tls-client-crt=/mnt/shulker/agones-allocation-client-tls/tls.crt - - --agones-allocation-tls-client-key=/mnt/shulker/agones-allocation-client-tls/tls.key + - --agones-allocator-tls-client-crt=/mnt/shulker/agones-allocator-client-tls/tls.crt + - --agones-allocator-tls-client-key=/mnt/shulker/agones-allocator-client-tls/tls.key ports: - containerPort: 8080 protocol: TCP @@ -4016,9 +4016,9 @@ spec: cpu: 100m memory: 128Mi volumeMounts: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls readOnly: true - mountPath: "/mnt/shulker/agones-allocation-client-tls" + mountPath: "/mnt/shulker/agones-allocator-client-tls" securityContext: allowPrivilegeEscalation: false capabilities: @@ -4042,7 +4042,7 @@ spec: seccompProfile: type: RuntimeDefault volumes: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls secret: secretName: allocator-client.default --- diff --git a/kube/manifests/next.yaml b/kube/manifests/next.yaml index 531f885b..ec9b2c7e 100644 --- a/kube/manifests/next.yaml +++ b/kube/manifests/next.yaml @@ -3974,8 +3974,8 @@ spec: args: - --metrics-bind-address=0.0.0.0:8080 - --api-bind-address=0.0.0.0:9090 - - --agones-allocation-tls-client-crt=/mnt/shulker/agones-allocation-client-tls/tls.crt - - --agones-allocation-tls-client-key=/mnt/shulker/agones-allocation-client-tls/tls.key + - --agones-allocator-tls-client-crt=/mnt/shulker/agones-allocator-client-tls/tls.crt + - --agones-allocator-tls-client-key=/mnt/shulker/agones-allocator-client-tls/tls.key ports: - containerPort: 8080 protocol: TCP @@ -4016,9 +4016,9 @@ spec: cpu: 100m memory: 128Mi volumeMounts: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls readOnly: true - mountPath: "/mnt/shulker/agones-allocation-client-tls" + mountPath: "/mnt/shulker/agones-allocator-client-tls" securityContext: allowPrivilegeEscalation: false capabilities: @@ -4042,6 +4042,6 @@ spec: seccompProfile: type: RuntimeDefault volumes: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls secret: secretName: allocator-client.default diff --git a/kube/manifests/stable-with-prometheus.yaml b/kube/manifests/stable-with-prometheus.yaml index ea892761..9fc0f7a4 100644 --- a/kube/manifests/stable-with-prometheus.yaml +++ b/kube/manifests/stable-with-prometheus.yaml @@ -3494,8 +3494,8 @@ spec: args: - --metrics-bind-address=0.0.0.0:8080 - --api-bind-address=0.0.0.0:9090 - - --agones-allocation-tls-client-crt=/mnt/shulker/agones-allocation-client-tls/tls.crt - - --agones-allocation-tls-client-key=/mnt/shulker/agones-allocation-client-tls/tls.key + - --agones-allocator-tls-client-crt=/mnt/shulker/agones-allocator-client-tls/tls.crt + - --agones-allocator-tls-client-key=/mnt/shulker/agones-allocator-client-tls/tls.key ports: - containerPort: 8080 protocol: TCP @@ -3536,9 +3536,9 @@ spec: cpu: 100m memory: 128Mi volumeMounts: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls readOnly: true - mountPath: "/mnt/shulker/agones-allocation-client-tls" + mountPath: "/mnt/shulker/agones-allocator-client-tls" securityContext: allowPrivilegeEscalation: false capabilities: @@ -3562,7 +3562,7 @@ spec: seccompProfile: type: RuntimeDefault volumes: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls secret: secretName: allocator-client.default --- diff --git a/kube/manifests/stable.yaml b/kube/manifests/stable.yaml index c531b5c4..718410c1 100644 --- a/kube/manifests/stable.yaml +++ b/kube/manifests/stable.yaml @@ -3494,8 +3494,8 @@ spec: args: - --metrics-bind-address=0.0.0.0:8080 - --api-bind-address=0.0.0.0:9090 - - --agones-allocation-tls-client-crt=/mnt/shulker/agones-allocation-client-tls/tls.crt - - --agones-allocation-tls-client-key=/mnt/shulker/agones-allocation-client-tls/tls.key + - --agones-allocator-tls-client-crt=/mnt/shulker/agones-allocator-client-tls/tls.crt + - --agones-allocator-tls-client-key=/mnt/shulker/agones-allocator-client-tls/tls.key ports: - containerPort: 8080 protocol: TCP @@ -3536,9 +3536,9 @@ spec: cpu: 100m memory: 128Mi volumeMounts: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls readOnly: true - mountPath: "/mnt/shulker/agones-allocation-client-tls" + mountPath: "/mnt/shulker/agones-allocator-client-tls" securityContext: allowPrivilegeEscalation: false capabilities: @@ -3562,6 +3562,6 @@ spec: seccompProfile: type: RuntimeDefault volumes: - - name: agones-allocation-client-tls + - name: agones-allocator-client-tls secret: secretName: allocator-client.default diff --git a/packages/shulker-operator/Cargo.toml b/packages/shulker-operator/Cargo.toml index ee70a6a5..648fb50d 100644 --- a/packages/shulker-operator/Cargo.toml +++ b/packages/shulker-operator/Cargo.toml @@ -34,7 +34,9 @@ k8s-openapi.workspace = true kube.workspace = true lazy_static.workspace = true rand.workspace = true +reqwest.workspace = true serde.workspace = true +serde-xml-rs.workspace = true serde_yaml.workspace = true shulker-crds.workspace = true shulker-kube-utils.workspace = true diff --git a/packages/shulker-operator/assets/proxy-init-fs.sh b/packages/shulker-operator/assets/proxy-init-fs.sh index b7b089fe..daa251d8 100644 --- a/packages/shulker-operator/assets/proxy-init-fs.sh +++ b/packages/shulker-operator/assets/proxy-init-fs.sh @@ -12,14 +12,8 @@ else cp "${SHULKER_CONFIG_DIR}/bungeecord-config.yml" "${PROXY_DATA_DIR}/config.yml" fi -mkdir -p "${PROXY_DATA_DIR}/plugins" -if [ "${TYPE}" == "VELOCITY" ]; then - (cd "${PROXY_DATA_DIR}/plugins" && wget "${SHULKER_MAVEN_REPOSITORY}/io/shulkermc/shulker-proxy-agent/${SHULKER_PROXY_AGENT_VERSION}/shulker-proxy-agent-${SHULKER_PROXY_AGENT_VERSION}-velocity.jar") -else - (cd "${PROXY_DATA_DIR}/plugins" && wget "${SHULKER_MAVEN_REPOSITORY}/io/shulkermc/shulker-proxy-agent/${SHULKER_PROXY_AGENT_VERSION}/shulker-proxy-agent-${SHULKER_PROXY_AGENT_VERSION}-bungeecord.jar") -fi - if [ ! -z "${PROXY_PLUGIN_URLS+x}" ]; then + mkdir -p "${PROXY_DATA_DIR}/plugins" for plugin_url in ${PROXY_PLUGIN_URLS//;/ }; do (cd "${PROXY_DATA_DIR}/plugins" && wget "${plugin_url}") done diff --git a/packages/shulker-operator/assets/server-init-fs.sh b/packages/shulker-operator/assets/server-init-fs.sh index 70d8f700..9f026b52 100644 --- a/packages/shulker-operator/assets/server-init-fs.sh +++ b/packages/shulker-operator/assets/server-init-fs.sh @@ -14,15 +14,8 @@ if [ ! -z "${SERVER_WORLD_URL+x}" ]; then (cd "${SERVER_CONFIG_DIR}" && wget "${SERVER_WORLD_URL}" -O - | tar -xzv) fi -mkdir -p "${SERVER_CONFIG_DIR}/plugins" -if [ "${TYPE}" == "PAPER" ] || [ "${TYPE}" == "FOLIA" ]; then - (cd "${SERVER_CONFIG_DIR}/plugins" && wget "${SHULKER_MAVEN_REPOSITORY}/io/shulkermc/shulker-server-agent/${SHULKER_SERVER_AGENT_VERSION}/shulker-server-agent-${SHULKER_SERVER_AGENT_VERSION}-paper.jar") -else - echo "[!] No server agent available for this server type" - exit 1 -fi - if [ ! -z "${SERVER_PLUGIN_URLS+x}" ]; then + mkdir -p "${SERVER_CONFIG_DIR}/plugins" for plugin_url in ${SERVER_PLUGIN_URLS//;/ }; do (cd "${SERVER_CONFIG_DIR}/plugins" && wget "${plugin_url}") done diff --git a/packages/shulker-operator/src/reconcilers/agent.rs b/packages/shulker-operator/src/reconcilers/agent.rs new file mode 100644 index 00000000..f48c36ed --- /dev/null +++ b/packages/shulker-operator/src/reconcilers/agent.rs @@ -0,0 +1,48 @@ +use shulker_crds::resourceref::{ResourceRefFromMavenSpec, ResourceRefFromSpec, ResourceRefSpec}; +use url::Url; + +use crate::{ + agent::AgentConfig, + resources::{resourceref_resolver::ResourceRefResolver, ResourceRefError}, +}; + +pub enum AgentSide { + Proxy, + Server, +} + +impl AgentSide { + pub fn get_artifact_name(&self) -> &'static str { + match self { + AgentSide::Proxy => "shulker-proxy-agent", + AgentSide::Server => "shulker-server-agent", + } + } +} + +pub async fn get_agent_plugin_url( + resourceref_resolver: &ResourceRefResolver, + agent_config: &AgentConfig, + side: AgentSide, + platform: String, +) -> Result { + resourceref_resolver + .resolve( + "shulker-system", + &ResourceRefSpec { + url_from: Some(ResourceRefFromSpec { + maven_ref: Some(ResourceRefFromMavenSpec { + repository_url: agent_config.maven_repository.clone(), + group_id: "io.shulkermc".to_string(), + artifact_id: side.get_artifact_name().to_string(), + version: agent_config.version.clone(), + classifier: Some(platform), + credentials_secret_name: None, + }), + }), + ..ResourceRefSpec::default() + }, + ) + .await? + .as_url() +} diff --git a/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs b/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs index 4351f38d..2c8784bd 100644 --- a/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs +++ b/packages/shulker-operator/src/reconcilers/minecraft_server/gameserver.rs @@ -20,8 +20,11 @@ use kube::ResourceExt; use lazy_static::lazy_static; use shulker_crds::v1alpha1::minecraft_cluster::MinecraftCluster; use shulker_crds::v1alpha1::minecraft_server::MinecraftServerVersion; +use url::Url; use crate::agent::AgentConfig; +use crate::reconcilers::agent::get_agent_plugin_url; +use crate::reconcilers::agent::AgentSide; use crate::resources::resourceref_resolver::ResourceRefResolver; use google_agones_crds::v1::game_server::GameServer; use google_agones_crds::v1::game_server::GameServerEvictionSpec; @@ -303,6 +306,10 @@ impl<'a> GameServerBuilder { ) -> Result, anyhow::Error> { let spec = &minecraft_server.spec; + let plugin_urls = + GameServerBuilder::get_plugin_urls(resourceref_resolver, context, minecraft_server) + .await?; + let mut env: Vec = vec![ EnvVar { name: "SHULKER_CONFIG_DIR".to_string(), @@ -324,16 +331,6 @@ impl<'a> GameServerBuilder { value: Some(Self::get_type_from_version_channel(&spec.version.channel)), ..EnvVar::default() }, - EnvVar { - name: "SHULKER_MAVEN_REPOSITORY".to_string(), - value: Some(context.agent_config.maven_repository.clone()), - ..EnvVar::default() - }, - EnvVar { - name: "SHULKER_SERVER_AGENT_VERSION".to_string(), - value: Some(context.agent_config.version.clone()), - ..EnvVar::default() - }, ]; if let Some(world) = &spec.config.world { @@ -349,13 +346,8 @@ impl<'a> GameServerBuilder { }) } - if let Some(plugins) = &spec.config.plugins { - let urls: Vec = resourceref_resolver - .resolve_all(minecraft_server.namespace().as_ref().unwrap(), plugins) - .await? - .into_iter() - .map(|url| url.to_string()) - .collect(); + if !plugin_urls.is_empty() { + let urls: Vec = plugin_urls.into_iter().map(|url| url.to_string()).collect(); env.push(EnvVar { name: "SERVER_PLUGIN_URLS".to_string(), @@ -492,6 +484,42 @@ impl<'a> GameServerBuilder { env } + async fn get_plugin_urls( + resourceref_resolver: &ResourceRefResolver, + context: &GameServerBuilderContext<'a>, + minecraft_server: &MinecraftServer, + ) -> Result, anyhow::Error> { + let agent_platform = match minecraft_server.spec.version.channel { + MinecraftServerVersion::Paper | MinecraftServerVersion::Folia => { + Some("paper".to_string()) + } + }; + + let mut plugin_refs: Vec = vec![]; + + if let Some(agent_platform) = agent_platform { + plugin_refs.push( + get_agent_plugin_url( + resourceref_resolver, + context.agent_config, + AgentSide::Server, + agent_platform, + ) + .await?, + ) + } + + if let Some(plugins) = &minecraft_server.spec.config.plugins { + plugin_refs.extend( + resourceref_resolver + .resolve_all(minecraft_server.namespace().as_ref().unwrap(), plugins) + .await?, + ); + } + + Ok(plugin_refs) + } + fn get_type_from_version_channel(channel: &MinecraftServerVersion) -> String { match channel { MinecraftServerVersion::Paper => "PAPER".to_string(), @@ -614,7 +642,7 @@ mod tests { plugins_env, &EnvVar { name: "SERVER_PLUGIN_URLS".to_string(), - value: Some("https://example.com/my_plugin.jar".to_string()), + value: Some("https://maven.jeremylvln.fr/artifactory/shulker-snapshots/io/shulkermc/shulker-server-agent/0.0.0-test-cfg/shulker-server-agent-0.0.0-test-cfg-paper.jar;https://example.com/my_plugin.jar".to_string()), ..EnvVar::default() } ); 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 c211610f..24336eb6 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 @@ -6,7 +6,7 @@ apiVersion: v1 kind: ConfigMap data: bukkit-config.yml: "settings:\n allow-end: false\nauto-updater:\n enabled: false\n\n" - init-fs.sh: "#!/bin/sh\nset -euo pipefail\nset -o xtrace\n\ncp \"${SHULKER_CONFIG_DIR}/server.properties\" \"${SERVER_CONFIG_DIR}/server.properties\"\nif [ \"${TYPE}\" == \"PAPER\" ] || [ \"${TYPE}\" == \"FOLIA\" ]; then\n cp \"${SHULKER_CONFIG_DIR}/bukkit-config.yml\" \"${SERVER_CONFIG_DIR}/bukkit.yml\"\n cp \"${SHULKER_CONFIG_DIR}/spigot-config.yml\" \"${SERVER_CONFIG_DIR}/spigot.yml\"\n mkdir -p \"${SERVER_CONFIG_DIR}/config\"\n cp \"${SHULKER_CONFIG_DIR}/paper-global-config.yml\" \"${SERVER_CONFIG_DIR}/config/paper-global.yml\"\nfi\n\nif [ ! -z \"${SERVER_WORLD_URL+x}\" ]; then\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${SERVER_WORLD_URL}\" -O - | tar -xzv)\nfi\n\nmkdir -p \"${SERVER_CONFIG_DIR}/plugins\"\nif [ \"${TYPE}\" == \"PAPER\" ] || [ \"${TYPE}\" == \"FOLIA\" ]; then\n (cd \"${SERVER_CONFIG_DIR}/plugins\" && wget \"${SHULKER_MAVEN_REPOSITORY}/io/shulkermc/shulker-server-agent/${SHULKER_SERVER_AGENT_VERSION}/shulker-server-agent-${SHULKER_SERVER_AGENT_VERSION}-paper.jar\")\nelse\n echo \"[!] No server agent available for this server type\"\n exit 1\nfi\n\nif [ ! -z \"${SERVER_PLUGIN_URLS+x}\" ]; then\n for plugin_url in ${SERVER_PLUGIN_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}/plugins\" && wget \"${plugin_url}\")\n done\nfi\n\nif [ ! -z \"${SERVER_PATCH_URLS+x}\" ]; then\n for patch_url in ${SERVER_PATCH_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${patch_url}\" -O - | tar -xzv)\n done\nfi\n" + init-fs.sh: "#!/bin/sh\nset -euo pipefail\nset -o xtrace\n\ncp \"${SHULKER_CONFIG_DIR}/server.properties\" \"${SERVER_CONFIG_DIR}/server.properties\"\nif [ \"${TYPE}\" == \"PAPER\" ] || [ \"${TYPE}\" == \"FOLIA\" ]; then\n cp \"${SHULKER_CONFIG_DIR}/bukkit-config.yml\" \"${SERVER_CONFIG_DIR}/bukkit.yml\"\n cp \"${SHULKER_CONFIG_DIR}/spigot-config.yml\" \"${SERVER_CONFIG_DIR}/spigot.yml\"\n mkdir -p \"${SERVER_CONFIG_DIR}/config\"\n cp \"${SHULKER_CONFIG_DIR}/paper-global-config.yml\" \"${SERVER_CONFIG_DIR}/config/paper-global.yml\"\nfi\n\nif [ ! -z \"${SERVER_WORLD_URL+x}\" ]; then\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${SERVER_WORLD_URL}\" -O - | tar -xzv)\nfi\n\nif [ ! -z \"${SERVER_PLUGIN_URLS+x}\" ]; then\n for plugin_url in ${SERVER_PLUGIN_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}/plugins\" && wget \"${plugin_url}\")\n done\nfi\n\nif [ ! -z \"${SERVER_PATCH_URLS+x}\" ]; then\n for patch_url in ${SERVER_PATCH_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${patch_url}\" -O - | tar -xzv)\n done\nfi\n" paper-global-config.yml: "proxies:\n bungee-cord:\n online-mode: false\n velocity:\n enabled: true\n online-mode: true\n secret: ${CFG_VELOCITY_FORWARDING_SECRET}\n\n" server.properties: "allow-nether=true\nenforce-secure-profiles=true\nmax-players=42\nonline-mode=false\nprevent-proxy-connections=false\n" 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" 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 04bcfb38..36960786 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 @@ -107,14 +107,10 @@ spec: value: /data - name: TYPE value: PAPER - - name: SHULKER_MAVEN_REPOSITORY - value: "https://maven.jeremylvln.fr/artifactory/shulker-snapshots" - - name: SHULKER_SERVER_AGENT_VERSION - value: 0.0.0-test-cfg - name: SERVER_WORLD_URL value: "https://example.com/my_world.tar.gz" - name: SERVER_PLUGIN_URLS - value: "https://example.com/my_plugin.jar" + value: "https://maven.jeremylvln.fr/artifactory/shulker-snapshots/io/shulkermc/shulker-server-agent/0.0.0-test-cfg/shulker-server-agent-0.0.0-test-cfg-paper.jar;https://example.com/my_plugin.jar" - name: SERVER_PATCH_URLS value: "https://example.com/my_patch.tar.gz" image: "alpine:latest" 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 1ed0bea1..09dddb82 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 @@ -6,7 +6,7 @@ apiVersion: v1 kind: ConfigMap data: bukkit-config.yml: "settings:\n allow-end: false\nauto-updater:\n enabled: false\n\n" - init-fs.sh: "#!/bin/sh\nset -euo pipefail\nset -o xtrace\n\ncp \"${SHULKER_CONFIG_DIR}/server.properties\" \"${SERVER_CONFIG_DIR}/server.properties\"\nif [ \"${TYPE}\" == \"PAPER\" ] || [ \"${TYPE}\" == \"FOLIA\" ]; then\n cp \"${SHULKER_CONFIG_DIR}/bukkit-config.yml\" \"${SERVER_CONFIG_DIR}/bukkit.yml\"\n cp \"${SHULKER_CONFIG_DIR}/spigot-config.yml\" \"${SERVER_CONFIG_DIR}/spigot.yml\"\n mkdir -p \"${SERVER_CONFIG_DIR}/config\"\n cp \"${SHULKER_CONFIG_DIR}/paper-global-config.yml\" \"${SERVER_CONFIG_DIR}/config/paper-global.yml\"\nfi\n\nif [ ! -z \"${SERVER_WORLD_URL+x}\" ]; then\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${SERVER_WORLD_URL}\" -O - | tar -xzv)\nfi\n\nmkdir -p \"${SERVER_CONFIG_DIR}/plugins\"\nif [ \"${TYPE}\" == \"PAPER\" ] || [ \"${TYPE}\" == \"FOLIA\" ]; then\n (cd \"${SERVER_CONFIG_DIR}/plugins\" && wget \"${SHULKER_MAVEN_REPOSITORY}/io/shulkermc/shulker-server-agent/${SHULKER_SERVER_AGENT_VERSION}/shulker-server-agent-${SHULKER_SERVER_AGENT_VERSION}-paper.jar\")\nelse\n echo \"[!] No server agent available for this server type\"\n exit 1\nfi\n\nif [ ! -z \"${SERVER_PLUGIN_URLS+x}\" ]; then\n for plugin_url in ${SERVER_PLUGIN_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}/plugins\" && wget \"${plugin_url}\")\n done\nfi\n\nif [ ! -z \"${SERVER_PATCH_URLS+x}\" ]; then\n for patch_url in ${SERVER_PATCH_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${patch_url}\" -O - | tar -xzv)\n done\nfi\n" + init-fs.sh: "#!/bin/sh\nset -euo pipefail\nset -o xtrace\n\ncp \"${SHULKER_CONFIG_DIR}/server.properties\" \"${SERVER_CONFIG_DIR}/server.properties\"\nif [ \"${TYPE}\" == \"PAPER\" ] || [ \"${TYPE}\" == \"FOLIA\" ]; then\n cp \"${SHULKER_CONFIG_DIR}/bukkit-config.yml\" \"${SERVER_CONFIG_DIR}/bukkit.yml\"\n cp \"${SHULKER_CONFIG_DIR}/spigot-config.yml\" \"${SERVER_CONFIG_DIR}/spigot.yml\"\n mkdir -p \"${SERVER_CONFIG_DIR}/config\"\n cp \"${SHULKER_CONFIG_DIR}/paper-global-config.yml\" \"${SERVER_CONFIG_DIR}/config/paper-global.yml\"\nfi\n\nif [ ! -z \"${SERVER_WORLD_URL+x}\" ]; then\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${SERVER_WORLD_URL}\" -O - | tar -xzv)\nfi\n\nif [ ! -z \"${SERVER_PLUGIN_URLS+x}\" ]; then\n for plugin_url in ${SERVER_PLUGIN_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}/plugins\" && wget \"${plugin_url}\")\n done\nfi\n\nif [ ! -z \"${SERVER_PATCH_URLS+x}\" ]; then\n for patch_url in ${SERVER_PATCH_URLS//;/ }; do\n (cd \"${SERVER_CONFIG_DIR}\" && wget \"${patch_url}\" -O - | tar -xzv)\n done\nfi\n" paper-global-config.yml: "proxies:\n bungee-cord:\n online-mode: false\n velocity:\n enabled: true\n online-mode: true\n secret: ${CFG_VELOCITY_FORWARDING_SECRET}\n\n" server.properties: "allow-nether=true\nenforce-secure-profiles=true\nmax-players=42\nonline-mode=false\nprevent-proxy-connections=false\n" 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" 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 6adf19df..e2297169 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 @@ -129,14 +129,10 @@ spec: value: /data - name: TYPE value: PAPER - - name: SHULKER_MAVEN_REPOSITORY - value: "https://maven.jeremylvln.fr/artifactory/shulker-snapshots" - - name: SHULKER_SERVER_AGENT_VERSION - value: 0.0.0-test-cfg - name: SERVER_WORLD_URL value: "https://example.com/my_world.tar.gz" - name: SERVER_PLUGIN_URLS - value: "https://example.com/my_plugin.jar" + value: "https://maven.jeremylvln.fr/artifactory/shulker-snapshots/io/shulkermc/shulker-server-agent/0.0.0-test-cfg/shulker-server-agent-0.0.0-test-cfg-paper.jar;https://example.com/my_plugin.jar" - name: SERVER_PATCH_URLS value: "https://example.com/my_patch.tar.gz" image: "alpine:latest" diff --git a/packages/shulker-operator/src/reconcilers/mod.rs b/packages/shulker-operator/src/reconcilers/mod.rs index bca97add..cdd4d463 100644 --- a/packages/shulker-operator/src/reconcilers/mod.rs +++ b/packages/shulker-operator/src/reconcilers/mod.rs @@ -1,5 +1,6 @@ use thiserror::Error; +mod agent; mod cluster_ref; pub mod minecraft_cluster; pub mod minecraft_server; diff --git a/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs b/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs index 99c1b56e..125c039b 100644 --- a/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs +++ b/packages/shulker-operator/src/reconcilers/proxy_fleet/fleet.rs @@ -28,8 +28,11 @@ use kube::ResourceExt; use lazy_static::lazy_static; use shulker_crds::v1alpha1::minecraft_cluster::MinecraftCluster; use shulker_crds::v1alpha1::proxy_fleet::ProxyFleetTemplateVersion; +use url::Url; use crate::agent::AgentConfig; +use crate::reconcilers::agent::get_agent_plugin_url; +use crate::reconcilers::agent::AgentSide; use crate::reconcilers::redis_ref::RedisRef; use crate::resources::resourceref_resolver::ResourceRefResolver; use google_agones_crds::v1::fleet::Fleet; @@ -354,6 +357,9 @@ impl<'a> FleetBuilder { ) -> Result, anyhow::Error> { let spec = &proxy_fleet.spec.template.spec; + let plugin_urls = + FleetBuilder::get_plugin_urls(&self.resourceref_resolver, context, proxy_fleet).await?; + let mut env: Vec = vec![ EnvVar { name: "SHULKER_CONFIG_DIR".to_string(), @@ -370,26 +376,10 @@ impl<'a> FleetBuilder { value: Some(Self::get_type_from_version_channel(&spec.version.channel)), ..EnvVar::default() }, - EnvVar { - name: "SHULKER_MAVEN_REPOSITORY".to_string(), - value: Some(context.agent_config.maven_repository.clone()), - ..EnvVar::default() - }, - EnvVar { - name: "SHULKER_PROXY_AGENT_VERSION".to_string(), - value: Some(context.agent_config.version.clone()), - ..EnvVar::default() - }, ]; - if let Some(plugins) = &spec.config.plugins { - let urls: Vec = self - .resourceref_resolver - .resolve_all(proxy_fleet.namespace().as_ref().unwrap(), plugins) - .await? - .into_iter() - .map(|url| url.to_string()) - .collect(); + if !plugin_urls.is_empty() { + let urls: Vec = plugin_urls.into_iter().map(|url| url.to_string()).collect(); env.push(EnvVar { name: "PROXY_PLUGIN_URLS".to_string(), @@ -531,6 +521,43 @@ impl<'a> FleetBuilder { Ok(env) } + async fn get_plugin_urls( + resourceref_resolver: &ResourceRefResolver, + context: &FleetBuilderContext<'a>, + proxy_fleet: &ProxyFleet, + ) -> Result, anyhow::Error> { + let agent_platform = match proxy_fleet.spec.template.spec.version.channel { + ProxyFleetTemplateVersion::Velocity => Some("velocity".to_string()), + ProxyFleetTemplateVersion::BungeeCord | ProxyFleetTemplateVersion::Waterfall => { + Some("bungeecord".to_string()) + } + }; + + let mut plugin_refs: Vec = vec![]; + + if let Some(agent_platform) = agent_platform { + plugin_refs.push( + get_agent_plugin_url( + resourceref_resolver, + context.agent_config, + AgentSide::Proxy, + agent_platform, + ) + .await?, + ) + } + + if let Some(plugins) = &proxy_fleet.spec.template.spec.config.plugins { + plugin_refs.extend( + resourceref_resolver + .resolve_all(proxy_fleet.namespace().as_ref().unwrap(), plugins) + .await?, + ); + } + + Ok(plugin_refs) + } + fn get_type_from_version_channel(channel: &ProxyFleetTemplateVersion) -> String { match channel { ProxyFleetTemplateVersion::Velocity => "VELOCITY".to_string(), @@ -719,7 +746,7 @@ mod tests { plugins_env, &EnvVar { name: "PROXY_PLUGIN_URLS".to_string(), - value: Some("https://example.com/my_plugin.jar".to_string()), + value: Some("https://maven.jeremylvln.fr/artifactory/shulker-snapshots/io/shulkermc/shulker-proxy-agent/0.0.0-test-cfg/shulker-proxy-agent-0.0.0-test-cfg-velocity.jar;https://example.com/my_plugin.jar".to_string()), ..EnvVar::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 d8d5c655..d605715d 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 @@ -5,7 +5,7 @@ expression: config_map apiVersion: v1 kind: ConfigMap data: - init-fs.sh: "#!/bin/sh\nset -euo pipefail\nset -o xtrace\n\ncp \"${SHULKER_CONFIG_DIR}/probe-readiness.sh\" \"${PROXY_DATA_DIR}/probe-readiness.sh\"\ncat \"${SHULKER_CONFIG_DIR}/server-icon.png\" | base64 -d > \"${PROXY_DATA_DIR}/server-icon.png\"\n\nif [ \"${TYPE}\" == \"VELOCITY\" ]; then\n cp \"${SHULKER_CONFIG_DIR}/velocity-config.toml\" \"${PROXY_DATA_DIR}/velocity.toml\"\n echo \"dummy\" > \"${PROXY_DATA_DIR}/forwarding.secret\"\nelse\n cp \"${SHULKER_CONFIG_DIR}/bungeecord-config.yml\" \"${PROXY_DATA_DIR}/config.yml\"\nfi\n\nmkdir -p \"${PROXY_DATA_DIR}/plugins\"\nif [ \"${TYPE}\" == \"VELOCITY\" ]; then\n (cd \"${PROXY_DATA_DIR}/plugins\" && wget \"${SHULKER_MAVEN_REPOSITORY}/io/shulkermc/shulker-proxy-agent/${SHULKER_PROXY_AGENT_VERSION}/shulker-proxy-agent-${SHULKER_PROXY_AGENT_VERSION}-velocity.jar\")\nelse\n (cd \"${PROXY_DATA_DIR}/plugins\" && wget \"${SHULKER_MAVEN_REPOSITORY}/io/shulkermc/shulker-proxy-agent/${SHULKER_PROXY_AGENT_VERSION}/shulker-proxy-agent-${SHULKER_PROXY_AGENT_VERSION}-bungeecord.jar\")\nfi\n\nif [ ! -z \"${PROXY_PLUGIN_URLS+x}\" ]; then\n for plugin_url in ${PROXY_PLUGIN_URLS//;/ }; do\n (cd \"${PROXY_DATA_DIR}/plugins\" && wget \"${plugin_url}\")\n done\nfi\n\nif [ ! -z \"${PROXY_PATCH_URLS+x}\" ]; then\n for patch_url in ${PROXY_PATCH_URLS//;/ }; do\n (cd \"${PROXY_DATA_DIR}\" && wget \"${patch_url}\" -O - | tar -xzv)\n done\nfi\n" + init-fs.sh: "#!/bin/sh\nset -euo pipefail\nset -o xtrace\n\ncp \"${SHULKER_CONFIG_DIR}/probe-readiness.sh\" \"${PROXY_DATA_DIR}/probe-readiness.sh\"\ncat \"${SHULKER_CONFIG_DIR}/server-icon.png\" | base64 -d > \"${PROXY_DATA_DIR}/server-icon.png\"\n\nif [ \"${TYPE}\" == \"VELOCITY\" ]; then\n cp \"${SHULKER_CONFIG_DIR}/velocity-config.toml\" \"${PROXY_DATA_DIR}/velocity.toml\"\n echo \"dummy\" > \"${PROXY_DATA_DIR}/forwarding.secret\"\nelse\n cp \"${SHULKER_CONFIG_DIR}/bungeecord-config.yml\" \"${PROXY_DATA_DIR}/config.yml\"\nfi\n\nif [ ! -z \"${PROXY_PLUGIN_URLS+x}\" ]; then\n for plugin_url in ${PROXY_PLUGIN_URLS//;/ }; do\n (cd \"${PROXY_DATA_DIR}/plugins\" && wget \"${plugin_url}\")\n done\nfi\n\nif [ ! -z \"${PROXY_PATCH_URLS+x}\" ]; then\n for patch_url in ${PROXY_PATCH_URLS//;/ }; do\n (cd \"${PROXY_DATA_DIR}\" && wget \"${patch_url}\" -O - | tar -xzv)\n done\nfi\n" probe-readiness.sh: "#!/bin/sh\nset -euo pipefail\nset -o xtrace\n\nif [ -f \"/tmp/drain-lock\" ]; then\n echo \"Drain lock found\" && exit 1\nfi\n\nbash /health.sh\n" server-icon.png: abc== velocity-config.toml: "config-version = \"2.5\"\nbind = \"0.0.0.0:25577\"\nmotd = \"A Motd\"\nshow-max-players = 1000\nonline-mode = true\nforce-key-authentication = true\nprevent-client-proxy-connections = true\nforwarding-secret-file = \"/mnt/shulker/forwarding-secret/key\"\nplayer-info-forwarding-mode = \"modern\"\n\n[servers]\nlobby = \"localhost:30000\"\nlimbo = \"localhost:30001\"\ntry = [\"lobby\", \"limbo\"]\n\n[forced-hosts]\n\n[advanced]\nhaproxy-protocol = true\ntcp-fast-open = true\n\n" 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 ca74b191..76df9a7e 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 @@ -128,12 +128,8 @@ spec: value: /server - name: TYPE value: VELOCITY - - name: SHULKER_MAVEN_REPOSITORY - value: "https://maven.jeremylvln.fr/artifactory/shulker-snapshots" - - name: SHULKER_PROXY_AGENT_VERSION - value: 0.0.0-test-cfg - name: PROXY_PLUGIN_URLS - value: "https://example.com/my_plugin.jar" + value: "https://maven.jeremylvln.fr/artifactory/shulker-snapshots/io/shulkermc/shulker-proxy-agent/0.0.0-test-cfg/shulker-proxy-agent-0.0.0-test-cfg-velocity.jar;https://example.com/my_plugin.jar" - name: PROXY_PATCH_URLS value: "https://example.com/my_patch.tar.gz" image: "alpine:latest" diff --git a/packages/shulker-operator/src/resources/maven/fixtures/maven-metadata.xml b/packages/shulker-operator/src/resources/maven/fixtures/maven-metadata.xml new file mode 100644 index 00000000..ea2f6518 --- /dev/null +++ b/packages/shulker-operator/src/resources/maven/fixtures/maven-metadata.xml @@ -0,0 +1,32 @@ + + + io.shulkermc + google-agones-sdk + 0.3.0-SNAPSHOT + + + 20231127.141358 + 1 + + 20231127141408 + + + javadoc + jar + 0.3.0-20231127.141358-1 + 20231127141358 + + + sources + jar + 0.3.0-20231127.141358-2 + 20231127141358 + + + jar + 0.3.0-20231127.141358-3 + 20231127141358 + + + + diff --git a/packages/shulker-operator/src/resources/maven/fixtures/mod.rs b/packages/shulker-operator/src/resources/maven/fixtures/mod.rs new file mode 100644 index 00000000..f5f2acc1 --- /dev/null +++ b/packages/shulker-operator/src/resources/maven/fixtures/mod.rs @@ -0,0 +1 @@ +pub const MAVEN_METADATA: &str = include_str!("maven-metadata.xml"); diff --git a/packages/shulker-operator/src/resources/maven/mod.rs b/packages/shulker-operator/src/resources/maven/mod.rs new file mode 100644 index 00000000..cb21de32 --- /dev/null +++ b/packages/shulker-operator/src/resources/maven/mod.rs @@ -0,0 +1,129 @@ +use serde::Deserialize; + +pub mod resolver; + +#[cfg(test)] +mod fixtures; + +#[derive(Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct MavenMetadata { + pub versioning: MavenMetadataVersionning, +} + +#[derive(Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct MavenMetadataVersionning { + pub snapshot_versions: Option, +} + +#[derive(Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct MavenMetadataVersionningSnapshotVersions { + #[serde(rename = "$value")] + pub versions: Vec, +} + +#[derive(Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct MavenMetadataVersionningSnapshotVersion { + pub extension: String, + pub value: String, + pub updated: u64, + pub classifier: Option, +} + +impl MavenMetadata { + pub fn find_latest_snapshot_version(&self, extension: &str) -> Option { + self.find_latest_snapshot_version_for_classifier(extension, None) + } + + pub fn find_latest_snapshot_version_for_classifier( + &self, + extension: &str, + classifier: Option<&str>, + ) -> Option { + match &self.versioning.snapshot_versions { + Some(versions) => { + let mut versions = versions.versions.clone(); + versions.sort_by(|a, b| b.updated.cmp(&a.updated)); + versions + .into_iter() + .find(|v| v.extension == extension && v.classifier.as_deref() == classifier) + .map(|v| v.value) + } + None => None, + } + } +} + +#[cfg(test)] +mod tests { + use crate::resources::maven::{ + MavenMetadata, MavenMetadataVersionning, MavenMetadataVersionningSnapshotVersion, + MavenMetadataVersionningSnapshotVersions, + }; + + use super::fixtures::MAVEN_METADATA; + + #[test] + fn parse() { + // G + let metadata: MavenMetadata = serde_xml_rs::from_str(MAVEN_METADATA).unwrap(); + + // W + assert_eq!( + metadata, + MavenMetadata { + versioning: MavenMetadataVersionning { + snapshot_versions: Some(MavenMetadataVersionningSnapshotVersions { + versions: vec![ + MavenMetadataVersionningSnapshotVersion { + extension: "jar".to_string(), + value: "0.3.0-20231127.141358-1".to_string(), + updated: 20231127141358, + classifier: Some("javadoc".to_string()), + }, + MavenMetadataVersionningSnapshotVersion { + extension: "jar".to_string(), + value: "0.3.0-20231127.141358-2".to_string(), + updated: 20231127141358, + classifier: Some("sources".to_string()), + }, + MavenMetadataVersionningSnapshotVersion { + extension: "jar".to_string(), + value: "0.3.0-20231127.141358-3".to_string(), + updated: 20231127141358, + classifier: None, + }, + ], + }), + } + } + ) + } + + #[test] + fn find_latest_snapshot_version() { + // G + let metadata: MavenMetadata = serde_xml_rs::from_str(MAVEN_METADATA).unwrap(); + + // W + let version = metadata.find_latest_snapshot_version("jar"); + + // T + assert_eq!(version, Some("0.3.0-20231127.141358-3".to_string())) + } + + #[test] + fn find_latest_snapshot_version_for_classifier() { + // G + let metadata: MavenMetadata = serde_xml_rs::from_str(MAVEN_METADATA).unwrap(); + + // W + let version = metadata.find_latest_snapshot_version_for_classifier("jar", Some("sources")); + + // T + assert_eq!(version, Some("0.3.0-20231127.141358-2".to_string())) + } +} diff --git a/packages/shulker-operator/src/resources/maven/resolver.rs b/packages/shulker-operator/src/resources/maven/resolver.rs new file mode 100644 index 00000000..d0686acc --- /dev/null +++ b/packages/shulker-operator/src/resources/maven/resolver.rs @@ -0,0 +1,107 @@ +use http::StatusCode; +use reqwest::Client; +use thiserror::Error; +use tracing::*; + +use crate::resources::http_credentials::HttpCredentials; + +use super::MavenMetadata; + +#[derive(Error, Debug)] +pub enum ResolverError { + #[error("failed to perform request: {0}")] + FailedToRequestUnderlying(#[source] reqwest::Error), + + #[error("failed to request, got status {0}: {1}")] + FailedToRequest(StatusCode, String), + + #[error("failed to parse Maven metadata: {0}")] + FailedToParseMetadata(#[source] serde_xml_rs::Error), +} + +pub type Result = std::result::Result; + +pub struct MavenResolver { + repository_url: String, + credentials: Option, + http_client: Client, +} + +impl MavenResolver { + pub fn new(repository_url: String, credentials: Option) -> Self { + MavenResolver { + repository_url, + credentials, + http_client: Client::new(), + } + } + + pub async fn try_resolve_artifact_metadata( + &self, + group_id: &str, + artifact_id: &str, + ) -> Result> { + let url = format!( + "{}/{}/{}/maven-metadata.xml", + self.repository_url, + group_id.replace('.', "/"), + artifact_id + ); + + self.try_resolve_metadata(url).await + } + + pub async fn try_resolve_version_metadata( + &self, + group_id: &str, + artifact_id: &str, + version: &str, + ) -> Result> { + let url = format!( + "{}/{}/{}/{}/maven-metadata.xml", + self.repository_url, + group_id.replace('.', "/"), + artifact_id, + version + ); + + self.try_resolve_metadata(url).await + } + + async fn try_resolve_metadata(&self, url: String) -> Result> { + debug!(url = url, "trying to resolve Maven metadata"); + let mut request_builder = self.http_client.get(url); + if let Some(credentials) = &self.credentials { + request_builder = request_builder.basic_auth( + credentials.username.clone(), + Some(credentials.password.clone()), + ); + } + + let response = request_builder + .send() + .await + .map_err(ResolverError::FailedToRequestUnderlying)?; + + if !response.status().is_success() { + if response.status().as_u16() == 404 { + return Ok(None); + } + + return Err(ResolverError::FailedToRequest( + response.status(), + response + .text() + .await + .map_err(ResolverError::FailedToRequestUnderlying)?, + )); + } + + let response_str = response + .text() + .await + .map_err(ResolverError::FailedToRequestUnderlying)?; + + serde_xml_rs::from_str(&response_str).map_err(ResolverError::FailedToParseMetadata) + } +} diff --git a/packages/shulker-operator/src/resources/mod.rs b/packages/shulker-operator/src/resources/mod.rs index c5ad4e01..7bd81a5e 100644 --- a/packages/shulker-operator/src/resources/mod.rs +++ b/packages/shulker-operator/src/resources/mod.rs @@ -1,6 +1,7 @@ use thiserror::Error; pub mod http_credentials; +pub mod maven; pub mod resourceref; pub mod resourceref_resolver; @@ -15,6 +16,9 @@ pub enum ResourceRefError { #[error("invalid generated URL for a resource: {0}")] InvalidUrlSpec(#[source] url::ParseError), + #[error("failed to resolve Maven metadata: {0}")] + FailedToResolveMavenMetadata(#[source] maven::resolver::ResolverError), + #[error("invalid resource ref")] InvalidSpec, } diff --git a/packages/shulker-operator/src/resources/resourceref.rs b/packages/shulker-operator/src/resources/resourceref.rs index 2db86a89..10c826fa 100644 --- a/packages/shulker-operator/src/resources/resourceref.rs +++ b/packages/shulker-operator/src/resources/resourceref.rs @@ -1,5 +1,16 @@ use super::{http_credentials::HttpCredentials, ResourceRefError, Result}; +#[derive(Clone, Debug, PartialEq)] +pub struct MavenArtifact { + repository_url: String, + group_id: String, + artifact_id: String, + version: String, + snapshot_version: Option, + classifier: Option, + credentials: Option, +} + #[derive(Clone, Debug, PartialEq)] pub enum ResourceRef { Url(String), @@ -8,6 +19,7 @@ pub enum ResourceRef { group_id: String, artifact_id: String, version: String, + snapshot_version: Option, classifier: Option, credentials: Option, }, @@ -24,13 +36,17 @@ impl ResourceRef { group_id, artifact_id, version, + snapshot_version, classifier, credentials, } => { let group_path = group_id.replace('.', "/"); + let file_version = snapshot_version.as_ref().unwrap_or(version); let file_name = match classifier { - None => format!("{}-{}.jar", artifact_id, version), - Some(classifier) => format!("{}-{}-{}.jar", artifact_id, version, classifier), + None => format!("{}-{}.jar", artifact_id, file_version), + Some(classifier) => { + format!("{}-{}-{}.jar", artifact_id, file_version, classifier) + } }; let mut url = url::Url::parse(&format!( @@ -67,13 +83,14 @@ mod tests { } #[test] - fn serialize_mavenartifact_without_classifier_credentials() { + fn serialize_mavenartifact_with_snapshot_version() { // G let resourceref = super::ResourceRef::MavenArtifact { repository_url: "https://example.com".to_string(), group_id: "io.shulkermc".to_string(), artifact_id: "test".to_string(), version: "1.0.0".to_string(), + snapshot_version: Some("0.3.0-20231127.101010-1".to_string()), classifier: None, credentials: None, }; @@ -84,18 +101,19 @@ mod tests { // T assert_eq!( url.to_string(), - "https://example.com/io/shulkermc/test/1.0.0/test-1.0.0.jar" + "https://example.com/io/shulkermc/test/1.0.0/test-0.3.0-20231127.101010-1.jar" ); } #[test] - fn serialize_mavenartifact_with_classifier_without_credentials() { + fn serialize_mavenartifact_with_classifier() { // G let resourceref = super::ResourceRef::MavenArtifact { repository_url: "https://example.com".to_string(), group_id: "io.shulkermc".to_string(), artifact_id: "test".to_string(), version: "1.0.0".to_string(), + snapshot_version: None, classifier: Some("api".to_string()), credentials: None, }; @@ -111,13 +129,14 @@ mod tests { } #[test] - fn serialize_mavenartifact_with_classifier_credentials() { + fn serialize_mavenartifact_with_credentials() { // G let resourceref = super::ResourceRef::MavenArtifact { repository_url: "https://example.com".to_string(), group_id: "io.shulkermc".to_string(), artifact_id: "test".to_string(), version: "1.0.0".to_string(), + snapshot_version: None, classifier: Some("api".to_string()), credentials: Some(HttpCredentials { username: "user".to_string(), diff --git a/packages/shulker-operator/src/resources/resourceref_resolver.rs b/packages/shulker-operator/src/resources/resourceref_resolver.rs index 8c336ca8..a9f0f9fe 100644 --- a/packages/shulker-operator/src/resources/resourceref_resolver.rs +++ b/packages/shulker-operator/src/resources/resourceref_resolver.rs @@ -4,7 +4,8 @@ use url::Url; use shulker_crds::resourceref::ResourceRefSpec; use super::{ - http_credentials::HttpCredentials, resourceref::ResourceRef, ResourceRefError, Result, + http_credentials::HttpCredentials, maven::resolver::MavenResolver, resourceref::ResourceRef, + ResourceRefError, Result, }; pub struct ResourceRefResolver { @@ -53,11 +54,31 @@ impl ResourceRefResolver { } }; + let snapshot_version = if maven_ref.version.ends_with("-SNAPSHOT") { + MavenResolver::new(maven_ref.repository_url.clone(), credentials.clone()) + .try_resolve_version_metadata( + &maven_ref.group_id, + &maven_ref.artifact_id, + &maven_ref.version, + ) + .await + .map_err(ResourceRefError::FailedToResolveMavenMetadata)? + .and_then(|metadata| { + metadata.find_latest_snapshot_version_for_classifier( + "jar", + maven_ref.classifier.as_deref(), + ) + }) + } else { + None + }; + return Ok(ResourceRef::MavenArtifact { repository_url: maven_ref.repository_url.clone(), group_id: maven_ref.group_id.clone(), artifact_id: maven_ref.artifact_id.clone(), version: maven_ref.version.clone(), + snapshot_version, classifier: maven_ref.classifier.clone(), credentials, }); @@ -219,6 +240,7 @@ mod tests { group_id, artifact_id, version, + snapshot_version: None, classifier: Some(classifier), credentials: None, } @@ -285,6 +307,7 @@ mod tests { group_id, artifact_id, version, + snapshot_version: None, classifier: Some(classifier), credentials: Some(super::HttpCredentials { username: "user".to_string(), diff --git a/packages/shulker-proxy-agent/build.gradle.kts b/packages/shulker-proxy-agent/build.gradle.kts index 89683464..f0f59c1f 100644 --- a/packages/shulker-proxy-agent/build.gradle.kts +++ b/packages/shulker-proxy-agent/build.gradle.kts @@ -8,8 +8,8 @@ dependencies { commonApi(project(":packages:shulker-proxy-api")) // Kubernetes - commonCompileOnly(libs.kubernetes.client) - commonRuntimeOnly(libs.kubernetes.client.api) + commonCompileOnly(libs.kubernetes.client.api) + commonRuntimeOnly(libs.kubernetes.client) commonImplementation(libs.kubernetes.client.http) // Agones