From 2196b3e4f168905fdacf9605790a73cc017793a4 Mon Sep 17 00:00:00 2001 From: Brutus5000 Date: Sat, 9 Nov 2024 19:44:39 +0100 Subject: [PATCH 01/22] Add telepresence --- cluster/telepresence/Chart.yaml | 7 +++++++ cluster/telepresence/values.yaml | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 cluster/telepresence/Chart.yaml create mode 100644 cluster/telepresence/values.yaml diff --git a/cluster/telepresence/Chart.yaml b/cluster/telepresence/Chart.yaml new file mode 100644 index 00000000..2596ffc2 --- /dev/null +++ b/cluster/telepresence/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: telepresence +version: 1.0.0 +dependencies: + - name: telepresence-oss + version: 2.21.3 + repository: oci://ghcr.io/telepresenceio \ No newline at end of file diff --git a/cluster/telepresence/values.yaml b/cluster/telepresence/values.yaml new file mode 100644 index 00000000..72fa2a8d --- /dev/null +++ b/cluster/telepresence/values.yaml @@ -0,0 +1,3 @@ +namespace: telepresence +telepresence: + releaseName: traffic-manager \ No newline at end of file From 11e38026e12161605c2098fdf0c26cf26b2f2337 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 20:53:33 +0000 Subject: [PATCH 02/22] Update telepresence-oss Docker tag to v2.25.1 --- cluster/telepresence/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/telepresence/Chart.yaml b/cluster/telepresence/Chart.yaml index 2596ffc2..34f52f1e 100644 --- a/cluster/telepresence/Chart.yaml +++ b/cluster/telepresence/Chart.yaml @@ -3,5 +3,5 @@ name: telepresence version: 1.0.0 dependencies: - name: telepresence-oss - version: 2.21.3 + version: 2.25.1 repository: oci://ghcr.io/telepresenceio \ No newline at end of file From 880ea81e4f02377999255217556b8dbe4cc34ad1 Mon Sep 17 00:00:00 2001 From: Sheikah45 <66929319+Sheikah45@users.noreply.github.com> Date: Sun, 23 Mar 2025 15:18:33 -0400 Subject: [PATCH 03/22] Add replays old to content (#204) * Update values.yaml * Update deployment.yaml --- apps/faf-content/templates/deployment.yaml | 7 +++++++ cluster/storage/values.yaml | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/apps/faf-content/templates/deployment.yaml b/apps/faf-content/templates/deployment.yaml index c84d6417..d06d01e6 100644 --- a/apps/faf-content/templates/deployment.yaml +++ b/apps/faf-content/templates/deployment.yaml @@ -33,6 +33,9 @@ spec: - name: faf-replays-pvc mountPath: /data/replays readOnly: true + - name: faf-replays-old-pvc + mountPath: /data/replays-old + readOnly: true - name: faf-maps-pvc mountPath: /data/maps readOnly: true @@ -69,6 +72,10 @@ spec: persistentVolumeClaim: claimName: faf-replays-pvc readOnly: true + - name: faf-replays-old-pvc + persistentVolumeClaim: + claimName: faf-replays-old-pvc + readOnly: true - name: faf-maps-pvc persistentVolumeClaim: claimName: faf-maps-pvc diff --git a/cluster/storage/values.yaml b/cluster/storage/values.yaml index 374e8dd4..5abc8e17 100644 --- a/cluster/storage/values.yaml +++ b/cluster/storage/values.yaml @@ -24,6 +24,12 @@ managedStorages: size: 500Gi pvc: namespace: faf-apps + - pv: + name: faf-replays-old + folderName: replays-old + size: 500Gi + pvc: + namespace: faf-apps - pv: name: faf-maps folderName: maps From 48709658eb71ec9d3a02de3ec201590667cb4078 Mon Sep 17 00:00:00 2001 From: Sheikah45 <66929319+Sheikah45@users.noreply.github.com> Date: Sun, 23 Mar 2025 15:32:58 -0400 Subject: [PATCH 04/22] not read only attempy --- apps/faf-content/templates/deployment.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/faf-content/templates/deployment.yaml b/apps/faf-content/templates/deployment.yaml index d06d01e6..77fc7c23 100644 --- a/apps/faf-content/templates/deployment.yaml +++ b/apps/faf-content/templates/deployment.yaml @@ -35,7 +35,6 @@ spec: readOnly: true - name: faf-replays-old-pvc mountPath: /data/replays-old - readOnly: true - name: faf-maps-pvc mountPath: /data/maps readOnly: true @@ -75,7 +74,6 @@ spec: - name: faf-replays-old-pvc persistentVolumeClaim: claimName: faf-replays-old-pvc - readOnly: true - name: faf-maps-pvc persistentVolumeClaim: claimName: faf-maps-pvc From 186ff098691dafd5ada36bbcc66c517fccae6702 Mon Sep 17 00:00:00 2001 From: Sheikah45 <66929319+Sheikah45@users.noreply.github.com> Date: Sun, 23 Mar 2025 15:33:46 -0400 Subject: [PATCH 05/22] remove replays-old mount to nginx --- apps/faf-content/templates/deployment.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/faf-content/templates/deployment.yaml b/apps/faf-content/templates/deployment.yaml index 77fc7c23..c84d6417 100644 --- a/apps/faf-content/templates/deployment.yaml +++ b/apps/faf-content/templates/deployment.yaml @@ -33,8 +33,6 @@ spec: - name: faf-replays-pvc mountPath: /data/replays readOnly: true - - name: faf-replays-old-pvc - mountPath: /data/replays-old - name: faf-maps-pvc mountPath: /data/maps readOnly: true @@ -71,9 +69,6 @@ spec: persistentVolumeClaim: claimName: faf-replays-pvc readOnly: true - - name: faf-replays-old-pvc - persistentVolumeClaim: - claimName: faf-replays-old-pvc - name: faf-maps-pvc persistentVolumeClaim: claimName: faf-maps-pvc From 517aea523e9af09f0f4ab76940e51ecc3f8b24fd Mon Sep 17 00:00:00 2001 From: Sheikah45 <66929319+Sheikah45@users.noreply.github.com> Date: Sat, 3 May 2025 18:13:06 -0400 Subject: [PATCH 06/22] Change delay to 30 seconds --- apps/faf-replay-server/config/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/faf-replay-server/config/config.yaml b/apps/faf-replay-server/config/config.yaml index c46329c7..8c15c806 100644 --- a/apps/faf-replay-server/config/config.yaml +++ b/apps/faf-replay-server/config/config.yaml @@ -17,7 +17,7 @@ storage: replay: forced_timeout_s: 18000 time_with_zero_writers_to_end_replay_s: 30 - delay_s: 300 + delay_s: 30 update_interval_s: 1 merge_quorum_size: 2 - stream_comparison_distance_b: 4096 \ No newline at end of file + stream_comparison_distance_b: 4096 From b4989089af462e7f3dc84972d8d2214cbd50becc Mon Sep 17 00:00:00 2001 From: BlackYps <52536103+BlackYps@users.noreply.github.com> Date: Thu, 8 May 2025 20:36:55 +0200 Subject: [PATCH 07/22] Allow top players to match with anyone in the 1v1 queue (#211) * Let top players match with anyone in the 1v1 queue --- apps/faf-lobby-server/config/config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/faf-lobby-server/config/config.yaml b/apps/faf-lobby-server/config/config.yaml index 5a5679e6..62b83932 100644 --- a/apps/faf-lobby-server/config/config.yaml +++ b/apps/faf-lobby-server/config/config.yaml @@ -40,6 +40,9 @@ NEWBIE_TIME_BONUS: .25 MAXIMUM_NEWBIE_TIME_BONUS: 3.0 MINORITY_BONUS: 1 +LADDER_TOP_PLAYER_SEARCH_EXPANSION_MAX: 1.0 +LADDER_TOP_PLAYER_SEARCH_EXPANSION_STEP: 1.0 + QUEUE_POP_TIME_MAX: 90 # LADDER_VIOLATIONS_ENABLED: false \ No newline at end of file From d594b74d992dfbd79d9078177aaa7a600081e08e Mon Sep 17 00:00:00 2001 From: Brutus5000 Date: Fri, 5 Sep 2025 21:19:47 +0200 Subject: [PATCH 08/22] Enable force relay --- apps/faf-icebreaker/templates/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/faf-icebreaker/templates/config.yaml b/apps/faf-icebreaker/templates/config.yaml index 44f97b04..2227dc60 100644 --- a/apps/faf-icebreaker/templates/config.yaml +++ b/apps/faf-icebreaker/templates/config.yaml @@ -18,5 +18,5 @@ data: XIRSYS_TURN_ENABLED: "true" GEOIPUPDATE_EDITION_IDS: "GeoLite2-City" LOKI_BASE_URL: "http://monitoring-loki-gateway.faf-ops.svc" - FORCE_RELAY: "false" + FORCE_RELAY: "true" QUARKUS_LOG_CATEGORY__COM_FAFOREVER__LEVEL: "DEBUG" \ No newline at end of file From 8fe82e968d4b9d51236ef689d28a0ff5eb5e7ff3 Mon Sep 17 00:00:00 2001 From: Ivan-Shaml <72102779+Ivan-Shaml@users.noreply.github.com> Date: Mon, 8 Sep 2025 00:13:35 +0300 Subject: [PATCH 09/22] ice-breaker set to trace (attempt 1) --- apps/faf-icebreaker/templates/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/faf-icebreaker/templates/config.yaml b/apps/faf-icebreaker/templates/config.yaml index 2227dc60..08bbfc4a 100644 --- a/apps/faf-icebreaker/templates/config.yaml +++ b/apps/faf-icebreaker/templates/config.yaml @@ -19,4 +19,4 @@ data: GEOIPUPDATE_EDITION_IDS: "GeoLite2-City" LOKI_BASE_URL: "http://monitoring-loki-gateway.faf-ops.svc" FORCE_RELAY: "true" - QUARKUS_LOG_CATEGORY__COM_FAFOREVER__LEVEL: "DEBUG" \ No newline at end of file + QUARKUS_LOG_CATEGORY__COM_FAFOREVER__LEVEL: "TRACE" \ No newline at end of file From 4d6b33f7e0b308fe00fffc5ccf79317432a5eee0 Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 17:33:20 +0200 Subject: [PATCH 10/22] Drop promtail --- ops/monitoring/Chart.yaml | 6 +++--- ops/monitoring/values-test.yaml | 3 +++ ops/monitoring/values.yaml | 23 +++++++++++++++++++---- 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 ops/monitoring/values-test.yaml diff --git a/ops/monitoring/Chart.yaml b/ops/monitoring/Chart.yaml index 541e70ff..a787d872 100644 --- a/ops/monitoring/Chart.yaml +++ b/ops/monitoring/Chart.yaml @@ -5,9 +5,9 @@ dependencies: - name: victoria-metrics-k8s-stack version: 0.60.1 repository: https://victoriametrics.github.io/helm-charts/ -- name: promtail - version: 6.17.0 - repository: https://grafana.github.io/helm-charts - name: loki version: 6.40.0 repository: https://grafana.github.io/helm-charts +- name: k8s-monitoring + version: 3.5.1 + repository: https://grafana.github.io/helm-charts diff --git a/ops/monitoring/values-test.yaml b/ops/monitoring/values-test.yaml new file mode 100644 index 00000000..4bce1a76 --- /dev/null +++ b/ops/monitoring/values-test.yaml @@ -0,0 +1,3 @@ +k8s-monitoring: + cluster: + name: faforever-xyz \ No newline at end of file diff --git a/ops/monitoring/values.yaml b/ops/monitoring/values.yaml index 05ce39f8..edb1b096 100644 --- a/ops/monitoring/values.yaml +++ b/ops/monitoring/values.yaml @@ -145,7 +145,22 @@ loki: chunksCache: enabled: false -promtail: - config: - clients: - - url: http://monitoring-loki-gateway/loki/api/v1/push + +k8s-monitoring: + # Where Alloy pushes data to + # We can add our own Loki, Thanos... + destinations: + - name: local-loki + type: loki + url: http://monitoring-loki-gateway/loki/api/v1/push + + # We are using 1% of this chart, just logs for now, as it implements lots of things that vm-stack provides + # We could switch to this + vmsingle + + # Collectors + alloy-logs: + enabled: true + + # Features + podLogs: + enabled: true \ No newline at end of file From 1909f4b748f2dc57b740f6a4bd1dfaa4b02f8525 Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 17:33:38 +0200 Subject: [PATCH 11/22] Ignore charts --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c500ca99..208cde60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ certs spicy-secrets/** **/charts -.idea \ No newline at end of file +.idea + +# Ignore Chart.lock files +**/Chart.lock + +# Ignore Helm chart tarballs in any charts/ directory at any depth +**/charts/*.tgz \ No newline at end of file From ba14c9c00d2d5fdb6ea7f79e3d0867e50973e0a6 Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 17:43:54 +0200 Subject: [PATCH 12/22] Add a values for alloy prod --- ops/monitoring/values-prod.yaml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ops/monitoring/values-prod.yaml diff --git a/ops/monitoring/values-prod.yaml b/ops/monitoring/values-prod.yaml new file mode 100644 index 00000000..063295f5 --- /dev/null +++ b/ops/monitoring/values-prod.yaml @@ -0,0 +1,3 @@ +k8s-monitoring: + cluster: + name: faforever-com \ No newline at end of file From c3aabbd11e27f4df5ee9eb036f051fcc369bf148 Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 17:47:56 +0200 Subject: [PATCH 13/22] Fix duped yaml key --- ops/monitoring/values.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/ops/monitoring/values.yaml b/ops/monitoring/values.yaml index edb1b096..c94dbd5d 100644 --- a/ops/monitoring/values.yaml +++ b/ops/monitoring/values.yaml @@ -131,9 +131,6 @@ loki: limits_config: retention_period: 168h - limits_config: - retention_period: 168h - # We know it's working test: enabled: false From 8044c636a70d9a23cf33af61e760d6f47f97e875 Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 17:54:00 +0200 Subject: [PATCH 14/22] No affinity for loki gw --- ops/monitoring/values.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ops/monitoring/values.yaml b/ops/monitoring/values.yaml index c94dbd5d..f4d526d9 100644 --- a/ops/monitoring/values.yaml +++ b/ops/monitoring/values.yaml @@ -142,6 +142,9 @@ loki: chunksCache: enabled: false + gateway: + affinity: null + k8s-monitoring: # Where Alloy pushes data to From 5ebb8355b1deb1aa25d55af44108cd12ba34b1ff Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 18:06:10 +0200 Subject: [PATCH 15/22] No affinity for loki --- ops/monitoring/values.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ops/monitoring/values.yaml b/ops/monitoring/values.yaml index f4d526d9..82155036 100644 --- a/ops/monitoring/values.yaml +++ b/ops/monitoring/values.yaml @@ -142,6 +142,10 @@ loki: chunksCache: enabled: false + # Disable anti-affinity + singleBinary: + affinity: null + gateway: affinity: null From d69d8d8e564189f7d714360234a5a7a551a960bc Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 18:07:51 +0200 Subject: [PATCH 16/22] Fix yaml --- ops/monitoring/values.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ops/monitoring/values.yaml b/ops/monitoring/values.yaml index 82155036..1113c317 100644 --- a/ops/monitoring/values.yaml +++ b/ops/monitoring/values.yaml @@ -94,8 +94,6 @@ victoria-metrics-k8s-stack: loki: deploymentMode: SingleBinary - singleBinary: - replicas: 1 # Disable Simple Scalable read: @@ -144,6 +142,7 @@ loki: # Disable anti-affinity singleBinary: + replicas: 1 affinity: null gateway: From 59b241191ea5df32cf3a6b33b68c47253ee522ad Mon Sep 17 00:00:00 2001 From: Brutus5000 Date: Tue, 21 Oct 2025 22:29:43 +0200 Subject: [PATCH 17/22] Python server log level DEBUG --- apps/faf-lobby-server/config/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/faf-lobby-server/config/config.yaml b/apps/faf-lobby-server/config/config.yaml index 62b83932..77514dc2 100644 --- a/apps/faf-lobby-server/config/config.yaml +++ b/apps/faf-lobby-server/config/config.yaml @@ -1,5 +1,5 @@ CONFIGURATION_REFRESH_TIME: 60 -LOG_LEVEL: "INFO" +LOG_LEVEL: "DEBUG" LISTEN: - ADDRESS: From 42804511136cfb2daf3fa0b5fdd82cc0e0ba7c12 Mon Sep 17 00:00:00 2001 From: Brutus5000 Date: Wed, 12 Nov 2025 09:17:54 +0100 Subject: [PATCH 18/22] Deploy coop maps --- .../scripts/deploy-coop-maps.py | 381 ++++++++++++++++++ .../templates/deploy-coop-maps.yaml | 56 +++ 2 files changed, 437 insertions(+) create mode 100644 apps/faf-legacy-deployment/scripts/deploy-coop-maps.py create mode 100644 apps/faf-legacy-deployment/templates/deploy-coop-maps.yaml diff --git a/apps/faf-legacy-deployment/scripts/deploy-coop-maps.py b/apps/faf-legacy-deployment/scripts/deploy-coop-maps.py new file mode 100644 index 00000000..b28badef --- /dev/null +++ b/apps/faf-legacy-deployment/scripts/deploy-coop-maps.py @@ -0,0 +1,381 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +clone: https://github.com/FAForever/faf-coop-maps + +FAF coop maps updater + +All default settings are setup for FAF production! +Override the directory settings for local testing. +To get more help run + $ pipenv run patch-coop-maps -h + +Default usage: + $ pipenv run patch-coop-maps -s +""" +import argparse +import hashlib +import logging +import os +import shutil +import subprocess +import sys +import zipfile +from tempfile import TemporaryDirectory +from typing import NamedTuple, List + +import mysql.connector + +logger: logging.Logger = logging.getLogger() +logger.setLevel(logging.DEBUG) + +fixed_file_timestamp = 1078100502 # 2004-03-01T00:21:42Z + + +db_config = { + "host": os.getenv("DATABASE_HOST", "localhost"), + "user": os.getenv("DATABASE_USERNAME", "root"), + "password": os.getenv("DATABASE_PASSWORD", "banana"), + "database": os.getenv("DATABASE_NAME", "faf_lobby"), +} + + +def get_db_connection(): + """Create and return a MySQL connection.""" + try: + conn = mysql.connector.connect(**db_config) + if conn.is_connected(): + logger.debug(f"Connected to MySQL at {db_config['host']}") + return conn + except Error as e: + logger.error(f"MySQL connection failed: {e}") + sys.exit(1) + + +def run_sql(conn, sql: str) -> str: + """ + Run an SQL query directly on the MySQL database instead of via Docker. + Returns output in a string format similar to the old implementation. + """ + logger.debug(f"Executing SQL query:\n{sql}") + try: + with conn.cursor() as cursor: + cursor.execute(sql) + + # If it's a SELECT query, fetch and format results + if sql.strip().lower().startswith("select"): + rows = cursor.fetchall() + column_names = [desc[0] for desc in cursor.description] + # Simulate the Docker mysql CLI tabular text output + lines = ["\t".join(column_names)] + for row in rows: + lines.append("\t".join(str(x) for x in row)) + result = "\n".join(lines) + else: + conn.commit() + result = "Query OK" + + logger.debug(f"SQL result:\n{result}") + return result + + except Error as e: + logger.error(f"SQL execution failed: {e}") + sys.exit(1) + + +class CoopMap(NamedTuple): + folder_name: str + map_id: int + map_type: int + + def build_zip_filename(self, version: int) -> str: + return f"{self.folder_name.lower()}.v{version:04d}.zip" + + def build_folder_name(self, version: int) -> str: + return f"{self.folder_name.lower()}.v{version:04d}" + + +# Coop maps are in db table `coop_map` +coop_maps: List[CoopMap] = [ + # Forged Alliance missions + CoopMap("X1CA_Coop_001", 1, 0), + CoopMap("X1CA_Coop_002", 3, 0), + CoopMap("X1CA_Coop_003", 4, 0), + CoopMap("X1CA_Coop_004", 5, 0), + CoopMap("X1CA_Coop_005", 6, 0), + CoopMap("X1CA_Coop_006", 7, 0), + + # Vanilla Aeon missions + CoopMap("SCCA_Coop_A01", 8, 1), + CoopMap("SCCA_Coop_A02", 9, 1), + CoopMap("SCCA_Coop_A03", 10, 1), + CoopMap("SCCA_Coop_A04", 11, 1), + CoopMap("SCCA_Coop_A05", 12, 1), + CoopMap("SCCA_Coop_A06", 13, 1), + + # Vanilla Cybran missions + CoopMap("SCCA_Coop_R01", 20, 2), + CoopMap("SCCA_Coop_R02", 21, 2), + CoopMap("SCCA_Coop_R03", 22, 2), + CoopMap("SCCA_Coop_R04", 23, 2), + CoopMap("SCCA_Coop_R05", 24, 2), + CoopMap("SCCA_Coop_R06", 25, 2), + + # Vanilla UEF missions + CoopMap("SCCA_Coop_E01", 14, 3), + CoopMap("SCCA_Coop_E02", 15, 3), + CoopMap("SCCA_Coop_E03", 16, 3), + CoopMap("SCCA_Coop_E04", 17, 3), + CoopMap("SCCA_Coop_E05", 18, 3), + CoopMap("SCCA_Coop_E06", 19, 3), + + # Custom missions + CoopMap("FAF_Coop_Prothyon_16", 26, 4), + CoopMap("FAF_Coop_Fort_Clarke_Assault", 27, 4), + CoopMap("FAF_Coop_Theta_Civilian_Rescue", 28, 4), + CoopMap("FAF_Coop_Novax_Station_Assault", 31, 4), + CoopMap("FAF_Coop_Operation_Tha_Atha_Aez", 32, 4), + CoopMap("FAF_Coop_Havens_Invasion", 33, 4), + CoopMap("FAF_Coop_Operation_Rescue", 35, 4), + CoopMap("FAF_Coop_Operation_Uhthe_Thuum_QAI", 36, 4), + CoopMap("FAF_Coop_Operation_Yath_Aez", 37, 4), + CoopMap("FAF_Coop_Operation_Ioz_Shavoh_Kael", 38, 4), + CoopMap("FAF_Coop_Operation_Trident", 39, 4), + CoopMap("FAF_Coop_Operation_Blockade", 40, 4), + CoopMap("FAF_Coop_Operation_Golden_Crystals", 41, 4), + CoopMap("FAF_Coop_Operation_Holy_Raid", 42, 4), + CoopMap("FAF_Coop_Operation_Tight_Spot", 45, 4), + CoopMap("FAF_Coop_Operation_Overlord_Surth_Velsok", 47, 4), + CoopMap("FAF_Coop_Operation_Rebel's_Rest", 48, 4), + CoopMap("FAF_Coop_Operation_Red_Revenge", 49, 4), +] + +def fix_file_timestamps(files: List[str]) -> None: + for file in files: + logger.debug(f"Fixing timestamp in {file}") + os.utime(file, (fixed_file_timestamp, fixed_file_timestamp)) + + +def fix_folder_paths(folder_name: str, files: List[str], new_version: int) -> None: + old_maps_lua_path = f"/maps/{folder_name}/" + new_maps_lua_path = f"/maps/{folder_name.lower()}.v{new_version:04d}/" + + for file in files: + logger.debug(f"Fixing lua folder path in {file}: '{old_maps_lua_path}' -> '{new_maps_lua_path}'") + + with open(file, "rb") as file_handler: + data = file_handler.read() + data = data.replace(old_maps_lua_path.encode(), new_maps_lua_path.encode()) + + with open(file, "wb") as file_handler: + file_handler.seek(0) + file_handler.write(data) + + +def get_latest_map_version(coop_map: CoopMap) -> int: + logger.debug(f"Fetching latest map version for coop map {coop_map}") + + query = f""" + SELECT version FROM coop_map WHERE id = {coop_map.map_id}; + """ + result = run_sql(query).split("\n") + assert len(result) == 3, f"Mysql returned wrong result! Either map id {coop_map.map_id} is not in table coop_map" \ + f" or the where clause is wrong. Result: " + "\n".join(result) + return int(result[1]) + + +def new_file_is_different(old_file_name: str, new_file_name: str) -> bool: + old_file_md5 = calc_md5(old_file_name) + new_file_md5 = calc_md5(new_file_name) + + logger.debug(f"MD5 hash of {old_file_name} is: {old_file_md5}") + logger.debug(f"MD5 hash of {new_file_name} is: {new_file_md5}") + + return old_file_md5 != new_file_md5 + + +def update_database(coop_map: CoopMap, new_version: int) -> None: + logger.debug(f"Updating coop map {coop_map} in database to version {new_version}") + + query = f""" + UPDATE coop_map + SET version = {new_version}, filename = "maps/{coop_map.build_zip_filename(new_version)}" + WHERE id = {coop_map.map_id} + """ + run_sql(query) + + +def copytree(src, dst, symlinks=False, ignore=None): + """ + Reason for that method is because shutil.copytree will raise exception on existing + temporary directory + """ + + for item in os.listdir(src): + s = os.path.join(src, item) + d = os.path.join(dst, item) + if os.path.isdir(s): + shutil.copytree(s, d, symlinks, ignore) + else: + shutil.copy2(s, d) + + +def create_zip_package(coop_map: CoopMap, version: int, files: List[str], tmp_folder_path: str, zip_file_path: str): + fix_folder_paths(coop_map.folder_name, files, version) + fix_file_timestamps(files) + with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_BZIP2) as zip_file: + for path in files: + zip_file.write(path, arcname=f"/{coop_map.build_folder_name(version)}/{os.path.relpath(path, tmp_folder_path)}") + + +def process_coop_map(coop_map: CoopMap, simulate: bool, git_directory:str, coop_maps_path: str): + logger.info(f"Processing: {coop_map}") + + temp_dir = TemporaryDirectory() + copytree(os.path.join(git_directory, coop_map.folder_name), temp_dir.name) + processing_files = [] + for root, dirs, files in os.walk(temp_dir.name): + for f in files: + processing_files.append(os.path.relpath(os.path.join(root, f), temp_dir.name)) + + logger.debug(f"Files to process in {coop_map}: {processing_files}") + current_version = get_latest_map_version(coop_map) + current_file_path = os.path.join(coop_maps_path, coop_map.build_zip_filename(current_version)) + zip_file_path = os.path.join(temp_dir.name, coop_map.build_zip_filename(current_version)) + create_zip_package(coop_map, current_version, processing_files, temp_dir.name, zip_file_path) + if current_version == 0 or new_file_is_different(current_file_path, zip_file_path): + new_version = current_version + 1 + + if current_version == 0: + logger.info(f"{coop_map} first upload. New version: {new_version}") + else: + logger.info(f"{coop_map} has changed. New version: {new_version}") + + if not simulate: + temp_dir.cleanup() + temp_dir = TemporaryDirectory() + copytree(os.path.join(git_directory, coop_map.folder_name), temp_dir.name) + + zip_file_path = os.path.join(coop_maps_path, coop_map.build_zip_filename(new_version)) + create_zip_package(coop_map, new_version, processing_files, temp_dir.name, zip_file_path) + + update_database(coop_map, new_version) + else: + logger.info(f"Updating database skipped due to simulation") + else: + logger.info(f"{coop_map} remains unchanged") + temp_dir.cleanup() + + +def calc_md5(filename: str) -> str: + """ + Calculate the MD5 hash of a file + """ + hash_md5 = hashlib.md5() + with open(filename, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + + +def run_checked_shell(cmd: List[str]) -> subprocess.CompletedProcess: + """ + Runs a command as a shell process and checks for success + Output is captured in the result object + :param cmd: command to run + :return: CompletedProcess of the execution + """ + logger.debug("Run shell command: {cmd}".format(cmd=cmd)) + return subprocess.run(cmd, check=True, stdout=subprocess.PIPE) + + +def run_sql(sql: str, container: str = "faf-db", database: str = "faf_lobby") -> str: + + """ + Run a sql-query against the faf-db in the docker container + :param database: name of the database where to run the query + :param container: name of the docker container where to run the query + :param sql: the sql-query to run + :return: the query output as string + """ + try: + sql_text_result = run_checked_shell( + ["docker", "exec", "-u", "root", container, "mysql", database, "-e", sql] + ).stdout.decode() # type: str + logger.debug(f"SQL output >>> \n{sql_text_result}<<<") + return sql_text_result + except subprocess.CalledProcessError as e: + logger.error(f"""Executing sql query failed: {sql}\n\t\tError message: {str(e)}""") + exit(1) + + +def git_checkout(path: str, tag: str) -> None: + """ + Checkout a git tag of the git repository. This requires the repo to be checked out in the path folder! + + :param path: the path of the git repository to checkout + :param tag: version of the git tag (full name) + :return: nothing + """ + cwd = os.getcwd() + os.chdir(path) + logger.debug(f"Git checkout from path {path}") + + try: + run_checked_shell(["git", "fetch"]) + run_checked_shell(["git", "checkout", tag]) + except subprocess.CalledProcessError as e: + logger.error(f"git checkout failed - please check the error message: {e.stderr}") + exit(1) + finally: + os.chdir(cwd) + + +def create_zip(content: List[str], relative_to: str, output_file: str) -> None: + logger.debug(f"Zipping files to file `{output_file}`: {content}") + + with zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED) as zip_file: + for path in content: + if os.path.isdir(path): + cwd = os.getcwd() + os.chdir(path) + + for root, dirs, files in os.walk(path): + for next_file in files: + file_path = os.path.join(root, next_file) + zip_file.write(file_path, os.path.relpath(file_path, relative_to)) + + os.chdir(cwd) + else: + zip_file.write(path, os.path.relpath(path, relative_to)) + + +if __name__ == "__main__": + # Setting up logger + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setFormatter(logging.Formatter('%(levelname)-5s - %(message)s')) + logger.addHandler(stream_handler) + + # Setting up CLI arguments + parser = argparse.ArgumentParser(description=__doc__) + + parser.add_argument("version", help="the git tag name of the version") + parser.add_argument("-s", "--simulate", dest="simulate", action="store_true", default=False, + help="only runs a simulation without updating the database") + parser.add_argument("--git-directory", dest="git_directory", action="store", + default="/opt/featured-mods/faf-coop-maps", + help="base directory of the faf-coop-maps repository") + parser.add_argument("--maps-directory", dest="coop_maps_path", action="store", + default="/opt/faf/data/maps", + help="directory of the coop map files (content server)") + + args = parser.parse_args() + + git_checkout(args.git_directory, args.version) + + for coop_map in coop_maps: + try: + process_coop_map(coop_map, args.simulate, args.git_directory, args.coop_maps_path) + except Exception as error: + logger.warning(f"Unable to parse {coop_map}", exc_info=True) diff --git a/apps/faf-legacy-deployment/templates/deploy-coop-maps.yaml b/apps/faf-legacy-deployment/templates/deploy-coop-maps.yaml new file mode 100644 index 00000000..37ee5092 --- /dev/null +++ b/apps/faf-legacy-deployment/templates/deploy-coop-maps.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: faf-deploy-coop-maps + labels: + app: faf-deploy-coop-maps +data: + PATCH_VERSION: "65" + DATABASE_HOST: "mariadb" + DATABASE_NAME: "faf_lobby" + "deploy-coop.py": |- +{{ tpl ( .Files.Get "scripts/deploy-coop-maps.py" ) . | indent 4 }} + +--- + +kind: CronJob +apiVersion: batch/v1 +metadata: + name: faf-deploy-coop-maps + namespace: faf-apps + labels: + app: faf-deploy-coop-maps +spec: + # Disabled because triggered manually + schedule: "0 0 31 2 *" + suspend: true + concurrencyPolicy: Forbid + jobTemplate: + metadata: + labels: + app: faf-deploy-coop-maps + annotations: + prometheus.io/scrape: 'false' + spec: + template: + spec: + containers: + - image: python:3.13 + imagePullPolicy: Always + name: faf-coop-deployment + envFrom: + - configMapRef: + name: faf-deploy-coop-maps + - secretRef: + name: faf-legacy-deployment + command: [ "sh" ] + args: [ "-c", "pip install mysql-connector-python && python3 /tmp/deploy-coop.py" ] + volumeMounts: + - mountPath: /tmp/deploy-coop.py + name: faf-deploy-coop-maps + subPath: "deploy-coop.py" + restartPolicy: Never + volumes: + - name: faf-deploy-coop-maps + configMap: + name: "faf-deploy-coop-maps" From bac0ef31b9cc8863b2864c314d078207548f76f7 Mon Sep 17 00:00:00 2001 From: Pablo <42.pablo.ms@gmail.com> Date: Sun, 21 Sep 2025 17:33:20 +0200 Subject: [PATCH 19/22] Drop promtail --- ops/monitoring/Chart.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ops/monitoring/Chart.yaml b/ops/monitoring/Chart.yaml index a787d872..b48a5be9 100644 --- a/ops/monitoring/Chart.yaml +++ b/ops/monitoring/Chart.yaml @@ -11,3 +11,6 @@ dependencies: - name: k8s-monitoring version: 3.5.1 repository: https://grafana.github.io/helm-charts +- name: k8s-monitoring + version: 3.5.1 + repository: https://grafana.github.io/helm-charts From 2fe565649ee8c1b8d163bed1b1eeaf1fbcb4431d Mon Sep 17 00:00:00 2001 From: Brutus5000 Date: Sun, 23 Nov 2025 10:30:24 +0100 Subject: [PATCH 20/22] Enable Cloudflare --- apps/faf-icebreaker/templates/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/faf-icebreaker/templates/config.yaml b/apps/faf-icebreaker/templates/config.yaml index 08bbfc4a..8b485953 100644 --- a/apps/faf-icebreaker/templates/config.yaml +++ b/apps/faf-icebreaker/templates/config.yaml @@ -13,7 +13,7 @@ data: RABBITMQ_HOST: "rabbitmq" RABBITMQ_USER: "faf-icebreaker" RABBITMQ_PORT: "5672" - CLOUDFLARE_ENABLED: "false" + CLOUDFLARE_ENABLED: "true" XIRSYS_ENABLED: "true" XIRSYS_TURN_ENABLED: "true" GEOIPUPDATE_EDITION_IDS: "GeoLite2-City" From f8c70e524ccc3d99bf133c2e46e0da2cdc5a612b Mon Sep 17 00:00:00 2001 From: Brutus5000 Date: Sun, 30 Nov 2025 00:28:18 +0100 Subject: [PATCH 21/22] Specify HYDRA_JWKS_URI --- apps/faf-lobby-server/templates/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/faf-lobby-server/templates/config.yaml b/apps/faf-lobby-server/templates/config.yaml index 84d3b6c9..21735fb0 100644 --- a/apps/faf-lobby-server/templates/config.yaml +++ b/apps/faf-lobby-server/templates/config.yaml @@ -10,5 +10,6 @@ data: MQ_USER: "faf-lobby-server" DB_LOGIN: "faf-python-server" DB_NAME: "faf_lobby" + HYDRA_JWKS_URI: "https://hydra.{{ .Values.baseDomain }}/.well-known/jwks.json" "config.yaml": |- {{ tpl ( .Files.Get "config/config.yaml" ) . | indent 4 }} From 0d991dea5cb45acf2178565267b7df9eedc5b686 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 02:00:37 +0000 Subject: [PATCH 22/22] Update postgres Docker tag to v18 --- infra/postgres/templates/statefulset.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/postgres/templates/statefulset.yaml b/infra/postgres/templates/statefulset.yaml index 4eb55bbf..f28069c9 100644 --- a/infra/postgres/templates/statefulset.yaml +++ b/infra/postgres/templates/statefulset.yaml @@ -33,7 +33,7 @@ spec: restartPolicy: Always containers: - - image: postgres:17.6-bookworm + - image: postgres:18.1-bookworm imagePullPolicy: Always name: postgres ports: