From 4c675cd634ba03e9bb761b2489c4e0a03a9f2846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Sun, 26 Jul 2026 00:16:39 +0200 Subject: [PATCH] feat: add CentOS Stream support to deployment and maintenance scripts --- README.md | 14 +++++++------- server-setup.py | 11 ++++++----- system-optimise.py | 7 ++++--- vllm-deploy.py | 39 +++++++++++++++++++++++++-------------- zabbix-deploy.py | 14 +++++++++----- 5 files changed, 51 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index b1ddec8..3d19645 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ships with `--dry-run` where applicable. |---------|--------| | Language | Python 3.12+ | | Package manager | None — stdlib only | -| Target platforms | Fedora Server, openEuler; FreeBSD 13+ (`network-diag.py` only) | +| Target platforms | Fedora Server, CentOS Stream, openEuler; FreeBSD 13+ (`network-diag.py` only) | | Lint / format | Ruff (line length 100 — see `ruff.toml`) | | Licence | MIT | @@ -32,16 +32,16 @@ ships with `--dry-run` where applicable. | Script | Version | Purpose | |--------|---------|---------| -| `server-setup.py` | 1.2.0 | Server initial setup: packages, firewall (SSH verified before start), SELinux, Podman, automatic updates | +| `server-setup.py` | 1.3.0 | Server initial setup: packages, firewall (SSH verified before start), SELinux, Podman, automatic updates | | `workstation-setup.py` | 4.1.0 | Fedora desktop setup: Brave, dev tools (Bun, Zed, uv, Rust), Flatpak apps, SSH + Git | -| `vllm-deploy.py` | 1.1.0 | vLLM inference server behind nginx with HTTPS and API-key auth — installs ROCm on AMD GPUs | -| `zabbix-deploy.py` | 1.0.0 | Zabbix 7.4 monitoring stack: PostgreSQL 18, nginx with HTTPS on :443, PHP-FPM, SELinux | +| `vllm-deploy.py` | 1.2.0 | vLLM inference server behind nginx with HTTPS and API-key auth — installs ROCm on AMD GPUs | +| `zabbix-deploy.py` | 1.1.0 | Zabbix 7.4 monitoring stack: PostgreSQL 18, nginx with HTTPS on :443, PHP-FPM, SELinux | ### Maintenance | Script | Version | Purpose | |--------|---------|---------| -| `system-optimise.py` | 1.3.1 | System cleanup: old kernels (running + one fallback always kept), journals, temp files, core dumps, package audit. Refuses rpm-ostree systems | +| `system-optimise.py` | 1.4.0 | System cleanup: old kernels (running + one fallback always kept), journals, temp files, core dumps, package audit. Refuses rpm-ostree systems | --- @@ -107,8 +107,8 @@ flags to skip individual sections. it falls back to the legacy `ping6` binary where available. - `system-diag.py` is Linux-only (it reads `/proc` and `/sys`) and says so clearly on other platforms. -- The deployment and maintenance scripts target Fedora and openEuler - (dnf4 and dnf5 are both handled). +- The deployment and maintenance scripts target Fedora, CentOS Stream and + openEuler (dnf4 and dnf5 are both handled). --- diff --git a/server-setup.py b/server-setup.py index 4abf672..74b6045 100644 --- a/server-setup.py +++ b/server-setup.py @@ -2,7 +2,7 @@ # Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) # SPDX-License-Identifier: MIT -"""Idempotent server setup for Fedora Server and openEuler. +"""Idempotent server setup for Fedora Server, CentOS Stream and openEuler. No external dependencies — stdlib and system tools only. Every operation checks current state before acting; running the script repeatedly produces @@ -38,7 +38,7 @@ GREEN = "\033[32m" YELLOW = "\033[33m" DIM = "\033[2m" RESET = "\033[0m" -VERSION = "1.2.0" +VERSION = "1.3.0" # Timeout in seconds for dnf operations — metadata downloads and package # transactions on a fresh or slow system routinely exceed the 60 s default @@ -48,6 +48,7 @@ DNF_TIMEOUT = 1800 # Map os-release ID to display name — only these two are supported. SUPPORTED_OS: dict[str, str] = { "fedora": "Fedora", + "centos": "CentOS Stream", "openeuler": "openEuler", } @@ -850,9 +851,9 @@ def setup_auto_updates(os_id: str, dry_run: bool = False) -> dict[str, Any]: "failed": False, } - if os_id == "fedora": + if os_id in ("fedora", "centos"): # --- Install dnf-automatic (dnf4 name; provided virtually on dnf5) --- - _status("Checking dnf-automatic (Fedora)") + _status("Checking dnf-automatic (Fedora / CentOS Stream)") pkg_present = _rpm_installed("dnf-automatic") or _rpm_installed("dnf5-plugin-automatic") if not pkg_present: _status_done("not installed") @@ -1221,7 +1222,7 @@ def print_summary( def parse_args(argv: list[str] | None = None) -> argparse.Namespace: """Parse command-line arguments.""" parser = argparse.ArgumentParser( - description="Idempotent server setup for Fedora Server and openEuler", + description="Idempotent server setup for Fedora Server, CentOS Stream and openEuler", formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument( diff --git a/system-optimise.py b/system-optimise.py index 263feda..739bf96 100644 --- a/system-optimise.py +++ b/system-optimise.py @@ -2,7 +2,7 @@ # Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) # SPDX-License-Identifier: MIT -"""Idempotent system cleanup and optimisation for Fedora and openEuler. +"""Idempotent system cleanup and optimisation for Fedora, CentOS Stream and openEuler. Cleans old kernels, DNF caches, systemd journals, temp files, and core dumps. Every operation checks current state before acting; running the script @@ -37,10 +37,11 @@ GREEN = "\033[32m" YELLOW = "\033[33m" DIM = "\033[2m" RESET = "\033[0m" -VERSION = "1.3.1" +VERSION = "1.4.0" SUPPORTED_OS: dict[str, str] = { "fedora": "Fedora", + "centos": "CentOS Stream", "openeuler": "openEuler", } @@ -1112,7 +1113,7 @@ def print_summary( def parse_args(argv: list[str] | None = None) -> argparse.Namespace: """Parse command-line arguments.""" parser = argparse.ArgumentParser( - description="Idempotent system cleanup and optimisation for Fedora and openEuler", + description="Idempotent system cleanup and optimisation for Fedora, CentOS Stream and openEuler", formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument( diff --git a/vllm-deploy.py b/vllm-deploy.py index 6605454..489c6b8 100644 --- a/vllm-deploy.py +++ b/vllm-deploy.py @@ -4,13 +4,13 @@ """Idempotent vLLM deployment script for AMD ROCm GPUs. -Deploys vLLM behind nginx with self-signed TLS on Fedora or openEuler. +Deploys vLLM behind nginx with self-signed TLS on Fedora, CentOS Stream, or openEuler. vLLM binds to ::1 (IPv4 loopback fallback) on port 8000, internal only; nginx proxies :443 → the loopback upstream with streaming (SSE) support. The endpoint requires an API key, delivered to the service via a 0600 EnvironmentFile; nginx→vLLM proxying is allowed through SELinux on enforcing systems. Fedora gets ROCm from its native repositories; -openEuler falls back to AMD's amdgpu-install (unsupported by AMD). +CentOS Stream and openEuler fall back to AMD's amdgpu-install (unsupported by AMD). No external dependencies — stdlib and system tools only. Every operation checks current state before acting; running the script repeatedly produces @@ -46,10 +46,11 @@ GREEN = "\033[32m" YELLOW = "\033[33m" DIM = "\033[2m" RESET = "\033[0m" -VERSION = "1.1.0" +VERSION = "1.2.0" SUPPORTED_OS: dict[str, str] = { "fedora": "Fedora", + "centos": "CentOS Stream", "openeuler": "openEuler", } @@ -297,8 +298,17 @@ def _systemctl_is_enabled(service: str) -> bool: return result.returncode == 0 -def _map_to_el_major(version_id: str) -> str: - """Map an openEuler version to the closest RHEL major ("8"/"9") for AMDGPU repos.""" +def _map_to_el_major(os_id: str, version_id: str) -> str: + """Map an OS version to the closest RHEL major ("8"/"9") for AMDGPU repos. + + CentOS Stream VERSION_ID is already the RHEL major (e.g. "9", "10"); + openEuler uses its own numbering (≥24 → "9", otherwise "8"). + """ + if os_id.startswith("centos"): + try: + return str(int(version_id.split(".")[0])) + except (ValueError, IndexError): + return "9" try: major_ver = int(version_id.split(".")[0]) except (ValueError, IndexError): @@ -556,19 +566,20 @@ def _install_rocm_fedora(dry_run: bool) -> None: _status_done("ok") -def _install_rocm_openeuler(version_id: str, dry_run: bool) -> None: - """Install ROCm on openEuler via AMD's amdgpu-install script. +def _install_rocm_openeuler(os_id: str, version_id: str, dry_run: bool) -> None: + """Install ROCm on CentOS Stream / openEuler via AMD's amdgpu-install script. - AMD does not list openEuler as a supported ROCm platform — the RHEL - packages are installed strictly on a best-effort basis and may fail. - The RHEL point-release directory and RPM filename are resolved + AMD does not list CentOS Stream or openEuler as supported ROCm platforms — + the RHEL packages are installed strictly on a best-effort basis and may + fail. The RHEL point-release directory and RPM filename are resolved dynamically from the repository (nothing is hardcoded). """ _warn( - "AMD does not support ROCm on openEuler — amdgpu-install targets RHEL. " - "Continuing best-effort; this may fail or produce a broken install." + "AMD does not support ROCm on CentOS Stream / openEuler — " + "amdgpu-install targets RHEL. Continuing best-effort; this may fail " + "or produce a broken install." ) - el_major = _map_to_el_major(version_id) + el_major = _map_to_el_major(os_id, version_id) _status(f"Resolving latest amdgpu-install release for el{el_major}") listing = _fetch_text(f"{AMDGPU_INSTALL_URL}/") @@ -695,7 +706,7 @@ def preflight_checks(os_id: str, version_id: str, dry_run: bool = False) -> dict if os_id == "fedora": _install_rocm_fedora(dry_run) else: - _install_rocm_openeuler(version_id, dry_run) + _install_rocm_openeuler(os_id, version_id, dry_run) results["rocm"] = True # GPU verification via rocm-smi. diff --git a/zabbix-deploy.py b/zabbix-deploy.py index 0630a35..57400ba 100644 --- a/zabbix-deploy.py +++ b/zabbix-deploy.py @@ -4,8 +4,8 @@ """Idempotent Zabbix 7.4 deployment with PostgreSQL 18, nginx, PHP-FPM. -Deploys a full Zabbix monitoring stack with TLS-secured frontend on Fedora -or openEuler. Every operation checks current state before acting; running +Deploys a full Zabbix monitoring stack with TLS-secured frontend on Fedora, +CentOS Stream or openEuler. Every operation checks current state before acting; running the script repeatedly produces the same result with no errors and no duplicate work. @@ -45,10 +45,11 @@ GREEN = "\033[32m" YELLOW = "\033[33m" DIM = "\033[2m" RESET = "\033[0m" -VERSION = "1.0.0" +VERSION = "1.1.0" SUPPORTED_OS: dict[str, str] = { "fedora": "Fedora", + "centos": "CentOS Stream", "openeuler": "openEuler", } @@ -371,6 +372,9 @@ def _map_to_rhel_version(os_id: str, version_id: str) -> tuple[str, str]: openEuler 24+ -> el9 openEuler 22 -> el8 """ + if os_id == "centos": + return (version_id, version_id) + if os_id == "fedora": return ("9", "9") @@ -462,7 +466,7 @@ def setup_postgresql( """Install and configure PostgreSQL 18. Idempotent.""" results: dict[str, Any] = {} - # Map to EL version for repo URLs (used for openEuler; Fedora has native + # Map to EL version for repo URLs (used for non-Fedora; Fedora has native # PGDG reporpms). el_major, _ = _map_to_rhel_version(os_id, version_id) @@ -515,7 +519,7 @@ def setup_postgresql( _status_done("not present") else: _status("PostgreSQL module disable") - _status_done("skipped (openEuler)") + _status_done("skipped (non-Fedora)") # 2c. Install PostgreSQL 18 packages. pg_packages = ["postgresql18-server", "postgresql18"]