feat(post-install): rebuild Log2RAM with the journal and task logs kept on disk

This commit is contained in:
MacRimi
2026-10-27 19:48:26 +01:00
parent ac9b8c2705
commit 4cefc0484b
57 changed files with 992 additions and 1065 deletions
@@ -1,105 +0,0 @@
"""Log2RAM syncs only the archived journal files, so the active file it found
on disk when it was installed stays there and is restored at every boot.
journald then continues an old sequence and deletes its newest archives first.
The post-install makes the sync remove that file from the disk copy."""
from pathlib import Path
import re
import shutil
import stat
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[3]
SHARED = ROOT / "scripts/global/utils-install-functions.sh"
FLOWS = {"auto_post_install.sh": "install_log2ram_auto", "customizable_post_install.sh": "configure_log2ram"}
# The sync of Log2RAM in its journald-aware mode, as its project ships it.
JOURNALD_AWARE = '''#!/usr/bin/env bash
sync_to_disk() {
is_safe
local optional_params=()
if journald_logrotate; then
optional_params+=("--include=journal/*/*@*.journal")
optional_params+=("--exclude=journal/*/*")
fi
rsync -aXv --no-acls --delete-after "${optional_params[@]}" "${RAM_LOG}"/ "${HDD_LOG}"/
}
'''
NOT_AWARE = '''#!/usr/bin/env bash
sync_to_disk() {
rsync -aXv --delete-after "${RAM_LOG}"/ "${HDD_LOG}"/
}
'''
def gnu_sed():
return shutil.which("bash") and subprocess.run(["sed", "--version"], capture_output=True).returncode == 0
@unittest.skipUnless(gnu_sed(), "bash and GNU sed are needed")
class Log2ramJournalSyncTests(unittest.TestCase):
def correct(self, folder, content, times=1):
script = Path(folder) / "log2ram"
script.write_text(content)
script.chmod(0o755)
calls = "; ".join(['pmx_log2ram_drop_stale_journal "$1"; echo "rc=$?"'] * times)
# As the change journal does, the new content is read whole before it is written.
write = 'pmx_write_file() { local content; content="$(cat)"; printf "%s\\n" "$content" > "$1"; }'
run = subprocess.run(["bash", "-c", f'source "{SHARED}"; {write}; {calls}',
"bash", str(script)], capture_output=True, text=True, check=False)
return script, run.stdout.split()
def test_the_sync_removes_what_it_does_not_copy(self):
with tempfile.TemporaryDirectory() as folder:
script, results = self.correct(folder, JOURNALD_AWARE)
lines = script.read_text().splitlines()
position = lines.index(' optional_params+=("--exclude=journal/*/*")')
self.assertEqual(lines[position + 1], ' optional_params+=("--delete-excluded")')
self.assertEqual(lines[position + 2], " fi")
self.assertEqual(results, ["rc=0"])
self.assertEqual(subprocess.run(["bash", "-n", str(script)]).returncode, 0)
self.assertTrue(script.stat().st_mode & stat.S_IXUSR)
self.assertEqual(Path(str(script) + ".proxmenux.bak").read_text(), JOURNALD_AWARE)
def test_it_is_applied_once(self):
with tempfile.TemporaryDirectory() as folder:
script, results = self.correct(folder, JOURNALD_AWARE, times=2)
self.assertEqual(results, ["rc=0", "rc=1"])
self.assertEqual(script.read_text().count("--delete-excluded"), 1)
def test_a_sync_that_copies_every_file_is_left_as_it_is(self):
with tempfile.TemporaryDirectory() as folder:
script, results = self.correct(folder, NOT_AWARE)
self.assertEqual(results, ["rc=1"])
self.assertEqual(script.read_text(), NOT_AWARE)
self.assertFalse(Path(str(script) + ".proxmenux.bak").exists())
def test_both_flows_apply_it_to_new_and_existing_installations(self):
for name, function in FLOWS.items():
with self.subTest(flow=name):
text = (ROOT / "scripts/post_install" / name).read_text()
self.assertEqual(text.count("pmx_log2ram_drop_stale_journal"), 2)
# An existing installation is told that it needs a reboot.
self.assertIn('if pmx_log2ram_drop_stale_journal "$log2ram_bin"; then\n NECESSARY_REBOOT=1', text)
# The version is what offers the update to existing installations.
version = re.search(rf'{function}\(\) {{\n local FUNC_VERSION="([0-9.]+)"', text)
self.assertIsNotNone(version)
self.assertGreaterEqual(tuple(map(int, version.group(1).split("."))), (1, 7))
def test_rotated_logs_are_compressed_at_once_on_a_tmpfs_var_log(self):
# A rotated log kept uncompressed filled the 128M Log2RAM of a PBS.
for name, function in FLOWS.items():
with self.subTest(flow=name):
text = (ROOT / "scripts/post_install" / name).read_text()
self.assertNotIn("delaycompress", text)
version = re.search(rf'{function}\(\) {{\n local FUNC_VERSION="([0-9.]+)"', text)
self.assertGreaterEqual(tuple(map(int, version.group(1).split("."))), (1, 8))
if __name__ == "__main__":
unittest.main()
+125
View File
@@ -0,0 +1,125 @@
"""Log2RAM keeps /var/log in RAM while the journal and the task logs of
Proxmox VE and Proxmox Backup Server stay on disk behind a link. An update keeps the size
and interval the host already has."""
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[3]
KEEP = ROOT / "scripts/global/log2ram_keep_on_disk.sh"
SETUP = ROOT / "scripts/global/log2ram_setup.sh"
@unittest.skipUnless(shutil.which("bash"), "bash is needed")
class KeepOnDiskTests(unittest.TestCase):
def setUp(self):
folder = tempfile.TemporaryDirectory()
self.addCleanup(folder.cleanup)
self.root = Path(folder.name)
self.log = self.root / "var/log"
(self.log / "journal/abc").mkdir(parents=True)
(self.log / "journal/abc/system.journal").write_text("entries")
(self.log / "pveproxy").mkdir()
(self.log / "pveproxy/access.log").write_text("GET /")
def run_script(self, revert=False):
env = dict(os.environ, PMX_L2R_ROOT=str(self.root), PMX_L2R_REVERT="1" if revert else "0")
return subprocess.run(["bash", str(KEEP)], env=env, capture_output=True, text=True)
def test_the_journal_moves_to_disk_behind_a_link(self):
self.assertEqual(self.run_script().returncode, 0)
journal = self.log / "journal"
self.assertTrue(journal.is_symlink())
self.assertEqual(os.readlink(journal), "/var/hdd.journal")
self.assertEqual((self.root / "var/hdd.journal/abc/system.journal").read_text(), "entries")
self.assertTrue((self.log / "pveproxy/access.log").exists())
self.assertFalse((self.root / "var/hdd.proxmox-backup").exists())
def test_running_again_changes_nothing(self):
self.run_script()
self.assertEqual(self.run_script().returncode, 0)
self.assertEqual(os.readlink(self.log / "journal"), "/var/hdd.journal")
self.assertEqual(sorted(p.name for p in (self.root / "var/hdd.journal").iterdir()), ["abc"])
def test_the_task_logs_of_backup_server_stay_on_disk_too(self):
(self.log / "proxmox-backup/tasks").mkdir(parents=True)
(self.log / "proxmox-backup/tasks/active").write_text("task")
self.run_script()
self.assertEqual(os.readlink(self.log / "proxmox-backup"), "/var/hdd.proxmox-backup")
self.assertEqual((self.root / "var/hdd.proxmox-backup/tasks/active").read_text(), "task")
def test_files_written_back_to_the_folder_join_the_copy_on_disk(self):
self.run_script()
(self.log / "journal").unlink()
(self.log / "journal/def").mkdir(parents=True)
(self.log / "journal/def/system.journal").write_text("later")
self.run_script()
disk = self.root / "var/hdd.journal"
self.assertEqual(sorted(p.name for p in disk.iterdir()), ["abc", "def"])
self.assertTrue((self.log / "journal").is_symlink())
def test_a_host_without_a_journal_folder_gets_one_on_disk(self):
shutil.rmtree(self.log / "journal")
self.run_script()
self.assertTrue((self.root / "var/hdd.journal").is_dir())
self.assertTrue((self.log / "journal").is_symlink())
def test_the_task_logs_of_proxmox_ve_stay_on_disk(self):
(self.log / "pve/tasks").mkdir(parents=True)
(self.log / "pve/tasks/index").write_text("UPID")
self.run_script()
self.assertEqual(os.readlink(self.log / "pve"), "/var/hdd.pve")
self.assertEqual((self.root / "var/hdd.pve/tasks/index").read_text(), "UPID")
def test_removing_log2ram_puts_the_folders_back(self):
(self.log / "proxmox-backup").mkdir()
self.run_script()
self.assertEqual(self.run_script(revert=True).returncode, 0)
for name in ("journal", "proxmox-backup"):
self.assertFalse((self.log / name).is_symlink(), name)
self.assertTrue((self.log / name).is_dir(), name)
self.assertFalse((self.root / f"var/hdd.{name}").exists(), name)
self.assertEqual((self.log / "journal/abc/system.journal").read_text(), "entries")
@unittest.skipUnless(shutil.which("bash"), "bash is needed")
class KeptSettingsTests(unittest.TestCase):
def read(self, function, files):
with tempfile.TemporaryDirectory() as folder:
script = SETUP.read_text()
for path, content in files.items():
target = Path(folder) / path.lstrip("/")
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(content)
script = script.replace(path, str(target))
library = Path(folder) / "setup.sh"
library.write_text(script)
result = subprocess.run(["bash", "-c", f'source "{library}"; {function}'],
capture_output=True, text=True)
return result.stdout.strip()
def test_the_size_comes_from_the_installed_configuration(self):
self.assertEqual(self.read("pmx_log2ram_current_size", {"/etc/log2ram.conf": "SIZE=256M\n"}), "256")
def test_the_interval_comes_from_the_timer_of_this_version(self):
timer = "[Timer]\nOnCalendar=\nOnCalendar=*-*-* 00/6:55:00\n"
self.assertEqual(self.read("pmx_log2ram_current_hours",
{"/etc/systemd/system/log2ram-daily.timer.d/proxmenux.conf": timer}), "6")
def test_the_interval_of_an_earlier_version_is_kept(self):
cron = "MAILTO=\"\"\n0 */3 * * * root /usr/local/bin/log2ram write >/dev/null 2>&1\n"
self.assertEqual(self.read("pmx_log2ram_current_hours", {"/etc/cron.d/log2ram": cron}), "3")
def test_the_release_is_pinned_to_a_verified_commit(self):
text = SETUP.read_text()
self.assertIn('PMX_L2R_TAG="1.7.2"', text)
self.assertIn('PMX_L2R_COMMIT="f171449530f8984374c8f69fff3c92af813a694b"', text)
self.assertNotIn("install.sh", text.split("_pmx_log2ram_install_release() {", 1)[1].split("\n}\n", 1)[0])
if __name__ == "__main__":
unittest.main()
+19 -6
View File
@@ -874,7 +874,7 @@ export function NotificationSettings() {
// Flatten per-provider API keys
if (cfg.ai_api_keys) {
for (const [provider, key] of Object.entries(cfg.ai_api_keys)) {
if (key) {
if (key || provider === "ollama") {
flat[`ai_api_key_${provider}`] = key
}
}
@@ -2305,6 +2305,12 @@ export function NotificationSettings() {
// Restore previously saved model for the new provider (if any)
const savedModel = config.ai_models?.[v] || ''
setShowSecrets(p => ({ ...p, ai_key: false }))
setRevealedSecrets(p => {
const next = { ...p }
delete next.ai_key
return next
})
updateConfig(p => ({
...p,
@@ -2364,11 +2370,13 @@ export function NotificationSettings() {
</div>
)}
{/* API Key (not shown for Ollama) */}
{config.ai_provider !== "ollama" && (
{/* Ollama gateways may require a key; native servers do not. */}
<div className="space-y-2">
<div className="flex items-center gap-2">
<Label className="text-xs sm:text-sm text-foreground/80">{t("settings.notifications.ai.apiKey")}</Label>
<Label htmlFor="notification-ai-api-key" className="text-xs sm:text-sm text-foreground/80">{t("settings.notifications.ai.apiKey")}</Label>
{config.ai_provider === "ollama" && (
<span className="text-xs text-muted-foreground">({t("settings.notifications.ui.optional")})</span>
)}
{AI_PROVIDERS.find(p => p.value === config.ai_provider)?.keyUrl && (
<a
href={AI_PROVIDERS.find(p => p.value === config.ai_provider)?.keyUrl}
@@ -2382,9 +2390,10 @@ export function NotificationSettings() {
</div>
<div className="flex items-center gap-2">
<Input
id="notification-ai-api-key"
type={showSecrets["ai_key"] ? "text" : "password"}
className="h-9 text-sm font-mono"
placeholder="sk-..."
placeholder={config.ai_provider === "ollama" ? "" : "sk-..."}
value={secretValue("ai_key", config.ai_api_keys?.[config.ai_provider] || "")}
onChange={e => updateConfig(p => ({
...p,
@@ -2402,8 +2411,12 @@ export function NotificationSettings() {
{showSecrets["ai_key"] ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
</div>
{config.ai_provider === "ollama" && (
<p className="text-xs text-muted-foreground">
{t("settings.notifications.ai.ollamaApiKeyHint")}
</p>
)}
</div>
)}
{/* Model - selector with Load button for all providers */}
<div className="space-y-2">
+1
View File
@@ -2312,6 +2312,7 @@
"testing": "Testen…",
"testConnection": "Testverbindung",
"ollamaUrl": "Ollama-URL",
"ollamaApiKeyHint": "Bei einem normalen Ollama-Server leer lassen. Wenn dein Proxy oder Gateway einen Schlüssel verlangt, wird er als Authorization: Bearer gesendet. Dieses Feld aktiviert keine Authentifizierung auf dem Server.",
"getKey": "Holen Sie sich den Schlüssel",
"loadModelsPlaceholder": "Klicken Sie auf „Laden“, um Modelle abzurufen",
"selectModel": "Modell auswählen",
+1
View File
@@ -2439,6 +2439,7 @@
"testing": "Testing…",
"testConnection": "Test connection",
"ollamaUrl": "Ollama URL",
"ollamaApiKeyHint": "Leave empty for a standard Ollama server. If your proxy or gateway requires a key, it is sent as Authorization: Bearer. This field does not enable authentication on the server.",
"getKey": "Get key",
"loadModelsPlaceholder": "Click Load to fetch models",
"selectModel": "Select model",
+1
View File
@@ -2465,6 +2465,7 @@
"testing": "Pruebas…",
"testConnection": "Conexión de prueba",
"ollamaUrl": "URL de Ollama",
"ollamaApiKeyHint": "Déjala vacía para un servidor Ollama estándar. Si tu proxy o pasarela requiere una clave, se envía como Authorization: Bearer. Este campo no activa la autenticación en el servidor.",
"getKey": "Obtener clave",
"loadModelsPlaceholder": "Haz clic en Cargar para buscar modelos",
"selectModel": "Seleccionar modelo",
+1
View File
@@ -2312,6 +2312,7 @@
"testing": "Essai…",
"testConnection": "Tester la connexion",
"ollamaUrl": "URL d'Ollama",
"ollamaApiKeyHint": "Laissez ce champ vide pour un serveur Ollama standard. Si votre proxy ou passerelle exige une clé, elle est envoyée dans Authorization: Bearer. Ce champ n'active pas l'authentification sur le serveur.",
"getKey": "Obtenir la clé",
"loadModelsPlaceholder": "Cliquez sur Charger pour récupérer les modèles",
"selectModel": "Sélectionnez le modèle",
+1
View File
@@ -2312,6 +2312,7 @@
"testing": "Test in corso…",
"testConnection": "Prova connessione",
"ollamaUrl": "URL Ollama",
"ollamaApiKeyHint": "Lascia vuoto per un server Ollama standard. Se il proxy o gateway richiede una chiave, viene inviata come Authorization: Bearer. Questo campo non abilita l'autenticazione sul server.",
"getKey": "Ottieni chiave",
"loadModelsPlaceholder": "Fai clic su Carica per recuperare i modelli",
"selectModel": "Seleziona modello",
+1
View File
@@ -2312,6 +2312,7 @@
"testing": "Testando…",
"testConnection": "Conexão de teste",
"ollamaUrl": "URL de Ollama",
"ollamaApiKeyHint": "Deixa vazio para um servidor Ollama padrão. Se o proxy ou gateway exigir uma chave, esta é enviada como Authorization: Bearer. Este campo não ativa a autenticação no servidor.",
"getKey": "Obter chave",
"loadModelsPlaceholder": "Clique em Carregar para buscar modelos",
"selectModel": "Selecione o modelo",
+1
View File
@@ -2311,6 +2311,7 @@
"testing": "Testujem…",
"testConnection": "Otestovať pripojenie",
"ollamaUrl": "URL služby Ollama",
"ollamaApiKeyHint": "Pre bežný server Ollama nechajte prázdne. Ak proxy alebo brána vyžaduje kľúč, odosiela sa ako Authorization: Bearer. Toto pole nezapína autentifikáciu na serveri.",
"getKey": "Získať kľúč",
"loadModelsPlaceholder": "Kliknutím na Načítať získate modely",
"selectModel": "Vyberte model",
+1
View File
@@ -2312,6 +2312,7 @@
"testing": "Testning…",
"testConnection": "Testa anslutningen",
"ollamaUrl": "Ollama URL",
"ollamaApiKeyHint": "Lämna tomt för en vanlig Ollama-server. Om din proxy eller gateway kräver en nyckel skickas den som Authorization: Bearer. Fältet aktiverar inte autentisering på servern.",
"getKey": "Få nyckel",
"loadModelsPlaceholder": "Klicka på Ladda för att hämta modeller",
"selectModel": "Välj modell",
@@ -7,6 +7,16 @@ from typing import Optional
from .base import AIProvider, AIProviderError
def ollama_headers(api_key: str = "") -> dict:
"""Authenticate protected Ollama gateways without requiring a key locally."""
if not isinstance(api_key, str) or len(api_key) > 512 or '\r' in api_key or '\n' in api_key:
raise AIProviderError("Invalid Ollama API key")
headers = {'Content-Type': 'application/json'}
if api_key.strip():
headers['Authorization'] = f'Bearer {api_key.strip()}'
return headers
class OllamaProvider(AIProvider):
"""Ollama provider for local AI execution."""
@@ -18,7 +28,7 @@ class OllamaProvider(AIProvider):
"""Initialize Ollama provider.
Args:
api_key: Not used for Ollama (local execution)
api_key: Optional Bearer token for an authenticated Ollama gateway
model: Model name (user must select from loaded models)
base_url: Ollama server URL (default: http://localhost:11434)
"""
@@ -57,9 +67,7 @@ class OllamaProvider(AIProvider):
}
}
headers = {
'Content-Type': 'application/json',
}
headers = ollama_headers(self.api_key)
# Cloud models (e.g., kimi-k2.5:cloud, minimax-m2.7:cloud) need longer timeout
# because requests go through: ProxMenux -> Ollama -> Cloud Provider -> back
@@ -96,7 +104,8 @@ class OllamaProvider(AIProvider):
# First check if server is running
try:
url = f"{self.base_url.rstrip('/')}/api/tags"
req = urllib.request.Request(url, method='GET', headers={'User-Agent': 'ProxMenux/1.0'})
headers = {'User-Agent': 'ProxMenux/1.0', **ollama_headers(self.api_key)}
req = urllib.request.Request(url, method='GET', headers=headers)
with urllib.request.urlopen(req, timeout=5) as resp:
data = json.loads(resp.read().decode('utf-8'))
@@ -122,6 +131,13 @@ class OllamaProvider(AIProvider):
'message': f"Model '{self.model}' not found. Available: {', '.join(display_models)}{'...' if len(full_model_names) > 5 else ''}",
'model': self.model
}
except urllib.error.HTTPError as error:
message = (
f"HTTP {error.code}: Ollama authentication failed. Check the optional API key."
if error.code in (401, 403)
else f"HTTP {error.code}: Ollama request failed"
)
return {'success': False, 'message': message, 'model': self.model}
except urllib.error.URLError:
return {
'success': False,
@@ -446,7 +446,7 @@ def get_provider_models():
Request body:
{
"provider": "gemini|groq|openai|openrouter|ollama|anthropic",
"api_key": "your-api-key", // Not needed for ollama
"api_key": "your-api-key", // Optional for protected Ollama gateways
"ollama_url": "http://localhost:11434", // Only for ollama
"openai_base_url": "https://custom.endpoint/v1" // Optional for openai
}
@@ -498,9 +498,10 @@ def get_provider_models():
if provider == 'ollama':
import urllib.request
import urllib.error
from ai_providers.ollama_provider import ollama_headers
url = f"{ollama_url.rstrip('/')}/api/tags"
req = urllib.request.Request(url, method='GET')
req = urllib.request.Request(url, method='GET', headers=ollama_headers(api_key))
req.add_header('User-Agent', 'ProxMenux-Monitor/1.1')
with urllib.request.urlopen(req, timeout=10) as resp:
+3 -1
View File
@@ -86,6 +86,7 @@ SENSITIVE_KEYS = {
'ai_api_key_anthropic',
'ai_api_key_openai',
'ai_api_key_openrouter',
'ai_api_key_ollama',
# `telegram.bot_token` — was previously listed as `telegram.token`,
# which never matched the real config_key (`bot_token` in
# CHANNEL_TYPES). The mismatch silently sent Telegram bot tokens
@@ -3019,6 +3020,7 @@ class NotificationManager:
current_provider = self._config.get('ai_provider', 'groq')
_raw_keys = {
'groq': self._config.get('ai_api_key_groq', ''),
'ollama': self._config.get('ai_api_key_ollama', ''),
'gemini': self._config.get('ai_api_key_gemini', ''),
'anthropic': self._config.get('ai_api_key_anthropic', ''),
'openai': self._config.get('ai_api_key_openai', ''),
@@ -3026,7 +3028,7 @@ class NotificationManager:
}
ai_api_keys = {
'groq': _mask_if_set(_raw_keys['groq']),
'ollama': '', # Ollama doesn't need API key
'ollama': _mask_if_set(_raw_keys['ollama']),
'gemini': _mask_if_set(_raw_keys['gemini']),
'anthropic': _mask_if_set(_raw_keys['anthropic']),
'openai': _mask_if_set(_raw_keys['openai']),
+189
View File
@@ -0,0 +1,189 @@
"""Optional Ollama gateway authentication, with no real keys or network calls."""
import ast
import io
import json
from pathlib import Path
import sqlite3
import sys
import tempfile
from types import SimpleNamespace
import unittest
from unittest import mock
import urllib.error
SCRIPTS = Path(__file__).resolve().parents[1]
if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
from ai_providers.ollama_provider import OllamaProvider, ollama_headers
from ai_providers.base import AIProviderError
import notification_manager as manager_module
TOKEN = "test-only-ollama-token"
MODEL = "test-model:latest"
def routes(manager, payload):
"""Use the actual handlers without importing Flask or starting a server."""
source = SCRIPTS / "flask_notification_routes.py"
names = {"_resolve_masked_api_key", "get_provider_models",
"test_ai_connection", "reveal_notification_secret"}
functions = []
for node in ast.parse(source.read_text()).body:
if isinstance(node, ast.FunctionDef) and node.name in names:
node.decorator_list = []
functions.append(node)
scope = {
"__file__": str(source), "json": json,
"request": SimpleNamespace(get_json=lambda **kwargs: payload),
"jsonify": lambda value: value,
"notification_manager": manager,
"SENSITIVE_PLACEHOLDER": manager_module.SENSITIVE_PLACEHOLDER,
"validate_external_url": manager_module.validate_external_url,
"load_verified_models": lambda: {},
}
module = ast.fix_missing_locations(ast.Module(body=functions, type_ignores=[]))
exec(compile(module, str(source), "exec"), scope)
return scope
class OllamaAuthenticationTests(unittest.TestCase):
def setUp(self):
self.requests = []
self.required_token = TOKEN
patcher = mock.patch("urllib.request.urlopen", side_effect=self.respond)
patcher.start()
self.addCleanup(patcher.stop)
def respond(self, request, timeout=None):
self.requests.append(request)
if self.required_token and request.get_header("Authorization") != "Bearer " + self.required_token:
raise urllib.error.HTTPError(request.full_url, 401, "Unauthorized", {},
io.BytesIO(b"sensitive response body"))
if request.full_url.endswith("/api/tags"):
data = {"models": [{"name": MODEL}]}
elif request.full_url.endswith("/api/chat"):
data = {"message": {"content": "CONNECTION_OK"}}
else:
raise AssertionError("Unexpected endpoint: " + request.full_url)
return io.BytesIO(json.dumps(data).encode())
def test_key_is_optional_and_no_authorization_header_is_sent_when_empty(self):
self.required_token = ""
for key in ("", " "):
provider = OllamaProvider(api_key=key, model=MODEL)
self.assertTrue(provider.test_connection()["success"])
self.assertTrue(self.requests)
self.assertTrue(all(r.get_header("Authorization") is None for r in self.requests))
self.assertFalse(OllamaProvider.REQUIRES_API_KEY)
def test_connection_authenticates_both_model_lookup_and_generation(self):
result = OllamaProvider(api_key=TOKEN, model=MODEL).test_connection()
self.assertTrue(result["success"], result)
self.assertEqual([r.get_method() for r in self.requests], ["GET", "POST"])
self.assertTrue(all(r.get_header("Authorization") == "Bearer " + TOKEN for r in self.requests))
def test_authentication_failure_is_not_reported_as_an_unreachable_server(self):
result = OllamaProvider(api_key="wrong-test-token", model=MODEL).test_connection()
self.assertFalse(result["success"])
self.assertIn("HTTP 401", result["message"])
self.assertNotIn("Cannot connect", result["message"])
self.assertNotIn("wrong-test-token", json.dumps(result))
self.assertNotIn("sensitive response", json.dumps(result))
def test_invalid_header_values_are_rejected_without_echoing_them(self):
for value in ("test-secret\r\nInjected: header", "x" * 513, None):
with self.subTest(value_type=type(value).__name__):
with self.assertRaisesRegex(AIProviderError, "^Invalid Ollama API key$"):
ollama_headers(value)
self.assertEqual(self.requests, [])
def test_model_loading_uses_the_saved_key_when_the_browser_sends_a_mask(self):
manager = SimpleNamespace(_config={"ai_api_key_ollama": TOKEN})
handlers = routes(manager, {"provider": "ollama", "api_key": manager_module.SENSITIVE_PLACEHOLDER,
"ollama_url": "http://localhost:11434"})
result = handlers["get_provider_models"]()
self.assertTrue(result["success"], result)
self.assertEqual(result["models"], [MODEL])
self.assertEqual(self.requests[0].get_header("Authorization"), "Bearer " + TOKEN)
self.assertNotIn(TOKEN, json.dumps(result))
def test_model_loading_without_a_key_still_works_for_native_ollama(self):
self.required_token = ""
handlers = routes(SimpleNamespace(_config={}), {
"provider": "ollama", "ollama_url": "http://localhost:11434"})
result = handlers["get_provider_models"]()
self.assertTrue(result["success"], result)
self.assertIsNone(self.requests[0].get_header("Authorization"))
def test_test_ai_route_reuses_the_saved_key(self):
handlers = routes(SimpleNamespace(_config={"ai_api_key_ollama": TOKEN}), {
"provider": "ollama", "model": MODEL,
"api_key": manager_module.SENSITIVE_PLACEHOLDER,
"ollama_url": "http://localhost:11434"})
result = handlers["test_ai_connection"]()
self.assertTrue(result["success"], result)
self.assertTrue(all(r.get_header("Authorization") == "Bearer " + TOKEN for r in self.requests))
def test_reveal_endpoint_recognizes_the_ollama_secret(self):
handlers = routes(SimpleNamespace(_config={"ai_api_key_ollama": TOKEN}), {"ai_provider": "ollama"})
self.assertEqual(handlers["reveal_notification_secret"](), ({"value": TOKEN}, 200))
def test_real_notification_provider_receives_the_ollama_key(self):
manager = manager_module.NotificationManager()
manager._config = {"ai_enabled": "true", "ai_provider": "ollama",
"ai_api_key_ollama": TOKEN, "ai_model_ollama": MODEL,
"ai_ollama_url": "http://localhost:11434"}
from notification_templates import AIEnhancer
rewriter = AIEnhancer(manager._build_ai_config())
self.assertIsInstance(rewriter._provider, OllamaProvider)
self.assertEqual(rewriter._provider.generate("system", "user"), "CONNECTION_OK")
self.assertEqual(self.requests[0].get_header("Authorization"), "Bearer " + TOKEN)
class OllamaKeyStorageTests(unittest.TestCase):
def setUp(self):
directory = tempfile.TemporaryDirectory()
self.addCleanup(directory.cleanup)
self.db = Path(directory.name) / "settings.db"
with sqlite3.connect(str(self.db)) as conn:
conn.execute("CREATE TABLE user_settings (setting_key TEXT PRIMARY KEY, setting_value TEXT, updated_at TEXT)")
for name, value in (("DB_PATH", self.db), ("ENCRYPTION_KEY_FILE", Path(directory.name) / "key")):
patcher = mock.patch.object(manager_module, name, value)
patcher.start()
self.addCleanup(patcher.stop)
self.manager = manager_module.NotificationManager()
self.manager._rebuild_channels = mock.Mock()
def stored_value(self):
with sqlite3.connect(str(self.db)) as conn:
return conn.execute("SELECT setting_value FROM user_settings WHERE setting_key = ?",
("notification.ai_api_key_ollama",)).fetchone()[0]
def test_key_is_encrypted_masked_and_loaded_for_runtime_use(self):
result = self.manager.save_settings({"ai_provider": "ollama", "ai_api_key_ollama": TOKEN})
self.assertTrue(result["success"], result)
stored = self.stored_value()
self.assertTrue(stored.startswith("ENC2:"))
self.assertNotIn(TOKEN, stored)
self.assertEqual(manager_module.decrypt_sensitive_value(stored), TOKEN)
self.assertEqual(self.manager.get_settings()["config"]["ai_api_keys"]["ollama"],
manager_module.SENSITIVE_PLACEHOLDER)
fresh = manager_module.NotificationManager()
fresh._load_config()
self.assertEqual(fresh._build_ai_config()["ai_api_key"], TOKEN)
def test_masked_round_trip_keeps_the_key_and_an_empty_value_removes_it(self):
self.assertTrue(self.manager.save_settings({"ai_api_key_ollama": TOKEN})["success"])
stored = self.stored_value()
self.assertTrue(self.manager.save_settings({"ai_api_key_ollama": manager_module.SENSITIVE_PLACEHOLDER})["success"])
self.assertEqual(self.stored_value(), stored)
self.assertTrue(self.manager.save_settings({"ai_api_key_ollama": ""})["success"])
self.assertEqual(self.stored_value(), "")
self.assertEqual(self.manager.get_settings()["config"]["ai_api_keys"]["ollama"], "")
if __name__ == "__main__":
unittest.main()
+8
View File
@@ -3404,6 +3404,7 @@
"Installing Fail2Ban...": "Fail2Ban wird installiert...",
"Installing Git as a prerequisite...": "Git als Voraussetzung installieren...",
"Installing Intel VA-API drivers in container...": "Intel VA-API-Treiber werden im Container installiert...",
"Installing Log2RAM": "Log2RAM wird installiert",
"Installing Log2RAM from GitHub...": "Log2RAM von GitHub installieren...",
"Installing Log2RAM from source...": "Log2RAM von der Quelle installieren...",
"Installing NFS Client in LXC": "NFS-Client in LXC installieren",
@@ -3894,10 +3895,14 @@
"Log aggregation server for Grafana.": "Protokollaggregationsserver für Grafana.",
"Log file": "Protokolldatei",
"Log2RAM already registered — updating to latest configuration": "Log2RAM bereits registriert – Aktualisierung auf die neueste Konfiguration",
"Log2RAM could not be downloaded": "Log2RAM konnte nicht heruntergeladen werden",
"Log2RAM installation and configuration completed successfully.": "Die Installation und Konfiguration von Log2RAM wurde erfolgreich abgeschlossen.",
"Log2RAM installation cancelled by user": "Die Log2RAM-Installation wurde vom Benutzer abgebrochen",
"Log2RAM installation verification failed. Check /tmp/log2ram_install.log": "Die Überprüfung der Log2RAM-Installation ist fehlgeschlagen. Überprüfen Sie /tmp/log2ram_install.log",
"Log2RAM installed successfully": "Log2RAM erfolgreich installiert",
"Log2RAM installed:": "Log2RAM installiert:",
"Log2RAM is removed at the next reboot, after writing /var/log to disk": "Log2RAM wird beim nächsten Neustart entfernt, nachdem /var/log auf die Festplatte geschrieben wurde",
"Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot": "Log2RAM hält /var/log im RAM; das Journal bleibt ab dem nächsten Start auf der Festplatte",
"Log2RAM keeps the journal in order from the next reboot": "Log2RAM hält das Journal ab dem nächsten Neustart in Ordnung",
"Log2RAM size set to:": "Log2RAM-Größe eingestellt auf:",
"Log2RAM write scheduled every": "Log2RAM-Schreibvorgang alle geplant",
@@ -5789,6 +5794,7 @@
"Root shell/profile config": "Root-Shell-/Profilkonfiguration",
"Root user on the PVE host (default 'root'):": "Root-Benutzer auf dem PVE-Host (Standard „root“):",
"Rootfs size in GB": "Rootfs Größe in GB",
"Rotate and write /var/log to disk when it passes 85% of its size?": "/var/log rotieren und auf die Festplatte schreiben, wenn es 85 % seiner Größe überschreitet?",
"Rotate the recovery passphrase": "Drehen Sie die Wiederherstellungspassphrase",
"Routing Information": "Routing-Informationen",
"Routing Table": "Routing-Tabelle",
@@ -6966,6 +6972,7 @@
"The domain must resolve to the public address of this network before the certificate can be issued.": "Die Domain muss sich auf die öffentliche Adresse dieses Netzwerks auflösen, bevor das Zertifikat ausgestellt werden kann.",
"The download client still needs to be configured.": "Der Download-Client muss noch konfiguriert werden.",
"The download stopped progressing; cancelling this attempt.": "Der Download hat aufgehört voranzukommen; diesen Versuch abzubrechen.",
"The downloaded Log2RAM does not match the expected release": "Das heruntergeladene Log2RAM entspricht nicht der erwarteten Version",
"The downloaded image does not match its manifest": "Das heruntergeladene Bild stimmt nicht mit seinem Manifest überein",
"The downloaded image is corrupt:": "Das heruntergeladene Bild ist beschädigt:",
"The dpkg package database is clean.": "Die dpkg-Paketdatenbank ist sauber.",
@@ -7614,6 +7621,7 @@
"Uninstalling Ceph...": "Ceph deinstallieren...",
"Uninstalling Fastfetch...": "Fastfetch wird deinstalliert...",
"Uninstalling Figurine...": "Figur wird deinstalliert...",
"Uninstalling Log2RAM...": "Log2RAM wird deinstalliert...",
"Uninstalling amdgpu_top...": "amdgpu_top wird deinstalliert...",
"Uninstalling current NVIDIA driver before installing new version": "Deinstallieren Sie den aktuellen NVIDIA-Treiber, bevor Sie eine neue Version installieren",
"Uninstalling intel-gpu-tools...": "Intel-GPU-Tools werden deinstalliert...",
+8
View File
@@ -3401,6 +3401,7 @@
"Installing Fail2Ban...": "Instalando Fail2Ban...",
"Installing Git as a prerequisite...": "Instalar Git como requisito previo...",
"Installing Intel VA-API drivers in container...": "Instalación de controladores Intel VA-API en contenedor...",
"Installing Log2RAM": "Instalando Log2RAM",
"Installing Log2RAM from GitHub...": "Instalando Log2RAM desde GitHub...",
"Installing Log2RAM from source...": "Instalando Log2RAM desde la fuente...",
"Installing NFS Client in LXC": "Instalación del cliente NFS en LXC",
@@ -3890,10 +3891,14 @@
"Log aggregation server for Grafana.": "Servidor de agregación de registros para Grafana.",
"Log file": "Archivo de log",
"Log2RAM already registered — updating to latest configuration": "Log2RAM ya registrado: actualizando a la última configuración",
"Log2RAM could not be downloaded": "No se ha podido descargar Log2RAM",
"Log2RAM installation and configuration completed successfully.": "La instalación y configuración de Log2RAM se completó con éxito.",
"Log2RAM installation cancelled by user": "Instalación de Log2RAM cancelada por el usuario",
"Log2RAM installation verification failed. Check /tmp/log2ram_install.log": "Error en la verificación de la instalación de Log2RAM. Comprueba /tmp/log2ram_install.log",
"Log2RAM installed successfully": "Log2RAM se instaló correctamente",
"Log2RAM installed:": "Log2RAM instalado:",
"Log2RAM is removed at the next reboot, after writing /var/log to disk": "Log2RAM se elimina en el próximo reinicio, después de escribir /var/log en disco",
"Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot": "Log2RAM mantiene /var/log en RAM; el journal se queda en disco a partir del próximo arranque",
"Log2RAM keeps the journal in order from the next reboot": "Log2RAM mantiene el diario del sistema en orden a partir del próximo reinicio",
"Log2RAM size set to:": "Tamaño de Log2RAM establecido en:",
"Log2RAM write scheduled every": "Escritura de Log2RAM programada cada",
@@ -5773,6 +5778,7 @@
"Root shell/profile config": "Configuración de perfil/shell raíz",
"Root user on the PVE host (default 'root'):": "Usuario root en el host PVE ('root' predeterminado):",
"Rootfs size in GB": "Tamaño del rootfs en GB",
"Rotate and write /var/log to disk when it passes 85% of its size?": "¿Rotar y escribir /var/log en disco cuando supere el 85% de su tamaño?",
"Rotate the recovery passphrase": "Rotar la frase de contraseña de recuperación",
"Routing Information": "Información de enrutamiento",
"Routing Table": "Tabla de enrutamiento",
@@ -6948,6 +6954,7 @@
"The domain must resolve to the public address of this network before the certificate can be issued.": "El dominio debe resolver a la dirección pública de esta red antes de poder emitir el certificado.",
"The download client still needs to be configured.": "El cliente de descarga todavía necesita ser configurado.",
"The download stopped progressing; cancelling this attempt.": "La descarga dejó de progresar; cancelando este intento.",
"The downloaded Log2RAM does not match the expected release": "El Log2RAM descargado no coincide con la versión esperada",
"The downloaded image does not match its manifest": "La imagen descargada no coincide con su manifiesto",
"The downloaded image is corrupt:": "La imagen descargada es corrupta:",
"The dpkg package database is clean.": "La base de datos de paquetes de dpkg está limpia.",
@@ -7589,6 +7596,7 @@
"Uninstalling Ceph...": "Desinstalando Ceph...",
"Uninstalling Fastfetch...": "Desinstalando Fastfetch...",
"Uninstalling Figurine...": "Desinstalando Figurine...",
"Uninstalling Log2RAM...": "Desinstalando Log2RAM...",
"Uninstalling amdgpu_top...": "Desinstalando amdgpu_top...",
"Uninstalling current NVIDIA driver before installing new version": "Desinstalar el controlador NVIDIA actual antes de instalar una nueva versión",
"Uninstalling intel-gpu-tools...": "Desinstalando intel-gpu-tools...",
+8
View File
@@ -3404,6 +3404,7 @@
"Installing Fail2Ban...": "Installation de Fail2Ban...",
"Installing Git as a prerequisite...": "Installer Git comme prérequis...",
"Installing Intel VA-API drivers in container...": "Installation des pilotes Intel VA-API dans le conteneur...",
"Installing Log2RAM": "Installation de Log2RAM",
"Installing Log2RAM from GitHub...": "Installation de Log2RAM depuis GitHub...",
"Installing Log2RAM from source...": "Installation de Log2RAM à partir des sources...",
"Installing NFS Client in LXC": "Installation du client NFS dans LXC",
@@ -3894,10 +3895,14 @@
"Log aggregation server for Grafana.": "Serveur d’agrégation de journaux pour Grafana.",
"Log file": "Fichier journal",
"Log2RAM already registered — updating to latest configuration": "Log2RAM déjà enregistré - mise à jour vers la dernière configuration",
"Log2RAM could not be downloaded": "Impossible de télécharger Log2RAM",
"Log2RAM installation and configuration completed successfully.": "L'installation et la configuration de Log2RAM se sont terminées avec succès.",
"Log2RAM installation cancelled by user": "Installation de Log2RAM annulée par l'utilisateur",
"Log2RAM installation verification failed. Check /tmp/log2ram_install.log": "La vérification de l'installation de Log2RAM a échoué. Vérifiez /tmp/log2ram_install.log",
"Log2RAM installed successfully": "Log2RAM installé avec succès",
"Log2RAM installed:": "Log2RAM installé :",
"Log2RAM is removed at the next reboot, after writing /var/log to disk": "Log2RAM est supprimé au prochain redémarrage, après l'écriture de /var/log sur le disque",
"Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot": "Log2RAM garde /var/log en RAM ; le journal reste sur le disque à partir du prochain démarrage",
"Log2RAM keeps the journal in order from the next reboot": "Log2RAM maintient le journal en ordre dès le prochain redémarrage",
"Log2RAM size set to:": "Taille de Log2RAM définie sur :",
"Log2RAM write scheduled every": "Écriture Log2RAM programmée tous les",
@@ -5789,6 +5794,7 @@
"Root shell/profile config": "Configuration du shell/profil racine",
"Root user on the PVE host (default 'root'):": "Utilisateur root sur l'hôte PVE ('root' par défaut) :",
"Rootfs size in GB": "Taille des racines en GB",
"Rotate and write /var/log to disk when it passes 85% of its size?": "Effectuer la rotation de /var/log et l'écrire sur le disque lorsqu'il dépasse 85 % de sa taille ?",
"Rotate the recovery passphrase": "Faites pivoter la phrase secrète de récupération",
"Routing Information": "Informations d'acheminement",
"Routing Table": "Table de routage",
@@ -6965,6 +6971,7 @@
"The domain must resolve to the public address of this network before the certificate can be issued.": "Le domaine doit se résoudre à l'adresse publique de ce réseau avant la délivrance du certificat.",
"The download client still needs to be configured.": "Le client de téléchargement doit encore être configuré.",
"The download stopped progressing; cancelling this attempt.": "Le téléchargement a cessé de progresser; annuler cette tentative.",
"The downloaded Log2RAM does not match the expected release": "Le Log2RAM téléchargé ne correspond pas à la version attendue",
"The downloaded image does not match its manifest": "L'image téléchargée ne correspond pas à son manifeste",
"The downloaded image is corrupt:": "L'image téléchargée est corrompue :",
"The dpkg package database is clean.": "La base de données du package dpkg est propre.",
@@ -7613,6 +7620,7 @@
"Uninstalling Ceph...": "Désinstallation de Ceph...",
"Uninstalling Fastfetch...": "Désinstallation de Fastfetch...",
"Uninstalling Figurine...": "Désinstallation de Figurine...",
"Uninstalling Log2RAM...": "Désinstallation de Log2RAM...",
"Uninstalling amdgpu_top...": "Désinstallation d'amdgpu_top...",
"Uninstalling current NVIDIA driver before installing new version": "Désinstallation du pilote NVIDIA actuel avant d'installer la nouvelle version",
"Uninstalling intel-gpu-tools...": "Désinstallation des outils Intel-Gpu...",
+8
View File
@@ -3404,6 +3404,7 @@
"Installing Fail2Ban...": "Installazione Fail2Ban...",
"Installing Git as a prerequisite...": "Installazione Git come prerequisito...",
"Installing Intel VA-API drivers in container...": "Installazione dei driver Intel VA-API nel container...",
"Installing Log2RAM": "Installazione di Log2RAM",
"Installing Log2RAM from GitHub...": "Installazione di Log2RAM da GitHub...",
"Installing Log2RAM from source...": "Installazione di Log2RAM dal sorgente...",
"Installing NFS Client in LXC": "Installazione del client NFS in LXC",
@@ -3894,10 +3895,14 @@
"Log aggregation server for Grafana.": "Server di aggregazione dei log per Grafana.",
"Log file": "File di registro",
"Log2RAM already registered — updating to latest configuration": "Log2RAM già registrato: aggiornamento all'ultima configurazione",
"Log2RAM could not be downloaded": "Impossibile scaricare Log2RAM",
"Log2RAM installation and configuration completed successfully.": "Installazione e configurazione Log2RAM completate.",
"Log2RAM installation cancelled by user": "Installazione Log2RAM annullata dall'utente",
"Log2RAM installation verification failed. Check /tmp/log2ram_install.log": "Verifica installazione Log2RAM non riuscita. Controlla /tmp/log2ram_install.log",
"Log2RAM installed successfully": "Log2RAM installato correttamente",
"Log2RAM installed:": "Log2RAM installato:",
"Log2RAM is removed at the next reboot, after writing /var/log to disk": "Log2RAM viene rimosso al prossimo riavvio, dopo aver scritto /var/log su disco",
"Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot": "Log2RAM mantiene /var/log in RAM; il journal resta su disco dal prossimo avvio",
"Log2RAM keeps the journal in order from the next reboot": "Log2RAM mantiene in ordine il journal di sistema dal prossimo riavvio",
"Log2RAM size set to:": "Dimensione Log2RAM impostata su:",
"Log2RAM write scheduled every": "Scrittura Log2RAM programmata ogni",
@@ -5789,6 +5794,7 @@
"Root shell/profile config": "Configurazione shell/profilo root",
"Root user on the PVE host (default 'root'):": "Utente root sull'host PVE (default 'root'):",
"Rootfs size in GB": "Dimensione rootfs in GB",
"Rotate and write /var/log to disk when it passes 85% of its size?": "Ruotare e scrivere /var/log su disco quando supera l'85% della sua dimensione?",
"Rotate the recovery passphrase": "Sostituisci la passphrase di ripristino",
"Routing Information": "Informazioni di instradamento",
"Routing Table": "Tabella di instradamento",
@@ -6966,6 +6972,7 @@
"The domain must resolve to the public address of this network before the certificate can be issued.": "Il dominio deve risolversi nell'indirizzo pubblico di questa rete prima che il certificato possa essere emesso.",
"The download client still needs to be configured.": "Il client di download deve ancora essere configurato.",
"The download stopped progressing; cancelling this attempt.": "Il download non avanza più; annullamento del tentativo.",
"The downloaded Log2RAM does not match the expected release": "Il Log2RAM scaricato non corrisponde alla versione prevista",
"The downloaded image does not match its manifest": "L’immagine scaricata non corrisponde al manifest",
"The downloaded image is corrupt:": "L'immagine scaricata è danneggiata:",
"The dpkg package database is clean.": "Il database dei pacchetti dpkg è pulito.",
@@ -7614,6 +7621,7 @@
"Uninstalling Ceph...": "Disinstallazione Ceph...",
"Uninstalling Fastfetch...": "Disinstallazione Fastfetch...",
"Uninstalling Figurine...": "Disinstallazione Figurine...",
"Uninstalling Log2RAM...": "Disinstallazione di Log2RAM...",
"Uninstalling amdgpu_top...": "Disinstallazione amdgpu_top...",
"Uninstalling current NVIDIA driver before installing new version": "Disinstallazione del driver NVIDIA corrente prima di installare la nuova versione",
"Uninstalling intel-gpu-tools...": "Disinstallazione intel-gpu-tools...",
+8
View File
@@ -3404,6 +3404,7 @@
"Installing Fail2Ban...": "Instalando Fail2Ban...",
"Installing Git as a prerequisite...": "Instalando o Git como pré-requisito...",
"Installing Intel VA-API drivers in container...": "Instalando drivers Intel VA-API no contêiner...",
"Installing Log2RAM": "Instalando Log2RAM",
"Installing Log2RAM from GitHub...": "Instalando Log2RAM do GitHub...",
"Installing Log2RAM from source...": "Instalando Log2RAM da fonte...",
"Installing NFS Client in LXC": "Instalando o cliente NFS no LXC",
@@ -3894,10 +3895,14 @@
"Log aggregation server for Grafana.": "Servidor de agregação de logs para o Grafana.",
"Log file": "Arquivo de registro",
"Log2RAM already registered — updating to latest configuration": "Log2RAM já registrado — atualizando para a configuração mais recente",
"Log2RAM could not be downloaded": "Não foi possível baixar o Log2RAM",
"Log2RAM installation and configuration completed successfully.": "Instalação e configuração do Log2RAM concluídas com sucesso.",
"Log2RAM installation cancelled by user": "Instalação do Log2RAM cancelada pelo usuário",
"Log2RAM installation verification failed. Check /tmp/log2ram_install.log": "A verificação da instalação do Log2RAM falhou. Verifique /tmp/log2ram_install.log",
"Log2RAM installed successfully": "Log2RAM instalado com sucesso",
"Log2RAM installed:": "Log2RAM instalado:",
"Log2RAM is removed at the next reboot, after writing /var/log to disk": "O Log2RAM é removido na próxima reinicialização, depois de gravar /var/log no disco",
"Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot": "O Log2RAM mantém /var/log na RAM; o journal fica no disco a partir da próxima inicialização",
"Log2RAM keeps the journal in order from the next reboot": "Log2RAM mantém o diário em ordem a partir da próxima reinicialização",
"Log2RAM size set to:": "Tamanho do Log2RAM definido como:",
"Log2RAM write scheduled every": "Gravação Log2RAM agendada a cada",
@@ -5789,6 +5794,7 @@
"Root shell/profile config": "Configuração de shell/perfil raiz",
"Root user on the PVE host (default 'root'):": "Usuário root no host PVE (padrão 'root'):",
"Rootfs size in GB": "Tamanho do Rootfs em GB",
"Rotate and write /var/log to disk when it passes 85% of its size?": "Rotacionar e gravar /var/log no disco quando ultrapassar 85% do seu tamanho?",
"Rotate the recovery passphrase": "gire a senha de recuperação",
"Routing Information": "Informações de roteamento",
"Routing Table": "Tabela de roteamento",
@@ -6966,6 +6972,7 @@
"The domain must resolve to the public address of this network before the certificate can be issued.": "O domínio deve ser resolvido para o endereço público desta rede antes que o certificado possa ser emitido.",
"The download client still needs to be configured.": "O cliente de download ainda precisa ser configurado.",
"The download stopped progressing; cancelling this attempt.": "O download parou de progredir; cancelando esta tentativa.",
"The downloaded Log2RAM does not match the expected release": "O Log2RAM baixado não corresponde à versão esperada",
"The downloaded image does not match its manifest": "A imagem transferida não corresponde ao seu manifesto",
"The downloaded image is corrupt:": "A imagem baixada está corrompida:",
"The dpkg package database is clean.": "O banco de dados do pacote dpkg está limpo.",
@@ -7614,6 +7621,7 @@
"Uninstalling Ceph...": "Desinstalando o Ceph...",
"Uninstalling Fastfetch...": "Desinstalando o Fastfetch...",
"Uninstalling Figurine...": "Desinstalando a estatueta...",
"Uninstalling Log2RAM...": "Desinstalando Log2RAM...",
"Uninstalling amdgpu_top...": "Desinstalando amdgpu_top...",
"Uninstalling current NVIDIA driver before installing new version": "Desinstalando o driver NVIDIA atual antes de instalar a nova versão",
"Uninstalling intel-gpu-tools...": "Desinstalando ferramentas Intel-GPU...",
+8
View File
@@ -3404,6 +3404,7 @@
"Installing Fail2Ban...": "Inštalujem Fail2Ban...",
"Installing Git as a prerequisite...": "Inštalujem Git ako požiadavku...",
"Installing Intel VA-API drivers in container...": "Inštalujem Intel VA-API ovládače v kontajneri...",
"Installing Log2RAM": "Inštalujem Log2RAM",
"Installing Log2RAM from GitHub...": "Inštalujem Log2RAM z GitHubu...",
"Installing Log2RAM from source...": "Inštalujem Log2RAM zo zdrojového kódu...",
"Installing NFS Client in LXC": "Inštalujem NFS klienta v LXC",
@@ -3894,10 +3895,14 @@
"Log aggregation server for Grafana.": "Server na zhromažďovanie logov pre Grafanu.",
"Log file": "Súbor záznamu",
"Log2RAM already registered — updating to latest configuration": "Log2RAM už je zaregistrovaný - aktualizujem ho na najnovšie nastavenie",
"Log2RAM could not be downloaded": "Log2RAM sa nepodarilo stiahnuť",
"Log2RAM installation and configuration completed successfully.": "Inštalácia a nastavenie Log2RAM boli úspešne dokončené.",
"Log2RAM installation cancelled by user": "Inštalácia Log2RAM bola zrušená používateľom",
"Log2RAM installation verification failed. Check /tmp/log2ram_install.log": "Overenie inštalácie Log2RAM zlyhalo. Skontrolujte /tmp/log2ram_install.log",
"Log2RAM installed successfully": "Log2RAM bol úspešne nainštalovaný",
"Log2RAM installed:": "Log2RAM nainštalovaný:",
"Log2RAM is removed at the next reboot, after writing /var/log to disk": "Log2RAM sa odstráni pri ďalšom reštarte, po zápise /var/log na disk",
"Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot": "Log2RAM drží /var/log v RAM; journal zostáva na disku od nasledujúceho spustenia",
"Log2RAM keeps the journal in order from the next reboot": "Log2RAM udržiava žurnál v poriadku od nasledujúceho reštartu",
"Log2RAM size set to:": "Veľkosť Log2RAM nastavená na:",
"Log2RAM write scheduled every": "Zápis z Log2RAM je naplánovaný každých",
@@ -5791,6 +5796,7 @@
"Root shell/profile config": "Nastavenie shellu/profilu roota",
"Root user on the PVE host (default 'root'):": "Root používateľ na PVE hostovi (predvolené 'root'):",
"Rootfs size in GB": "Rootfs veľkosť v GB",
"Rotate and write /var/log to disk when it passes 85% of its size?": "Rotovať a zapísať /var/log na disk, keď prekročí 85 % svojej veľkosti?",
"Rotate the recovery passphrase": "Zmeniť obnovovaciu frázu",
"Routing Information": "Informácie o smerovaní",
"Routing Table": "Smerovacia tabuľka",
@@ -6967,6 +6973,7 @@
"The domain must resolve to the public address of this network before the certificate can be issued.": "Pred vydaním certifikátu musí doména smerovať na verejnú adresu tejto siete.",
"The download client still needs to be configured.": "Klienta na sťahovanie ešte treba nastaviť.",
"The download stopped progressing; cancelling this attempt.": "Sťahovanie prestalo napredovať; tento pokus sa ruší.",
"The downloaded Log2RAM does not match the expected release": "Stiahnutý Log2RAM nezodpovedá očakávanej verzii",
"The downloaded image does not match its manifest": "Stiahnutý obrázok nezodpovedá jeho manifestu",
"The downloaded image is corrupt:": "Stiahnutý obraz je poškodený:",
"The dpkg package database is clean.": "Databáza balíkov dpkg je čistá.",
@@ -7615,6 +7622,7 @@
"Uninstalling Ceph...": "Odinštalúvam Ceph...",
"Uninstalling Fastfetch...": "Odinštalúvam Fastfetch...",
"Uninstalling Figurine...": "Odinštalúvam Figurine...",
"Uninstalling Log2RAM...": "Odinštalúvam Log2RAM...",
"Uninstalling amdgpu_top...": "Odinštalúvam amdgpu_top...",
"Uninstalling current NVIDIA driver before installing new version": "Pred inštaláciou novej verzie odinštalúvam aktuálny ovládač NVIDIA",
"Uninstalling intel-gpu-tools...": "Odinštalúvam intel-gpu-tools...",
+8
View File
@@ -3404,6 +3404,7 @@
"Installing Fail2Ban...": "Installerar Fail2Ban...",
"Installing Git as a prerequisite...": "Installera Git som en förutsättning...",
"Installing Intel VA-API drivers in container...": "Installerar Intel VA-API-drivrutiner i container...",
"Installing Log2RAM": "Installerar Log2RAM",
"Installing Log2RAM from GitHub...": "Installerar Log2RAM från GitHub...",
"Installing Log2RAM from source...": "Installerar Log2RAM från källan...",
"Installing NFS Client in LXC": "Installerar NFS-klient i LXC",
@@ -3894,10 +3895,14 @@
"Log aggregation server for Grafana.": "Loggaggregeringsserver för Grafana.",
"Log file": "Loggfil",
"Log2RAM already registered — updating to latest configuration": "Log2RAM redan registrerat — uppdaterar till senaste konfigurationen",
"Log2RAM could not be downloaded": "Log2RAM kunde inte laddas ner",
"Log2RAM installation and configuration completed successfully.": "Log2RAM-installationen och konfigurationen har slutförts framgångsrikt.",
"Log2RAM installation cancelled by user": "Log2RAM-installationen avbröts av användaren",
"Log2RAM installation verification failed. Check /tmp/log2ram_install.log": "Verifiering av Log2RAM-installationen misslyckades. Kontrollera /tmp/log2ram_install.log",
"Log2RAM installed successfully": "Log2RAM installerades framgångsrikt",
"Log2RAM installed:": "Log2RAM installerat:",
"Log2RAM is removed at the next reboot, after writing /var/log to disk": "Log2RAM tas bort vid nästa omstart, efter att /var/log har skrivits till disken",
"Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot": "Log2RAM håller /var/log i RAM; journalen ligger kvar på disken från nästa start",
"Log2RAM keeps the journal in order from the next reboot": "Log2RAM håller ordning på journalen från nästa omstart",
"Log2RAM size set to:": "Log2RAM-storlek inställd på:",
"Log2RAM write scheduled every": "Log2RAM-skrivning schemalagt varje",
@@ -5789,6 +5794,7 @@
"Root shell/profile config": "Rotskal/profilkonfiguration",
"Root user on the PVE host (default 'root'):": "Rotanvändare på PVE-värden (standard 'root'):",
"Rootfs size in GB": "Rootfs storlek i GB",
"Rotate and write /var/log to disk when it passes 85% of its size?": "Rotera och skriva /var/log till disken när den överstiger 85 % av sin storlek?",
"Rotate the recovery passphrase": "Vrid återställningslösenfrasen",
"Routing Information": "Routningsinformation",
"Routing Table": "Rutttabell",
@@ -6966,6 +6972,7 @@
"The domain must resolve to the public address of this network before the certificate can be issued.": "Domänen måste lösa den offentliga adressen till detta nätverk innan certifikatet kan utfärdas.",
"The download client still needs to be configured.": "Nedladdningskunden behöver fortfarande konfigureras.",
"The download stopped progressing; cancelling this attempt.": "Nedladdningen slutade utvecklas; avbryta detta försök.",
"The downloaded Log2RAM does not match the expected release": "Det nedladdade Log2RAM motsvarar inte den förväntade versionen",
"The downloaded image does not match its manifest": "Den nedladdade bilden matchar inte dess manifest",
"The downloaded image is corrupt:": "Den nedladdade bilden är korrupt:",
"The dpkg package database is clean.": "Paketdatabasen för dpkg är ren.",
@@ -7614,6 +7621,7 @@
"Uninstalling Ceph...": "Avinstallerar Ceph...",
"Uninstalling Fastfetch...": "Avinstallerar Fastfetch...",
"Uninstalling Figurine...": "Avinstallerar figuren...",
"Uninstalling Log2RAM...": "Avinstallerar Log2RAM...",
"Uninstalling amdgpu_top...": "Avinstallerar amdgpu_top...",
"Uninstalling current NVIDIA driver before installing new version": "Avinstallerar nuvarande NVIDIA-drivrutin innan den nya versionen installeras",
"Uninstalling intel-gpu-tools...": "Avinstallerar intel-gpu-tools...",
+73
View File
@@ -0,0 +1,73 @@
#!/bin/bash
# ==========================================================
# ProxMenux - Folders of /var/log that Log2RAM leaves on disk
# ==========================================================
# Runs before Log2RAM puts /var/log in RAM. The journal, the task logs of
# Proxmox VE and those of Proxmox Backup Server are records a host needs after
# a power cut, and a task cannot run if its log cannot be written, so they
# stay on disk: each folder moves to
# /var/hdd.<name> and its usual place becomes a link to it. Log2RAM copies a
# link as a link, so their contents never enter the RAM.
#
# With PMX_L2R_REVERT=1 it puts the folders back in /var/log and removes the
# links; the uninstaller runs it that way at the next boot.
#
# PMX_L2R_ROOT prefixes every path, for tests.
# ==========================================================
ROOT="${PMX_L2R_ROOT:-}"
LOG_DIR="$ROOT/var/log"
# Only while /var/log is the folder on disk, never the copy in RAM.
if [ -z "$ROOT" ] && mountpoint -q /var/log; then
exit 0
fi
KEPT_ON_DISK="journal pve proxmox-backup"
keep_on_disk() {
local name="$1"
local place="$LOG_DIR/$name" disk="$ROOT/var/hdd.$name"
if [ -L "$place" ]; then
[ -d "$disk" ] || mkdir -p "$disk"
return 0
fi
# The journal is always kept on disk; any other folder only where it exists.
if [ ! -d "$place" ]; then
[ "$name" = journal ] || return 0
mkdir -p "$disk"
chown root:systemd-journal "$disk" 2>/dev/null || true
chmod 2755 "$disk"
elif [ ! -e "$disk" ]; then
mv "$place" "$disk" || return 1
else
cp -a "$place/." "$disk/" || return 1
rm -rf "${place:?}"
fi
ln -s "/var/hdd.$name" "$place"
}
put_back() {
local name="$1"
local place="$LOG_DIR/$name" disk="$ROOT/var/hdd.$name"
[ -d "$disk" ] || { [ -L "$place" ] && rm -f "$place"; return 0; }
[ -L "$place" ] && rm -f "$place"
if [ ! -e "$place" ]; then
mv "$disk" "$place" || return 1
else
cp -a "$disk/." "$place/" || return 1
rm -rf "${disk:?}"
fi
}
status=0
for name in $KEPT_ON_DISK; do
if [ "${PMX_L2R_REVERT:-0}" = 1 ]; then
put_back "$name" || status=1
else
keep_on_disk "$name" || status=1
fi
done
exit "$status"
+214
View File
@@ -0,0 +1,214 @@
#!/bin/bash
# ==========================================================
# ProxMenux - Log2RAM setup shared by both post-install modes
# ==========================================================
# Log2RAM keeps /var/log in RAM and writes it to disk on a schedule. The
# journal and the task logs of Proxmox VE and Proxmox Backup Server stay on
# disk: see log2ram_keep_on_disk.sh, which moves them before Log2RAM starts.
#
# Requires utils.sh (translate, msg_*) and pmx_journal.sh (pmx_write_file...).
# ==========================================================
PMX_L2R_TAG="1.7.2"
PMX_L2R_COMMIT="f171449530f8984374c8f69fff3c92af813a694b"
PMX_L2R_REPO="https://github.com/azlux/log2ram.git"
PMX_L2R_SCRIPTS="/usr/local/share/proxmenux/scripts/global"
PMX_L2R_REVERT_UNIT="/etc/systemd/system/proxmenux-log2ram-revert.service"
# Size in MB and sync interval in hours proposed for this host's RAM.
pmx_log2ram_default_size() {
local ram_gb
ram_gb="$(awk '/^MemTotal:/{print int($2/1024/1024)}' /proc/meminfo)"
if (( ${ram_gb:-4} <= 8 )); then echo 128
elif (( ram_gb <= 16 )); then echo 256
else echo 512; fi
}
pmx_log2ram_default_hours() {
local ram_gb
ram_gb="$(awk '/^MemTotal:/{print int($2/1024/1024)}' /proc/meminfo)"
if (( ${ram_gb:-4} <= 8 )); then echo 1
elif (( ram_gb <= 16 )); then echo 3
else echo 6; fi
}
# What an installed Log2RAM is set to, for an update to keep it.
pmx_log2ram_current_size() {
local size
size="$(grep -E '^SIZE=' /etc/log2ram.conf 2>/dev/null | tail -1 | cut -d= -f2 | tr -dc '0-9')"
echo "${size:-$(pmx_log2ram_default_size)}"
}
pmx_log2ram_current_hours() {
local hours
hours="$(sed -n 's/^OnCalendar=\*-\*-\* 00\/\([0-9]*\):55:00$/\1/p' \
/etc/systemd/system/log2ram-daily.timer.d/proxmenux.conf 2>/dev/null)"
# Earlier versions synced from a cron entry: "0 */N * * * root ... write".
[[ -n "$hours" ]] || hours="$(sed -n 's/^0 \*\/\([0-9]*\) .*log2ram write.*/\1/p' /etc/cron.d/log2ram 2>/dev/null)"
echo "${hours:-$(pmx_log2ram_default_hours)}"
}
# Size-based rotation for the API logs of Proxmox Backup Server, whose
# package ships no rule for them.
_pmx_log2ram_pbs_logrotate() {
dpkg-query -W -f='${Status}' proxmox-backup-server 2>/dev/null | grep -q 'install ok installed' || return 0
pmx_write_file /etc/logrotate.d/proxmox-backup-api <<'EOF'
/var/log/proxmox-backup/api/access.log /var/log/proxmox-backup/api/auth.log {
size 20M
rotate 3
compress
missingok
notifempty
copytruncate
}
EOF
chmod 0644 /etc/logrotate.d/proxmox-backup-api
}
# Files of the Log2RAM release, copied from a verified checkout. Its own
# install.sh is not run: it refuses to run while Log2RAM is active and starts
# by deleting /var/hdd.log, which is the disk copy of /var/log while mounted.
_pmx_log2ram_install_release() {
local checkout="/tmp/log2ram-${PMX_L2R_TAG}"
rm -rf "$checkout"
if ! git clone --quiet --depth 1 --branch "$PMX_L2R_TAG" "$PMX_L2R_REPO" "$checkout" >/dev/null 2>&1; then
msg_error "$(translate "Log2RAM could not be downloaded")"
return 1
fi
if [[ "$(git -C "$checkout" rev-parse HEAD 2>/dev/null)" != "$PMX_L2R_COMMIT" ]]; then
rm -rf "$checkout"
msg_error "$(translate "The downloaded Log2RAM does not match the expected release")"
return 1
fi
mkdir -p /usr/local/bin
install -m 644 "$checkout/log2ram.service" /etc/systemd/system/log2ram.service
install -m 644 "$checkout/log2ram-daily.service" /etc/systemd/system/log2ram-daily.service
install -m 644 "$checkout/log2ram-daily.timer" /etc/systemd/system/log2ram-daily.timer
install -m 755 "$checkout/log2ram" /usr/local/bin/log2ram
[[ -d /etc/logrotate.d ]] && install -m 644 "$checkout/log2ram.logrotate" /etc/logrotate.d/log2ram
[[ -f /etc/log2ram.conf ]] || install -m 644 "$checkout/log2ram.conf" /etc/log2ram.conf
rm -rf "$checkout"
}
# What earlier versions of this function installed and this one replaces.
_pmx_log2ram_remove_legacy() {
local path
for path in /etc/cron.d/log2ram /usr/local/bin/log2ram-check.sh \
/etc/cron.hourly/proxmox-backup-logrotate \
/usr/local/bin/log2ram.proxmenux.bak /usr/sbin/log2ram.proxmenux.bak; do
pmx_remove_file "$path" 2>/dev/null || true
done
}
# pmx_log2ram_setup SIZE_MB SYNC_HOURS WATCH(true|false)
pmx_log2ram_setup() {
local size_mb="$1" hours="$2" watch="$3"
local keep_free_mb=$(( size_mb / 2 ))
command -v rsync >/dev/null 2>&1 || pmx_install_pkg rsync
command -v git >/dev/null 2>&1 || pmx_install_pkg git
msg_info "$(translate "Installing Log2RAM") ${PMX_L2R_TAG}..."
_pmx_log2ram_install_release || return 1
msg_ok "$(translate "Log2RAM installed:") ${PMX_L2R_TAG}"
# The journal is not in RAM, so Log2RAM does not rotate it before a sync;
# and Proxmox has no mail command for its error notice.
pmx_edit_file /etc/log2ram.conf \
-e "s/^SIZE=.*/SIZE=${size_mb}M/" \
-e "s/^JOURNALD_AWARE=.*/JOURNALD_AWARE=false/" \
-e "s/^#\?NOTIFICATION=.*/NOTIFICATION=false/"
grep -q '^NOTIFICATION=' /etc/log2ram.conf || printf 'NOTIFICATION=false\n' | pmx_append_file /etc/log2ram.conf
mkdir -p /etc/systemd/system/log2ram.service.d /etc/systemd/system/log2ram-daily.timer.d
pmx_write_file /etc/systemd/system/log2ram.service.d/proxmenux.conf <<EOF
# ProxMenux: the journal stays on disk, and a sync is on disk when it ends.
[Service]
ExecStartPre=-${PMX_L2R_SCRIPTS}/log2ram_keep_on_disk.sh
ExecReload=
ExecReload=/usr/local/bin/log2ram write
ExecReload=/bin/sync -f /var/hdd.log
EOF
pmx_write_file /etc/systemd/system/log2ram-daily.timer.d/proxmenux.conf <<EOF
# ProxMenux: /var/log is written to disk every ${hours} hour(s).
[Timer]
OnCalendar=
OnCalendar=*-*-* 00/${hours}:55:00
EOF
mkdir -p /etc/systemd/journald.conf.d
pmx_write_file /etc/systemd/journald.conf.d/proxmenux-log2ram.conf <<EOF
# ProxMenux: the journal is kept on disk, outside the Log2RAM folder.
# SystemKeepFree also bounds it while it is still in RAM, until the next boot.
[Journal]
Storage=persistent
SystemMaxUse=1G
SystemKeepFree=${keep_free_mb}M
# MaxLevelStore=info: required for ProxMenux Monitor log display and Fail2Ban detection.
MaxLevelStore=info
EOF
# The journal folder is a link; the attribute for btrfs goes to its target.
pmx_write_file /etc/tmpfiles.d/journal-nocow.conf <<'EOF'
# ProxMenux: /var/log/journal links to /var/hdd.journal while Log2RAM is installed.
h /var/hdd.journal - - - - +C
h /var/hdd.journal/%m - - - - +C
h /var/hdd.journal/remote - - - - +C
EOF
if [[ "$watch" == true ]]; then
pmx_write_file /etc/cron.d/log2ram-auto-sync <<EOF
# ProxMenux: past 85% of its size, /var/log in RAM is rotated and written to disk.
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
3-59/10 * * * * root nice -n 19 ionice -c 3 ${PMX_L2R_SCRIPTS}/log2ram_watch.sh >/dev/null 2>&1
EOF
chmod 0644 /etc/cron.d/log2ram-auto-sync
else
pmx_remove_file /etc/cron.d/log2ram-auto-sync 2>/dev/null || true
fi
_pmx_log2ram_pbs_logrotate
_pmx_log2ram_remove_legacy
pmx_remove_file "$PMX_L2R_REVERT_UNIT" 2>/dev/null || true
systemctl daemon-reload >/dev/null 2>&1 || true
pmx_apply_setting "service-enabled:log2ram" "systemctl is-enabled log2ram" \
systemctl enable log2ram.service log2ram-daily.timer || return 1
msg_ok "$(translate "Log2RAM keeps /var/log in RAM; the journal stays on disk from the next boot")"
}
# Log2RAM stops at the next shutdown, writing /var/log to disk on its way;
# the boot after that puts the journal back in /var/log.
pmx_log2ram_remove() {
pmx_disable_service log2ram-daily.timer 2>/dev/null || true
systemctl disable log2ram.service >/dev/null 2>&1 || true
local path
for path in /etc/cron.d/log2ram-auto-sync /etc/systemd/journald.conf.d/proxmenux-log2ram.conf \
/etc/tmpfiles.d/journal-nocow.conf /etc/systemd/system/log2ram.service.d/proxmenux.conf \
/etc/systemd/system/log2ram-daily.timer.d/proxmenux.conf; do
pmx_remove_file "$path" 2>/dev/null || true
done
_pmx_log2ram_remove_legacy
pmx_write_file "$PMX_L2R_REVERT_UNIT" <<EOF
[Unit]
Description=ProxMenux: put the journal back in /var/log after removing Log2RAM
DefaultDependencies=no
After=local-fs.target
Before=systemd-journald.service sysinit.target
ConditionPathExists=!/etc/systemd/system/sysinit.target.wants/log2ram.service
[Service]
Type=oneshot
Environment=PMX_L2R_REVERT=1
ExecStart=-${PMX_L2R_SCRIPTS}/log2ram_keep_on_disk.sh
ExecStart=/bin/sh -c 'mountpoint -q /var/hdd.log || rmdir /var/hdd.log 2>/dev/null; rm -f /usr/local/bin/log2ram /usr/local/bin/uninstall-log2ram.sh /etc/log2ram.conf /etc/logrotate.d/log2ram /etc/systemd/system/log2ram.service /etc/systemd/system/log2ram-daily.service /etc/systemd/system/log2ram-daily.timer; rmdir /etc/systemd/system/log2ram.service.d /etc/systemd/system/log2ram-daily.timer.d 2>/dev/null; systemctl disable proxmenux-log2ram-revert.service; rm -f ${PMX_L2R_REVERT_UNIT}; systemctl daemon-reload'
[Install]
WantedBy=sysinit.target
EOF
systemctl daemon-reload >/dev/null 2>&1 || true
systemctl enable proxmenux-log2ram-revert.service >/dev/null 2>&1 || true
}
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# ==========================================================
# ProxMenux - Keeps the Log2RAM folder from filling up
# ==========================================================
# Past 85% of its size, the logs in RAM are rotated and the ones just rotated
# are compressed at once, then everything is written to disk. Rules with
# delaycompress, such as the one of pveproxy, would otherwise leave the largest
# log uncompressed until the next day. No log is emptied.
# ==========================================================
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
mountpoint -q /var/log || exit 0
used="$(df --output=pcent /var/log 2>/dev/null | tail -1 | tr -dc '0-9')"
[ "${used:-0}" -ge 85 ] || exit 0
exec 9>/run/proxmenux-log2ram-watch.lock || exit 0
flock -n 9 || exit 0
logrotate -f /etc/logrotate.conf >/dev/null 2>&1 || true
find /var/log -xdev -type f -name '*.1' -exec gzip -9 -- {} + 2>/dev/null || true
systemctl reload log2ram >/dev/null 2>&1 || true
+4 -3
View File
@@ -205,11 +205,12 @@ update_pve_safe() {
fi
# The package list rides in the same dialog as the summary, so the
# decision is taken knowing what is about to be replaced. --scrolltext
# keeps the buttons reachable however long the list is.
# decision is taken knowing what is about to be replaced. Keep Yes focused
# while the list remains scrollable; --keep-tite restores the execution screen.
menu_text+="$(translate "Packages to be upgraded"):\n$upgradable_list\n\n"
menu_text+="$(translate "Do you want to proceed with the system update?")"
if ! whiptail --title "$(translate "Proxmox Update")" --scrolltext --yesno "$menu_text" 24 78; then
if ! dialog --keep-tite --title "$(translate "Proxmox Update")" \
--default-button yes --no-collapse --scrollbar --yesno "$menu_text" 24 78; then
msg_info2 "$(translate "Update cancelled by user")"
apt-get -y autoremove >/dev/null 2>&1 || true
apt-get -y autoclean >/dev/null 2>&1 || true
+4 -2
View File
@@ -169,10 +169,12 @@ EOF
else
# The package list rides in the same dialog as the summary, so
# the decision is taken knowing what is about to be replaced.
# --scrolltext keeps the buttons reachable however long it is.
# Keep Yes focused while the full package list remains scrollable.
# --keep-tite restores the execution screen after confirmation.
menu_text+="$(translate "Packages to be upgraded"):\n$upgradable_list\n\n"
menu_text+="$(translate "Do you want to proceed with the system update?")"
if whiptail --title "$(translate "Proxmox Update")" --scrolltext --yesno "$menu_text" 24 78; then
if dialog --keep-tite --title "$(translate "Proxmox Update")" \
--default-button yes --no-collapse --scrollbar --yesno "$menu_text" 24 78; then
return 0
else
return 1
+4 -2
View File
@@ -272,10 +272,12 @@ EOF
else
# The package list rides in the same dialog as the summary, so
# the decision is taken knowing what is about to be replaced.
# --scrolltext keeps the buttons reachable however long it is.
# Keep Yes focused while the full package list remains scrollable.
# --keep-tite restores the execution screen after confirmation.
menu_text+="$(translate "Packages to be upgraded"):\n$upgradable_list\n\n"
menu_text+="$(translate "Do you want to proceed with the system update?")"
if whiptail --title "$(translate "Proxmox Update")" --scrolltext --yesno "$menu_text" 24 78; then
if dialog --keep-tite --title "$(translate "Proxmox Update")" \
--default-button yes --no-collapse --scrollbar --yesno "$menu_text" 24 78; then
return 0
else
return 1
-15
View File
@@ -401,18 +401,3 @@ pmx_rebuild_dkms_after_kernel() {
fi
return 0
}
# Log2RAM syncs only the archived journal files, so the active file it found
# on disk when it was installed stays there. Restored at every boot, it makes
# journald continue an old sequence and delete its newest archives first.
# The sync removes that file from the disk copy. Returns 0 when it changes
# the given Log2RAM script.
pmx_log2ram_drop_stale_journal() {
local log2ram_bin="$1"
[[ -f "$log2ram_bin" ]] || return 1
grep -q -- '--exclude=journal/\*/\*' "$log2ram_bin" 2>/dev/null || return 1
grep -q -- '--delete-excluded' "$log2ram_bin" 2>/dev/null && return 1
[[ -e "${log2ram_bin}.proxmenux.bak" ]] || cp -a "$log2ram_bin" "${log2ram_bin}.proxmenux.bak"
sed '/optional_params+=("--exclude=journal\/\*\/\*")/a\ optional_params+=("--delete-excluded")' "$log2ram_bin" \
| pmx_write_file "$log2ram_bin"
}
+7 -396
View File
@@ -53,6 +53,9 @@ fi
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
fi
if [[ -f "$LOCAL_SCRIPTS/global/log2ram_setup.sh" ]]; then
source "$LOCAL_SCRIPTS/global/log2ram_setup.sh"
fi
load_language
initialize_cache
@@ -959,148 +962,18 @@ EOF
_update_existing_log2ram_auto() {
local func_version="$1"
local log2ram_bin=""
local candidate resolved tmp_file
pmx_journal_context "_update_existing_log2ram_auto" "$func_version"
msg_ok "$(translate "Log2RAM already registered — updating to latest configuration")"
for candidate in \
"$(command -v log2ram 2>/dev/null)" \
/usr/local/bin/log2ram \
/usr/sbin/log2ram \
/usr/bin/log2ram
do
[[ -n "$candidate" && -f "$candidate" ]] || continue
resolved="$(readlink -f "$candidate" 2>/dev/null || printf '%s' "$candidate")"
[[ -f "$resolved" ]] || continue
log2ram_bin="$resolved"
break
done
if [[ -z "$log2ram_bin" || ! -f /etc/log2ram.conf ]]; then
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
return 1
fi
if grep -q 'rsync -aAXv ' "$log2ram_bin" 2>/dev/null; then
[[ -e "${log2ram_bin}.proxmenux.bak" ]] || cp -a "$log2ram_bin" "${log2ram_bin}.proxmenux.bak"
sed 's/rsync -aAXv /rsync -aXv --no-acls /g' "$log2ram_bin" | pmx_write_file "$log2ram_bin"
fi
if pmx_log2ram_drop_stale_journal "$log2ram_bin"; then
NECESSARY_REBOOT=1
msg_ok "$(translate "Log2RAM keeps the journal in order from the next reboot")"
fi
if dpkg-query -W -f='${Status}' proxmox-backup-server 2>/dev/null \
| grep -q 'install ok installed'; then
tmp_file="$(mktemp /etc/logrotate.d/.proxmox-backup-api.XXXXXX)" || return 1
cat > "$tmp_file" <<'EOF'
/var/log/proxmox-backup/api/access.log /var/log/proxmox-backup/api/auth.log {
size 20M
rotate 3
compress
missingok
notifempty
copytruncate
}
EOF
chmod 0644 "$tmp_file"
chown root:root "$tmp_file"
pmx_write_file /etc/logrotate.d/proxmox-backup-api < "$tmp_file"
rm -f "$tmp_file"
tmp_file="$(mktemp /etc/cron.hourly/.proxmox-backup-logrotate.XXXXXX)" || return 1
cat > "$tmp_file" <<'EOF'
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1
EOF
chmod 0755 "$tmp_file"
chown root:root "$tmp_file"
pmx_write_file /etc/cron.hourly/proxmox-backup-logrotate < "$tmp_file"
chmod 0755 /etc/cron.hourly/proxmox-backup-logrotate
chown root:root /etc/cron.hourly/proxmox-backup-logrotate
rm -f "$tmp_file"
msg_ok "$(translate "PBS API log rotation configured (hourly, size-based)")"
fi
tmp_file="$(mktemp /usr/local/bin/.log2ram-check.XXXXXX)" || return 1
cat > "$tmp_file" <<'EOF'
#!/usr/bin/env bash
# Watch /var/log usage on Log2RAM's tmpfs and act at two thresholds:
# > 80% → vacuum journald down to ~30% of SIZE, then log2ram write
# > 92% → aggressive: journal to ~5%, rotate PBS API logs if present,
# truncate existing pveproxy/pveam logs, then log2ram write
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CONF_FILE="/etc/log2ram.conf"
L2R_BIN="$(command -v log2ram || true)"
[[ -z "$L2R_BIN" && -x /usr/sbin/log2ram ]] && L2R_BIN="/usr/sbin/log2ram"
[[ -z "$L2R_BIN" ]] && exit 0
SIZE_MiB="$(grep -E '^SIZE=' "$CONF_FILE" 2>/dev/null | cut -d'=' -f2 | tr -dc '0-9')"
[[ -z "$SIZE_MiB" ]] && SIZE_MiB=128
LIMIT_BYTES=$(( SIZE_MiB * 1024 * 1024 ))
WARN_BYTES=$(( LIMIT_BYTES * 80 / 100 ))
EMERGENCY_BYTES=$(( LIMIT_BYTES * 92 / 100 ))
USED_BYTES="$(df -B1 --output=used /var/log 2>/dev/null | tail -1 | tr -dc '0-9')"
[[ -z "$USED_BYTES" ]] && exit 0
LOCK="/run/log2ram-check.lock"
exec 9>"$LOCK" 2>/dev/null || exit 0
flock -n 9 || exit 0
if (( USED_BYTES > EMERGENCY_BYTES )); then
SAFE_JOURNAL_MB=$(( SIZE_MiB * 5 / 100 ))
[[ "$SAFE_JOURNAL_MB" -lt 16 ]] && SAFE_JOURNAL_MB=16
journalctl --vacuum-size="${SAFE_JOURNAL_MB}M" >/dev/null 2>&1 || true
if [[ -x /usr/sbin/logrotate && -f /etc/logrotate.d/proxmox-backup-api ]]; then
/usr/sbin/logrotate -f /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1 || true
fi
[ -e /var/log/pveproxy/access.log ] && : > /var/log/pveproxy/access.log 2>/dev/null || true
[ -e /var/log/pveproxy/error.log ] && : > /var/log/pveproxy/error.log 2>/dev/null || true
[ -e /var/log/pveam.log ] && : > /var/log/pveam.log 2>/dev/null || true
"$L2R_BIN" write 2>/dev/null || true
elif (( USED_BYTES > WARN_BYTES )); then
SOFT_JOURNAL_MB=$(( SIZE_MiB * 30 / 100 ))
[[ "$SOFT_JOURNAL_MB" -lt 32 ]] && SOFT_JOURNAL_MB=32
journalctl --vacuum-size="${SOFT_JOURNAL_MB}M" >/dev/null 2>&1 || true
"$L2R_BIN" write 2>/dev/null || true
fi
EOF
chmod 0755 "$tmp_file"
chown root:root "$tmp_file"
bash -n "$tmp_file" || return 1
pmx_write_file /usr/local/bin/log2ram-check.sh < "$tmp_file"
chmod 0755 /usr/local/bin/log2ram-check.sh
chown root:root /usr/local/bin/log2ram-check.sh
rm -f "$tmp_file"
tmp_file="$(mktemp /etc/cron.d/.log2ram-auto-sync.XXXXXX)" || return 1
cat > "$tmp_file" <<'EOF'
# Log2RAM auto-sync based on /var/log usage - Created by ProxMenux
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
# nice/ionice keep the check off the priority queue for scheduled tasks.
3-59/10 * * * * root nice -n 19 ionice -c 3 /usr/local/bin/log2ram-check.sh >/dev/null 2>&1
EOF
chmod 0644 "$tmp_file"
chown root:root "$tmp_file"
pmx_write_file /etc/cron.d/log2ram-auto-sync < "$tmp_file"
chmod 0644 /etc/cron.d/log2ram-auto-sync
chown root:root /etc/cron.d/log2ram-auto-sync
rm -f "$tmp_file"
pmx_log2ram_setup "$(pmx_log2ram_current_size)" "$(pmx_log2ram_current_hours)" true || return 1
NECESSARY_REBOOT=1
register_tool "log2ram" true "$func_version"
msg_success "$(translate "Log2RAM installation and configuration completed successfully.")"
}
install_log2ram_auto() {
local FUNC_VERSION="1.8"
local FUNC_VERSION="2.0"
local existing_log2ram_bin=""
pmx_journal_context "install_log2ram_auto" "$FUNC_VERSION"
@@ -1156,270 +1029,8 @@ install_log2ram_auto() {
fi # end first-time install block
msg_info "$(translate "Cleaning previous Log2RAM installation...")"
pmx_disable_service log2ram || true
pmx_disable_service log2ram-daily.timer || true
local obsolete_path
for obsolete_path in \
/etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync \
/etc/cron.hourly/log2ram /etc/cron.daily/log2ram \
/etc/cron.weekly/log2ram /etc/cron.monthly/log2ram \
/usr/local/bin/log2ram-check.sh /usr/local/bin/log2ram /usr/sbin/log2ram \
/etc/systemd/system/log2ram.service \
/etc/systemd/system/log2ram-daily.timer \
/etc/systemd/system/log2ram-daily.service \
/etc/systemd/system/sysinit.target.wants/log2ram.service \
/etc/log2ram.conf /etc/log2ram.conf.* /etc/logrotate.d/log2ram
do
pmx_remove_file "$obsolete_path" 2>/dev/null || true
done
rm -rf /etc/systemd/system/log2ram.service.d 2>/dev/null || true
rm -rf /var/log.hdd /tmp/log2ram 2>/dev/null || true
systemctl daemon-reexec >/dev/null 2>&1 || true
systemctl daemon-reload >/dev/null 2>&1 || true
systemctl restart cron >/dev/null 2>&1 || true
msg_ok "$(translate "Previous installation cleaned")"
msg_info "$(translate "Installing Log2RAM from source...")"
if ! command -v git >/dev/null 2>&1; then
apt-get update -qq >/dev/null 2>&1
pmx_install_pkg git
fi
rm -rf /tmp/log2ram 2>/dev/null || true
if ! git clone --depth 1 https://github.com/azlux/log2ram.git /tmp/log2ram >/dev/null 2>>/tmp/log2ram_install.log; then
msg_error "$(translate "Failed to clone log2ram repository. Check /tmp/log2ram_install.log")"
return 1
fi
cd /tmp/log2ram || { msg_error "$(translate "Failed to access log2ram directory")"; return 1; }
if ! bash install.sh >>/tmp/log2ram_install.log 2>&1; then
msg_error "$(translate "Failed to run log2ram installer. Check /tmp/log2ram_install.log")"
return 1
fi
# Drop ACL preservation from the upstream rsync call: some
# /var/log.hdd filesystems reject POSIX ACLs and log2ram write
# exits 23 with `set_acl: Operation not supported`. xattrs stay.
local _l2r_bin
for _l2r_bin in \
"$(command -v log2ram 2>/dev/null)" \
/usr/local/bin/log2ram \
/usr/sbin/log2ram \
/usr/bin/log2ram
do
[[ -n "$_l2r_bin" && -f "$_l2r_bin" ]] || continue
if grep -q 'rsync -aAXv ' "$_l2r_bin" 2>/dev/null; then
cp -a "$_l2r_bin" "${_l2r_bin}.proxmenux.bak"
pmx_edit_file "$_l2r_bin" 's/rsync -aAXv /rsync -aXv --no-acls /g'
fi
pmx_log2ram_drop_stale_journal "$_l2r_bin" || true
break
done
# Size-based rotation for the PBS API logs — the upstream package
# ships no logrotate rule and pvestatd's local-datastore poll fills
# them fast enough to saturate a tmpfs /var/log.
if dpkg-query -W -f='${Status}' proxmox-backup-server 2>/dev/null \
| grep -q 'install ok installed'; then
mkdir -p /var/log/proxmox-backup/api 2>/dev/null || true
pmx_write_file /etc/logrotate.d/proxmox-backup-api <<'EOF'
/var/log/proxmox-backup/api/access.log /var/log/proxmox-backup/api/auth.log {
size 20M
rotate 3
compress
missingok
notifempty
copytruncate
}
EOF
chmod 0644 /etc/logrotate.d/proxmox-backup-api
chown root:root /etc/logrotate.d/proxmox-backup-api
pmx_write_file /etc/cron.hourly/proxmox-backup-logrotate <<'EOF'
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1
EOF
chmod 0755 /etc/cron.hourly/proxmox-backup-logrotate
chown root:root /etc/cron.hourly/proxmox-backup-logrotate
msg_ok "$(translate "PBS API log rotation configured (hourly, size-based)")"
fi
systemctl daemon-reload >/dev/null 2>&1 || true
if [[ -f /etc/log2ram.conf ]] && command -v log2ram >/dev/null 2>&1; then
msg_ok "$(translate "Log2RAM installed successfully")"
else
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
return 1
fi
RAM_SIZE_GB=$(awk '/^MemTotal:/{print int($2/1024/1024)}' /proc/meminfo)
[[ -z "$RAM_SIZE_GB" || "$RAM_SIZE_GB" -eq 0 ]] && RAM_SIZE_GB=4
if (( RAM_SIZE_GB <= 8 )); then
LOG2RAM_SIZE="128M"; CRON_HOURS=1
elif (( RAM_SIZE_GB <= 16 )); then
LOG2RAM_SIZE="256M"; CRON_HOURS=3
else
LOG2RAM_SIZE="512M"; CRON_HOURS=6
fi
msg_ok "$(translate "Detected RAM:") $RAM_SIZE_GB GB — $(translate "Log2RAM size set to:") $LOG2RAM_SIZE"
pmx_edit_file /etc/log2ram.conf "s/^SIZE=.*/SIZE=$LOG2RAM_SIZE/"
LOG2RAM_BIN="$(command -v log2ram || echo /usr/sbin/log2ram)"
pmx_write_file /etc/cron.d/log2ram <<EOF
# Log2RAM periodic sync - Created by ProxMenux
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
0 */$CRON_HOURS * * * root $LOG2RAM_BIN write >/dev/null 2>&1
EOF
chmod 0644 /etc/cron.d/log2ram
chown root:root /etc/cron.d/log2ram
msg_ok "$(translate "Log2RAM write scheduled every") $CRON_HOURS $(translate "hour(s)")"
pmx_write_file /usr/local/bin/log2ram-check.sh <<'EOF'
#!/usr/bin/env bash
# Watch /var/log usage on Log2RAM's tmpfs and act at two thresholds:
# > 80% → vacuum journald down to ~30% of SIZE, then log2ram write
# > 92% → aggressive: journal to ~5%, rotate PBS API logs if present,
# truncate pveproxy/pveam, then log2ram write
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CONF_FILE="/etc/log2ram.conf"
L2R_BIN="$(command -v log2ram || true)"
[[ -z "$L2R_BIN" && -x /usr/sbin/log2ram ]] && L2R_BIN="/usr/sbin/log2ram"
[[ -z "$L2R_BIN" ]] && exit 0
SIZE_MiB="$(grep -E '^SIZE=' "$CONF_FILE" 2>/dev/null | cut -d'=' -f2 | tr -dc '0-9')"
[[ -z "$SIZE_MiB" ]] && SIZE_MiB=128
LIMIT_BYTES=$(( SIZE_MiB * 1024 * 1024 ))
WARN_BYTES=$(( LIMIT_BYTES * 80 / 100 ))
EMERGENCY_BYTES=$(( LIMIT_BYTES * 92 / 100 ))
USED_BYTES="$(df -B1 --output=used /var/log 2>/dev/null | tail -1 | tr -dc '0-9')"
[[ -z "$USED_BYTES" ]] && exit 0
LOCK="/run/log2ram-check.lock"
exec 9>"$LOCK" 2>/dev/null || exit 0
flock -n 9 || exit 0
if (( USED_BYTES > EMERGENCY_BYTES )); then
SAFE_JOURNAL_MB=$(( SIZE_MiB * 5 / 100 ))
[[ "$SAFE_JOURNAL_MB" -lt 16 ]] && SAFE_JOURNAL_MB=16
journalctl --vacuum-size="${SAFE_JOURNAL_MB}M" >/dev/null 2>&1 || true
if [[ -x /usr/sbin/logrotate && -f /etc/logrotate.d/proxmox-backup-api ]]; then
/usr/sbin/logrotate -f /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1 || true
fi
# Only truncate if the file already exists. Creating one from
# this cron path (running as root, default umask) would leave
# it as root:root 644 — pveproxy runs as www-data and would then
# fail to reopen it on the next restart, taking :8006 down.
[ -e /var/log/pveproxy/access.log ] && : > /var/log/pveproxy/access.log 2>/dev/null || true
[ -e /var/log/pveproxy/error.log ] && : > /var/log/pveproxy/error.log 2>/dev/null || true
[ -e /var/log/pveam.log ] && : > /var/log/pveam.log 2>/dev/null || true
"$L2R_BIN" write 2>/dev/null || true
elif (( USED_BYTES > WARN_BYTES )); then
SOFT_JOURNAL_MB=$(( SIZE_MiB * 30 / 100 ))
[[ "$SOFT_JOURNAL_MB" -lt 32 ]] && SOFT_JOURNAL_MB=32
journalctl --vacuum-size="${SOFT_JOURNAL_MB}M" >/dev/null 2>&1 || true
"$L2R_BIN" write 2>/dev/null || true
fi
EOF
chmod +x /usr/local/bin/log2ram-check.sh
pmx_write_file /etc/cron.d/log2ram-auto-sync <<'EOF'
# Log2RAM auto-sync based on /var/log usage - Created by ProxMenux
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
# nice/ionice keep the check off the priority queue for scheduled tasks.
3-59/10 * * * * root nice -n 19 ionice -c 3 /usr/local/bin/log2ram-check.sh >/dev/null 2>&1
EOF
chmod 0644 /etc/cron.d/log2ram-auto-sync
chown root:root /etc/cron.d/log2ram-auto-sync
systemctl restart cron >/dev/null 2>&1 || true
msg_ok "$(translate "Auto-sync enabled when /var/log exceeds 80% of") $LOG2RAM_SIZE"
msg_info "$(translate "Adjusting systemd-journald limits to match Log2RAM size...")"
if [[ -f /etc/systemd/journald.conf ]]; then
cp -n /etc/systemd/journald.conf /etc/systemd/journald.conf.bak.$(date +%Y%m%d-%H%M%S)
fi
SIZE_MB=$(echo "$LOG2RAM_SIZE" | tr -dc '0-9')
USE_MB=$(( SIZE_MB * 55 / 100 ))
KEEP_MB=$(( SIZE_MB * 10 / 100 ))
RUNTIME_MB=$(( SIZE_MB * 25 / 100 ))
[ "$USE_MB" -lt 80 ] && USE_MB=80
[ "$RUNTIME_MB" -lt 32 ] && RUNTIME_MB=32
[ "$KEEP_MB" -lt 8 ] && KEEP_MB=8
# Compose the final file and write it once: keep everything above the
# existing [Journal] section, then our block. Editing then appending
# produced two journal entries for one file, each with half the diff;
# one write shows the whole before/after a sysadmin should read.
{
sed '/^\[Journal\]/,$d' /etc/systemd/journald.conf 2>/dev/null
cat <<EOF
[Journal]
Storage=persistent
SplitMode=none
RateLimitIntervalSec=30s
RateLimitBurst=1000
ForwardToSyslog=no
ForwardToWall=no
Seal=no
Compress=yes
SystemMaxUse=${USE_MB}M
SystemKeepFree=${KEEP_MB}M
RuntimeMaxUse=${RUNTIME_MB}M
# MaxLevelStore=info: required for ProxMenux Monitor log display and Fail2Ban detection.
# Using "warning" silently discards most system logs making date filters useless.
MaxLevelStore=info
MaxLevelSyslog=info
MaxLevelKMsg=warning
MaxLevelConsole=notice
MaxLevelWall=crit
EOF
} | pmx_write_file /etc/systemd/journald.conf
mkdir -p /var/log/pveproxy
chown -R www-data:www-data /var/log/pveproxy
chmod 0750 /var/log/pveproxy
mkdir -p /var/log.hdd/pveproxy
chown -R www-data:www-data /var/log.hdd/pveproxy
chmod 0750 /var/log.hdd/pveproxy
#msg_ok "$(translate "Backup created:") /etc/systemd/journald.conf.bak.$(date +%Y%m%d-%H%M%S)"
msg_ok "$(translate "Journald configuration adjusted to") ${USE_MB}M (Log2RAM ${LOG2RAM_SIZE})"
systemctl daemon-reload >/dev/null 2>&1 || true
if ! pmx_apply_setting "service-enabled:log2ram" "systemctl is-enabled log2ram" \
systemctl enable log2ram; then
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
return 1
fi
pmx_log2ram_setup "$(pmx_log2ram_default_size)" "$(pmx_log2ram_default_hours)" true || return 1
NECESSARY_REBOOT=1
register_tool "log2ram" true "$FUNC_VERSION"
}
+12 -364
View File
@@ -73,6 +73,9 @@ fi
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
fi
if [[ -f "$LOCAL_SCRIPTS/global/log2ram_setup.sh" ]]; then
source "$LOCAL_SCRIPTS/global/log2ram_setup.sh"
fi
if [[ -f "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh" ]]; then
source "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh"
fi
@@ -3287,134 +3290,22 @@ update_pve_appliance_manager() {
_update_existing_log2ram_custom() {
local func_version="$1"
local log2ram_bin=""
local candidate resolved tmp_file
local watch=false
pmx_journal_context "_update_existing_log2ram_custom" "$func_version"
msg_ok "$(translate "Log2RAM already registered — updating to latest configuration")"
for candidate in \
"$(command -v log2ram 2>/dev/null)" \
/usr/local/bin/log2ram \
/usr/sbin/log2ram \
/usr/bin/log2ram
do
[[ -n "$candidate" && -f "$candidate" ]] || continue
resolved="$(readlink -f "$candidate" 2>/dev/null || printf '%s' "$candidate")"
[[ -f "$resolved" ]] || continue
log2ram_bin="$resolved"
break
done
if [[ -z "$log2ram_bin" || ! -f /etc/log2ram.conf ]]; then
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
return 1
fi
if grep -q 'rsync -aAXv ' "$log2ram_bin" 2>/dev/null; then
[[ -e "${log2ram_bin}.proxmenux.bak" ]] || cp -a "$log2ram_bin" "${log2ram_bin}.proxmenux.bak"
sed 's/rsync -aAXv /rsync -aXv --no-acls /g' "$log2ram_bin" | pmx_write_file "$log2ram_bin"
fi
if pmx_log2ram_drop_stale_journal "$log2ram_bin"; then
NECESSARY_REBOOT=1
msg_ok "$(translate "Log2RAM keeps the journal in order from the next reboot")"
fi
if dpkg-query -W -f='${Status}' proxmox-backup-server 2>/dev/null \
| grep -q 'install ok installed'; then
tmp_file="$(mktemp /etc/logrotate.d/.proxmox-backup-api.XXXXXX)" || return 1
cat > "$tmp_file" <<'EOF'
/var/log/proxmox-backup/api/access.log /var/log/proxmox-backup/api/auth.log {
size 20M
rotate 3
compress
missingok
notifempty
copytruncate
}
EOF
chmod 0644 "$tmp_file"
chown root:root "$tmp_file"
pmx_write_file /etc/logrotate.d/proxmox-backup-api < "$tmp_file"
rm -f "$tmp_file"
tmp_file="$(mktemp /etc/cron.hourly/.proxmox-backup-logrotate.XXXXXX)" || return 1
cat > "$tmp_file" <<'EOF'
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1
EOF
chmod 0755 "$tmp_file"
chown root:root "$tmp_file"
pmx_write_file /etc/cron.hourly/proxmox-backup-logrotate < "$tmp_file"
chmod 0755 /etc/cron.hourly/proxmox-backup-logrotate
chown root:root /etc/cron.hourly/proxmox-backup-logrotate
rm -f "$tmp_file"
msg_ok "$(translate "PBS API log rotation configured (hourly, size-based)")"
fi
if [[ -f /usr/local/bin/log2ram-check.sh ]]; then
tmp_file="$(mktemp /usr/local/bin/.log2ram-check.XXXXXX)" || return 1
cat > "$tmp_file" <<'EOF'
#!/usr/bin/env bash
# Watch /var/log usage on Log2RAM's tmpfs and act at two thresholds:
# > 80% → vacuum journald down to ~30% of SIZE, then log2ram write
# > 92% → aggressive: journal to ~5%, rotate PBS API logs if present,
# truncate existing pveproxy/pveam logs, then log2ram write
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CONF_FILE="/etc/log2ram.conf"
L2R_BIN="$(command -v log2ram || true)"
[[ -z "$L2R_BIN" && -x /usr/sbin/log2ram ]] && L2R_BIN="/usr/sbin/log2ram"
[[ -z "$L2R_BIN" ]] && exit 0
SIZE_MiB="$(grep -E '^SIZE=' "$CONF_FILE" 2>/dev/null | cut -d'=' -f2 | tr -dc '0-9')"
[[ -z "$SIZE_MiB" ]] && SIZE_MiB=128
LIMIT_BYTES=$(( SIZE_MiB * 1024 * 1024 ))
WARN_BYTES=$(( LIMIT_BYTES * 80 / 100 ))
EMERGENCY_BYTES=$(( LIMIT_BYTES * 92 / 100 ))
USED_BYTES="$(df -B1 --output=used /var/log 2>/dev/null | tail -1 | tr -dc '0-9')"
[[ -z "$USED_BYTES" ]] && exit 0
LOCK="/run/log2ram-check.lock"
exec 9>"$LOCK" 2>/dev/null || exit 0
flock -n 9 || exit 0
if (( USED_BYTES > EMERGENCY_BYTES )); then
SAFE_JOURNAL_MB=$(( SIZE_MiB * 5 / 100 ))
[[ "$SAFE_JOURNAL_MB" -lt 16 ]] && SAFE_JOURNAL_MB=16
journalctl --vacuum-size="${SAFE_JOURNAL_MB}M" >/dev/null 2>&1 || true
if [[ -x /usr/sbin/logrotate && -f /etc/logrotate.d/proxmox-backup-api ]]; then
/usr/sbin/logrotate -f /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1 || true
fi
[ -e /var/log/pveproxy/access.log ] && : > /var/log/pveproxy/access.log 2>/dev/null || true
[ -e /var/log/pveproxy/error.log ] && : > /var/log/pveproxy/error.log 2>/dev/null || true
[ -e /var/log/pveam.log ] && : > /var/log/pveam.log 2>/dev/null || true
"$L2R_BIN" write 2>/dev/null || true
elif (( USED_BYTES > WARN_BYTES )); then
SOFT_JOURNAL_MB=$(( SIZE_MiB * 30 / 100 ))
[[ "$SOFT_JOURNAL_MB" -lt 32 ]] && SOFT_JOURNAL_MB=32
journalctl --vacuum-size="${SOFT_JOURNAL_MB}M" >/dev/null 2>&1 || true
"$L2R_BIN" write 2>/dev/null || true
fi
EOF
chmod 0755 "$tmp_file"
chown root:root "$tmp_file"
bash -n "$tmp_file" || return 1
pmx_write_file /usr/local/bin/log2ram-check.sh < "$tmp_file"
chmod 0755 /usr/local/bin/log2ram-check.sh
chown root:root /usr/local/bin/log2ram-check.sh
rm -f "$tmp_file"
fi
[[ -f /etc/cron.d/log2ram-auto-sync ]] && watch=true
pmx_log2ram_setup "$(pmx_log2ram_current_size)" "$(pmx_log2ram_current_hours)" "$watch" || return 1
NECESSARY_REBOOT=1
register_tool "log2ram" true "$func_version"
msg_success "$(translate "Log2RAM installation and configuration completed successfully.")"
}
configure_log2ram() {
local FUNC_VERSION="1.8"
local FUNC_VERSION="2.0"
local existing_log2ram_bin=""
local watch=false
pmx_journal_context "configure_log2ram" "$FUNC_VERSION"
# description: Install Log2RAM with a chosen size, sync interval and optional autosync. Updates preserve the size and autosync choice.
@@ -3429,7 +3320,6 @@ configure_log2ram() {
msg_info2 "$(translate "Preparing Log2RAM configuration")"
sleep 1
RAM_SIZE_GB=$(awk '/^MemTotal:/{print int($2/1024/1024)}' /proc/meminfo)
[[ -z "$RAM_SIZE_GB" || "$RAM_SIZE_GB" -eq 0 ]] && RAM_SIZE_GB=4
@@ -3467,254 +3357,12 @@ configure_log2ram() {
"12" "$(translate "Every 12 hours")" OFF \
3>&1 1>&2 2>&3) || return 0
if whiptail --title "Log2RAM" --yesno "$(translate "Enable auto-sync if /var/log exceeds 90% of its size?")" 10 60; then
ENABLE_AUTOSYNC=true
else
ENABLE_AUTOSYNC=false
if whiptail --title "Log2RAM" --yesno "$(translate "Rotate and write /var/log to disk when it passes 85% of its size?")" 10 60; then
watch=true
fi
msg_info "$(translate "Cleaning previous Log2RAM installation...")"
pmx_disable_service log2ram || true
pmx_disable_service log2ram-daily.timer || true
local obsolete_path
for obsolete_path in \
/etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync \
/etc/cron.hourly/log2ram /etc/cron.daily/log2ram \
/etc/cron.weekly/log2ram /etc/cron.monthly/log2ram \
/usr/local/bin/log2ram-check.sh /usr/local/bin/log2ram /usr/sbin/log2ram \
/etc/systemd/system/log2ram.service \
/etc/systemd/system/log2ram-daily.timer \
/etc/systemd/system/log2ram-daily.service \
/etc/systemd/system/sysinit.target.wants/log2ram.service \
/etc/log2ram.conf /etc/log2ram.conf.* /etc/logrotate.d/log2ram
do
pmx_remove_file "$obsolete_path" 2>/dev/null || true
done
rm -rf /etc/systemd/system/log2ram.service.d 2>/dev/null || true
rm -rf /var/log.hdd /tmp/log2ram 2>/dev/null || true
systemctl daemon-reload >/dev/null 2>&1 || true
systemctl restart cron >/dev/null 2>&1 || true
msg_ok "$(translate "Previous installation cleaned")"
msg_info "$(translate "Installing Log2RAM from GitHub...")"
if ! command -v git >/dev/null 2>&1; then
msg_info "$(translate "Installing required package: git")"
apt-get update -qq >/dev/null 2>&1
pmx_install_pkg git
fi
rm -rf /tmp/log2ram 2>/dev/null || true
if ! git clone --depth 1 https://github.com/azlux/log2ram.git /tmp/log2ram \
>/dev/null 2>>/tmp/log2ram_install.log; then
msg_error "$(translate "Failed to clone log2ram repository. Check /tmp/log2ram_install.log")"
return 1
fi
cd /tmp/log2ram || { msg_error "$(translate "Failed to access log2ram directory")"; return 1; }
if ! bash install.sh >>/tmp/log2ram_install.log 2>&1; then
msg_error "$(translate "Failed to run log2ram installer. Check /tmp/log2ram_install.log")"
return 1
fi
# Drop ACL preservation from the upstream rsync call: some
# /var/log.hdd filesystems reject POSIX ACLs and log2ram write
# exits 23 with `set_acl: Operation not supported`. xattrs stay.
local _l2r_bin
for _l2r_bin in \
"$(command -v log2ram 2>/dev/null)" \
/usr/local/bin/log2ram \
/usr/sbin/log2ram \
/usr/bin/log2ram
do
[[ -n "$_l2r_bin" && -f "$_l2r_bin" ]] || continue
if grep -q 'rsync -aAXv ' "$_l2r_bin" 2>/dev/null; then
cp -a "$_l2r_bin" "${_l2r_bin}.proxmenux.bak"
pmx_edit_file "$_l2r_bin" 's/rsync -aAXv /rsync -aXv --no-acls /g'
fi
pmx_log2ram_drop_stale_journal "$_l2r_bin" || true
break
done
# Size-based rotation for the PBS API logs — the upstream package
# ships no logrotate rule and pvestatd's local-datastore poll fills
# them fast enough to saturate a tmpfs /var/log.
if dpkg-query -W -f='${Status}' proxmox-backup-server 2>/dev/null \
| grep -q 'install ok installed'; then
mkdir -p /var/log/proxmox-backup/api 2>/dev/null || true
pmx_write_file /etc/logrotate.d/proxmox-backup-api <<'EOF'
/var/log/proxmox-backup/api/access.log /var/log/proxmox-backup/api/auth.log {
size 20M
rotate 3
compress
missingok
notifempty
copytruncate
}
EOF
chmod 0644 /etc/logrotate.d/proxmox-backup-api
chown root:root /etc/logrotate.d/proxmox-backup-api
pmx_write_file /etc/cron.hourly/proxmox-backup-logrotate <<'EOF'
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1
EOF
chmod 0755 /etc/cron.hourly/proxmox-backup-logrotate
chown root:root /etc/cron.hourly/proxmox-backup-logrotate
msg_ok "$(translate "PBS API log rotation configured (hourly, size-based)")"
fi
systemctl daemon-reload >/dev/null 2>&1 || true
if [[ -f /etc/log2ram.conf ]] && command -v log2ram >/dev/null 2>&1; then
msg_ok "$(translate "Log2RAM installed successfully")"
else
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
return 1
fi
pmx_edit_file /etc/log2ram.conf "s/^SIZE=.*/SIZE=$LOG2RAM_SIZE/"
LOG2RAM_BIN="$(command -v log2ram || echo /usr/sbin/log2ram)"
pmx_write_file /etc/cron.d/log2ram <<EOF
# Log2RAM periodic sync - Created by ProxMenux
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
0 */$CRON_HOURS * * * root $LOG2RAM_BIN write >/dev/null 2>&1
EOF
chmod 0644 /etc/cron.d/log2ram
chown root:root /etc/cron.d/log2ram
msg_ok "$(translate "Log2RAM write scheduled every") $CRON_HOURS $(translate "hour(s)")"
if [[ "$ENABLE_AUTOSYNC" == true ]]; then
pmx_write_file /usr/local/bin/log2ram-check.sh <<'EOF'
#!/usr/bin/env bash
# Watch /var/log usage on Log2RAM's tmpfs and act at two thresholds:
# > 80% → vacuum journald down to ~30% of SIZE, then log2ram write
# > 92% → aggressive: journal to ~5%, rotate PBS API logs if present,
# truncate existing pveproxy/pveam logs, then log2ram write
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CONF_FILE="/etc/log2ram.conf"
L2R_BIN="$(command -v log2ram || true)"
[[ -z "$L2R_BIN" && -x /usr/sbin/log2ram ]] && L2R_BIN="/usr/sbin/log2ram"
[[ -z "$L2R_BIN" ]] && exit 0
SIZE_MiB="$(grep -E '^SIZE=' "$CONF_FILE" 2>/dev/null | cut -d'=' -f2 | tr -dc '0-9')"
[[ -z "$SIZE_MiB" ]] && SIZE_MiB=128
LIMIT_BYTES=$(( SIZE_MiB * 1024 * 1024 ))
WARN_BYTES=$(( LIMIT_BYTES * 80 / 100 ))
EMERGENCY_BYTES=$(( LIMIT_BYTES * 92 / 100 ))
USED_BYTES="$(df -B1 --output=used /var/log 2>/dev/null | tail -1 | tr -dc '0-9')"
[[ -z "$USED_BYTES" ]] && exit 0
LOCK="/run/log2ram-check.lock"
exec 9>"$LOCK" 2>/dev/null || exit 0
flock -n 9 || exit 0
if (( USED_BYTES > EMERGENCY_BYTES )); then
SAFE_JOURNAL_MB=$(( SIZE_MiB * 5 / 100 ))
[[ "$SAFE_JOURNAL_MB" -lt 16 ]] && SAFE_JOURNAL_MB=16
journalctl --vacuum-size="${SAFE_JOURNAL_MB}M" >/dev/null 2>&1 || true
if [[ -x /usr/sbin/logrotate && -f /etc/logrotate.d/proxmox-backup-api ]]; then
/usr/sbin/logrotate -f /etc/logrotate.d/proxmox-backup-api >/dev/null 2>&1 || true
fi
[ -e /var/log/pveproxy/access.log ] && : > /var/log/pveproxy/access.log 2>/dev/null || true
[ -e /var/log/pveproxy/error.log ] && : > /var/log/pveproxy/error.log 2>/dev/null || true
[ -e /var/log/pveam.log ] && : > /var/log/pveam.log 2>/dev/null || true
"$L2R_BIN" write 2>/dev/null || true
elif (( USED_BYTES > WARN_BYTES )); then
SOFT_JOURNAL_MB=$(( SIZE_MiB * 30 / 100 ))
[[ "$SOFT_JOURNAL_MB" -lt 32 ]] && SOFT_JOURNAL_MB=32
journalctl --vacuum-size="${SOFT_JOURNAL_MB}M" >/dev/null 2>&1 || true
"$L2R_BIN" write 2>/dev/null || true
fi
EOF
chmod +x /usr/local/bin/log2ram-check.sh
pmx_write_file /etc/cron.d/log2ram-auto-sync <<'EOF'
# Log2RAM auto-sync based on /var/log usage - Created by ProxMenux
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
# nice/ionice keep the check off the priority queue for scheduled tasks.
3-59/10 * * * * root nice -n 19 ionice -c 3 /usr/local/bin/log2ram-check.sh >/dev/null 2>&1
EOF
chmod 0644 /etc/cron.d/log2ram-auto-sync
chown root:root /etc/cron.d/log2ram-auto-sync
msg_ok "$(translate "Auto-sync enabled when /var/log exceeds 80% of") $LOG2RAM_SIZE"
else
pmx_remove_file /usr/local/bin/log2ram-check.sh 2>/dev/null || true
pmx_remove_file /etc/cron.d/log2ram-auto-sync 2>/dev/null || true
msg_info2 "$(translate "Auto-sync was not enabled")"
fi
# --- Ajuste de systemd-journald proporcional al tamaño de Log2RAM ---
msg_info "$(translate "Adjusting systemd-journald limits to match Log2RAM size...")"
if [[ -f /etc/systemd/journald.conf ]]; then
cp -n /etc/systemd/journald.conf "/etc/systemd/journald.conf.bak.$(date +%Y%m%d-%H%M%S)"
BAK_OK=$?
fi
SIZE_MB=$(echo "$LOG2RAM_SIZE" | tr -dc '0-9')
# Repartos: 55% persistente / 10% libre / 25% runtime (pisos mínimos)
USE_MB=$(( SIZE_MB * 55 / 100 ))
KEEP_MB=$(( SIZE_MB * 10 / 100 ))
RUNTIME_MB=$(( SIZE_MB * 25 / 100 ))
[ "$USE_MB" -lt 80 ] && USE_MB=80
[ "$RUNTIME_MB" -lt 32 ] && RUNTIME_MB=32
[ "$KEEP_MB" -lt 8 ] && KEEP_MB=8
# Reescribir bloque [Journal] de forma segura
pmx_edit_file /etc/systemd/journald.conf '/^\[Journal\]/,$d' 2>/dev/null || true
pmx_append_file /etc/systemd/journald.conf <<EOF
[Journal]
Storage=persistent
SplitMode=none
RateLimitIntervalSec=30s
RateLimitBurst=1000
ForwardToSyslog=no
ForwardToWall=no
Seal=no
Compress=yes
SystemMaxUse=${USE_MB}M
SystemKeepFree=${KEEP_MB}M
RuntimeMaxUse=${RUNTIME_MB}M
# MaxLevelStore=info: required for ProxMenux Monitor log display and Fail2Ban detection.
# Using "warning" silently discards most system logs making date filters useless.
MaxLevelStore=info
MaxLevelSyslog=info
MaxLevelKMsg=warning
MaxLevelConsole=notice
MaxLevelWall=crit
EOF
[[ "$BAK_OK" = "0" ]] && msg_ok "$(translate "Backup created:") /etc/systemd/journald.conf.bak.$(date +%Y%m%d-%H%M%S)"
msg_ok "$(translate "Journald configuration adjusted to") ${USE_MB}M (Log2RAM ${LOG2RAM_SIZE})"
mkdir -p /var/log/pveproxy
chown -R www-data:www-data /var/log/pveproxy
chmod 0750 /var/log/pveproxy
mkdir -p /var/log.hdd/pveproxy
chown -R www-data:www-data /var/log.hdd/pveproxy
chmod 0750 /var/log.hdd/pveproxy
systemctl restart cron >/dev/null 2>&1 || true
if ! pmx_apply_setting "service-enabled:log2ram" "systemctl is-enabled log2ram" \
systemctl enable log2ram; then
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
return 1
fi
pmx_log2ram_setup "$USER_SIZE" "$CRON_HOURS" "$watch" || return 1
NECESSARY_REBOOT=1
msg_success "$(translate "Log2RAM installation and configuration completed successfully.")"
register_tool "log2ram" true "$FUNC_VERSION"
}
+6 -68
View File
@@ -37,6 +37,9 @@ fi
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
fi
if [[ -f "$LOCAL_SCRIPTS/global/log2ram_setup.sh" ]]; then
source "$LOCAL_SCRIPTS/global/log2ram_setup.sh"
fi
if [[ -f "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh" ]]; then
source "$LOCAL_SCRIPTS/post_install/zram_profile_helpers.sh"
fi
@@ -735,74 +738,9 @@ uninstall_bashrc_custom() {
################################################################
uninstall_log2ram() {
msg_info "$(translate "Uninstalling log2ram (all versions)...")"
systemctl stop log2ram log2ram-daily.timer log2ram-daily.service >/dev/null 2>&1 || true
systemctl disable log2ram log2ram-daily.timer log2ram-daily.service >/dev/null 2>&1 || true
rm -f /etc/cron.d/log2ram \
/etc/cron.d/log2ram-auto-sync \
/etc/cron.d/log2ram-sync \
/etc/cron.hourly/log2ram \
/etc/cron.daily/log2ram \
/etc/cron.weekly/log2ram \
/etc/cron.monthly/log2ram 2>/dev/null || true
rm -f /usr/local/bin/log2ram-check.sh \
/usr/local/bin/log2ram \
/usr/local/bin/log2ram-sync \
/usr/sbin/log2ram \
/usr/bin/log2ram 2>/dev/null || true
rm -f /etc/systemd/system/log2ram.service \
/etc/systemd/system/log2ram-daily.timer \
/etc/systemd/system/log2ram-daily.service \
/etc/systemd/system/sysinit.target.wants/log2ram.service \
/etc/systemd/system/timers.target.wants/log2ram-daily.timer \
/lib/systemd/system/log2ram.service \
/lib/systemd/system/log2ram-daily.timer \
/lib/systemd/system/log2ram-daily.service 2>/dev/null || true
rm -rf /etc/systemd/system/log2ram.service.d 2>/dev/null || true
rm -f /etc/log2ram.conf \
/etc/log2ram.conf.dpkg-old \
/etc/log2ram.conf.bak \
/etc/log2ram.conf.save 2>/dev/null || true
rm -rf /etc/logrotate.d/log2ram 2>/dev/null || true
if mountpoint -q /var/log 2>/dev/null; then
if [[ -d /var/log.hdd ]]; then
msg_info "$(translate "Preserving logs to /var/log.hdd before unmounting...")"
rsync -a /var/log/ /var/log.hdd/ >/dev/null 2>&1 || true
fi
umount /var/log >/dev/null 2>&1 || true
fi
[[ -d /var/log.hdd ]] && rm -rf /var/log.hdd
[[ -d /tmp/log2ram ]] && rm -rf /tmp/log2ram
[[ -d /var/hdd.log ]] && rm -rf /var/hdd.log
[[ -f /tmp/log2ram_install.log ]] && rm -f /tmp/log2ram_install.log
systemctl daemon-reload >/dev/null 2>&1 || true
systemctl reset-failed >/dev/null 2>&1 || true
systemctl restart cron >/dev/null 2>&1 || true
if dpkg -l 2>/dev/null | grep -q '^ii log2ram'; then
msg_info "$(translate "Purging log2ram apt package...")"
apt-get purge -y log2ram >/dev/null 2>&1 || true
apt-get autoremove -y >/dev/null 2>&1 || true
fi
if [[ -f /etc/log2ram.conf ]] || \
command -v log2ram >/dev/null 2>&1 || \
systemctl list-units --all 2>/dev/null | grep -q log2ram || \
[[ -f /etc/cron.d/log2ram-auto-sync ]]; then
msg_warn "$(translate "Some log2ram files may still exist. Manual cleanup may be required.")"
else
msg_ok "$(translate "log2ram completely removed from system")"
fi
msg_info "$(translate "Uninstalling Log2RAM...")"
pmx_log2ram_remove
msg_ok "$(translate "Log2RAM is removed at the next reboot, after writing /var/log to disk")"
register_tool "log2ram" false
NECESSARY_REBOOT=1
}
+126
View File
@@ -0,0 +1,126 @@
"""Exercise only the update confirmation widget in a disposable terminal.
No update script is sourced or executed: the isolated UI command receives
synthetic package names. Requires dialog; skips on systems without it.
"""
import errno
import fcntl
import os
from pathlib import Path
import pty
import re
import select
import shutil
import signal
import struct
import termios
import time
import unittest
ROOT = Path(__file__).resolve().parents[1]
UPDATERS = (
"update-pve8.sh",
"update-pve9_2.sh",
"update-pve-safe.sh",
)
def confirmation_command(name):
source = (ROOT / "scripts/global" / name).read_text()
match = re.search(
r'^\s*if (?:! )?((?:dialog|whiptail) --(?:keep-tite --)?title '
r'"\$\(translate "Proxmox Update"\)"[^;]+); then',
source,
re.MULTILINE,
)
if not match:
raise AssertionError("Update confirmation not found: " + name)
return match.group(1)
def run_widget(command, text, keys):
child, terminal = pty.fork()
if child == 0:
fcntl.ioctl(1, termios.TIOCSWINSZ, struct.pack("HHHH", 30, 100, 0, 0))
environment = dict(os.environ, TERM="xterm-256color", LC_ALL="C",
DIALOGRC="/dev/null", UPDATE_CONFIRMATION_TEXT=text)
# Exit-code overrides must not leak into this isolated test.
for key in list(environment):
if key.startswith("DIALOG_"):
environment.pop(key)
script = ('translate() { printf "%s" "$1"; }\n'
'menu_text=$UPDATE_CONFIRMATION_TEXT\n' + command)
os.execve("/bin/bash", ["bash", "-c", script], environment)
output = bytearray()
sent = False
status = None
deadline = time.monotonic() + 8
try:
while time.monotonic() < deadline:
if select.select([terminal], [], [], 0.1)[0]:
try:
chunk = os.read(terminal, 65536)
except OSError as error:
if error.errno != errno.EIO:
raise
chunk = b""
output.extend(chunk)
# The widget is ready once both buttons have been drawn.
plain = re.sub(rb"\x1b(?:\[[0-?]*[ -/]*[@-~]|[()][A-Za-z0-9]|.)", b"", output)
if not sent and b"Yes" in plain and b"No" in plain:
os.write(terminal, keys)
sent = True
finished, result = os.waitpid(child, os.WNOHANG)
if finished:
status = os.waitstatus_to_exitcode(result)
break
if status is None:
raise AssertionError("Confirmation did not respond to keyboard input: " + repr(bytes(output[-2000:])))
return status, bytes(output)
finally:
if status is None:
try:
os.kill(child, signal.SIGKILL)
except ProcessLookupError:
pass
os.waitpid(child, 0)
os.close(terminal)
@unittest.skipUnless(shutil.which("dialog"), "dialog is not installed")
class UpdateConfirmationTest(unittest.TestCase):
def test_enter_confirms_yes_without_tab_for_short_and_long_lists(self):
for updater in UPDATERS:
for count in (1, 80):
with self.subTest(updater=updater, packages=count):
text = "System Update Information\\n\\n" + "\\n".join(
" package-{:02d} 1.0 -> 2.0".format(i)
for i in range(count)
) + "\\n\\nDo you want to proceed with the system update?"
status, output = run_widget(confirmation_command(updater), text, b"\r")
self.assertEqual(status, 0, output)
def test_tab_can_select_no_and_escape_can_cancel(self):
for updater in UPDATERS:
for keys, expected in ((b"\t\r", 1), (b"\x1b", 255)):
with self.subTest(updater=updater, keys=keys):
status, output = run_widget(confirmation_command(updater), "Confirm update?", keys)
self.assertEqual(status, expected, output)
def test_full_list_remains_scrollable_with_yes_focused(self):
text = "\\n".join("package-{:03d}".format(i) for i in range(80))
for updater in UPDATERS:
with self.subTest(updater=updater):
# G scrolls to the end of the yes/no text without moving focus.
status, output = run_widget(confirmation_command(updater), text, b"G\r")
self.assertEqual(status, 0, output)
# Curses may repaint only changed digits rather than emit a
# complete final line. Its 100% indicator confirms the end.
self.assertIn(b"100%", output)
if __name__ == "__main__":
unittest.main()
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (SSD-bewusst, auto)",
"what": "Reduziert SSD-/NVMe-Verschleiß durch Verschieben von /var/log in eine tmpfs-RAM-Disk mit regelmäßiger Synchronisierung auf Datenträger. Installation aus dem Upstream-Projekt bei SSD oder NVMe als Systemplatte. Die Größe richtet sich nach dem Host-RAM (128M / 256M / 512M). Ein Schutz leert alte Journale ab 80% Belegung und kürzt stark wachsende Logs ab 92% vor dem Schreiben. Regelmäßige Synchronisierung wird geplant und journald an den verfügbaren Platz angepasst. Details unter <link>Log2RAM</link>.",
"what": "Reduziert SSD-/NVMe-Verschleiß durch Verschieben von /var/log in eine tmpfs-RAM-Disk, die nach Zeitplan auf den Datenträger geschrieben wird. Installation aus dem Upstream-Projekt bei SSD oder NVMe als Systemplatte. Die Größe richtet sich nach dem Host-RAM (128M / 256M / 512M); eine Überwachung rotiert und schreibt die Logs, wenn die RAM-Disk 85 % überschreitet. Das Journal und die Task-Logs von Proxmox VE und Proxmox Backup Server bleiben auf dem Datenträger. Alle Details unter <link>Log2RAM</link>.",
"category": "Speicher",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Hardwareabhängige Standardwerte",
"hardwareBody": "Das Skript liest die Host-Hardware vor dem Anwenden von Einstellungen. Log2RAM ist standardmäßig nur auf SSD / NVMe Root-Festplatten installiert (es wird aufgefordert, wenn die Erkennung etwas anderes sagt). Die Ramdisk-Größe von Log2RAM wird aus der Gesamt-RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>) ausgewählt. Die Journald-Limits werden an die Ramdisk-Größe angepasst, wenn Log2RAM aktiv ist, um ein Ausfüllen zu vermeiden.",
"hardwareBody": "Das Skript liest die Host-Hardware vor dem Anwenden von Einstellungen. Log2RAM ist standardmäßig nur auf SSD / NVMe Root-Festplatten installiert (es wird aufgefordert, wenn die Erkennung etwas anderes sagt). Die Ramdisk-Größe von Log2RAM wird aus der Gesamt-RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>) ausgewählt. Bei aktivem Log2RAM bleibt das Journal mit eigener Grenze auf dem Datenträger.",
"upgrade": {
"heading": "Paketlisten und System aktualisieren",
"intro": "Der erste Schritt der automatisierten Nachinstallation ist das Proxmox-Upgrade. Für einen laufenden Host innerhalb derselben Hauptversion empfiehlt Proxmox selbst:",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Log2RAM installieren (SSD/NVMe Verschleißreduzierung)",
"intro": "Log2RAM bindet <code>/var/log</code> als tmpfs-RAM-Disk ein und synchronisiert regelmäßig auf den Datenträger. Das Puffern häufiger journald-Schreibvorgänge im RAM kann SSD-Verschleiß und Datenträger-I/O verringern. Synchronisierung und sauberes Herunterfahren sichern die Logs; bei abruptem Stromausfall können Einträge seit der letzten Synchronisierung verloren gehen.",
"intro": "Log2RAM bindet <code>/var/log</code> als tmpfs-RAM-Disk ein und schreibt sie nach Zeitplan auf den Datenträger, sodass ständig wechselnde Logs wie das Zugriffslog von pveproxy in den RAM statt auf die System-SSD geschrieben werden. Das Journal und die Task-Logs von Proxmox VE und Proxmox Backup Server bleiben auf dem Datenträger. Ein sauberes Herunterfahren schreibt die RAM-Disk auf den Datenträger; bei einem abrupten Stromausfall gehen nur die seit der letzten Synchronisierung geschriebenen Textlogs verloren.",
"upstreamLabel": "Vorgelagertes Projekt:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram auf GitHub",
"doesLabel": "Was ProxMenux tut:",
"doesItems": [
"Erkennt anhand von <code>/sys/block/&lt;dev&gt;/queue/rotational</code>, ob die Systemplatte SSD/NVMe ist. Bei einer rotierenden Festplatte fragt die automatisierte Variante vor der Installation nach.",
"Klont das Originalprojekt (<code>azlux/log2ram</code>) nach <code>/tmp/log2ram</code> und passt <code>install.sh</code> an: <code>rsync -aAXv</code> wird durch <code>rsync -aXv --no-acls</code> ersetzt. Dadurch wird der Fehler <em>set_acl: Operation not supported</em> mit Exitcode 23 vermieden, der beim Verschieben von /var/log auf Dateisystemen ohne ACL-Unterstützung auftreten kann. Die systemd-Unit <code>log2ram</code> wird nach Installation aktiviert.",
"Installiert Log2RAM 1.7.2 aus dem Upstream-Projekt, prüft, dass der Download genau diese Version ist, und lässt den Code unverändert. Die Fehler-E-Mail wird mit <code>NOTIFICATION=false</code> abgeschaltet, da Proxmox VE keinen Mail-Befehl mitbringt.",
"Größe der Ramdisk auf Basis des Hosts RAM: <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Schreibt den Wert in <code>SIZE=</code> in <code>/etc/log2ram.conf</code>.",
"Plant eine regelmäßige Datenträgersynchronisierung über <code>/etc/cron.d/log2ram</code>: alle 1 / 3 / 6 Stunden entsprechend derselben RAM-Stufe.",
"Installiert den Schutz <code>/usr/local/bin/log2ram-check.sh</code>, der über <code>/etc/cron.d/log2ram-auto-sync</code> alle 10 Minuten läuft. Bei 80% Belegung von <code>/var/log</code> bereinigt er journald. Bei 92% führt er zunächst <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code> aus, falls die Datei existiert: Die PBS-API-Logs sind oft der größte Platzverbraucher auf einem PBS-Host. Danach kürzt er <code>pveproxy access/error</code> und <code>pveam.log</code> vor der Synchronisierung. <code>log2ram write</code> allein kopiert tmpfs auf Disk, verkleinert es aber nicht. Der Schutz hilft gegen PVE-Ausfälle mit <em>No space left on device</em> durch unkontrolliertes Logwachstum.",
"Erkennt den Dienst <code>proxmox-backup-server</code> auf dem Host. Falls vorhanden, erstellt es <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 Rotationen) und <code>/etc/cron.hourly/proxmox-backup-logrotate</code>, damit die häufig stark wachsenden PBS-API-Logs auch zwischen Log2RAM-Synchronisierungen begrenzt werden. Ohne PBS erfolgt keine Änderung.",
"Stellt systemd-journald-Grenzwerte (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) so ein, dass sie in die Ramdisk passen, so dass ein einzelner Burst sie nicht füllen kann.",
"Wird in <code>installed_tools.json</code> erfasst und kann über Optimierungen deinstallieren rückgängig gemacht werden."
"Hält das Journal (<code>/var/log/journal</code>), die Task-Logs von Proxmox VE (<code>/var/log/pve</code>) und, falls installiert, die Logs von Proxmox Backup Server (<code>/var/log/proxmox-backup</code>) auf dem Datenträger, in <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> und <code>/var/hdd.proxmox-backup</code>. Jeder übliche Pfad wird zu einem Link auf seinen Ordner auf dem Datenträger. Die Verschiebung erfolgt beim Start, bevor Log2RAM startet.",
"Schreibt die RAM-Disk mit dem Log2RAM-Timer alle 1 / 3 / 6 Stunden entsprechend derselben RAM-Stufe auf den Datenträger und leert nach jedem Schreiben den Datenträger-Cache, sodass eine abgeschlossene Synchronisierung einen Stromausfall übersteht.",
"Installiert eine Überwachung in <code>/etc/cron.d/log2ram-auto-sync</code>, die alle 10 Minuten läuft. Überschreitet <code>/var/log</code> 85 % der RAM-Disk, rotiert sie die Logs, komprimiert die gerade rotierten und schreibt alles auf den Datenträger. Kein Log wird geleert.",
"Hält das systemd-Journal mit einer Grenze von 1 GB auf dem Datenträger, in <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. Auf einem Host mit Proxmox Backup Server kommt <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 Rotationen) für dessen API-Logs hinzu.",
"Registriert sich in <code>installed_tools.json</code>, damit es über Optimierungen deinstallieren rückgängig gemacht werden kann. Ein Update von einer früheren Version behält Größe und Synchronisierungsintervall bei und verlegt das Journal beim nächsten Start auf den Datenträger."
],
"howUseLabel": "Wie zu verwenden:",
"howUseBody": "Die automatisierte Variante installiert Log2RAM unbeaufsichtigt bei erkanntem SSD-/NVMe-Systemlaufwerk. Die anpassbare Variante fragt nach Größe, Intervall und Auto-Sync-Schutz. Die Abfrage nennt derzeit 90%, das erzeugte Skript nutzt jedoch 80% für Bereinigung und 92% für die oben beschriebene intensive Bereinigung.",
"howUseBody": "Die automatisierte Variante installiert Log2RAM unbeaufsichtigt bei erkanntem SSD-/NVMe-Systemlaufwerk. Die anpassbare Variante fragt nach Größe, Synchronisierungsintervall und ob die Überwachung aktiviert werden soll. Die Änderungen werden beim nächsten Start wirksam.",
"verifyLabel": "Überprüfen und Verwalten aus der Shell:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "ZRAM-Swap-Profil aktivieren",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Stoppt und deaktiviert Dienst und Timer. Entfernt Cron-Jobs, systemd-Units, Programmdateien, Konfiguration und /var/log.hdd. Entfernt auch das apt-Paket, falls darüber installiert."
"restores": "Deaktiviert Dienst und Timer und entfernt die ProxMenux-Konfiguration von Log2RAM. Beim nächsten Herunterfahren schreibt Log2RAM /var/log auf den Datenträger; beim nächsten Start kehren das Journal und die Task-Logs nach /var/log zurück und die Log2RAM-Dateien werden entfernt."
},
{
"tool": "Automatisches ZFS-TRIM",
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (SSD-aware, auto)",
"what": "Reduces SSD/NVMe wear by moving /var/log to a tmpfs ramdisk with periodic disk sync. Installed from the upstream project when the root disk is SSD or NVMe. Sizes the ramdisk by host RAM (128M / 256M / 512M), schedules periodic sync and an auto-sync guard that vacuums at 80% and truncates hot logs at 92% before writing. Adjusts journald limits to fit in the ramdisk. Full details on <link>Log2RAM</link>.",
"what": "Reduces SSD/NVMe wear by moving /var/log to a tmpfs ramdisk that is written to disk on a schedule. Installed from the upstream project when the root disk is SSD or NVMe. Sizes the ramdisk by host RAM (128M / 256M / 512M) and adds a guard that rotates and writes the logs when the ramdisk passes 85%. The journal and the task logs of Proxmox VE and Proxmox Backup Server stay on disk. Full details on <link>Log2RAM</link>.",
"category": "Storage",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Hardware-aware defaults",
"hardwareBody": "The script reads the host hardware before applying settings. Log2RAM is only installed on SSD / NVMe root disks by default (it prompts if detection says otherwise). Log2RAM ramdisk size is picked from total RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). The journald limits are matched to the ramdisk size when Log2RAM is active, to avoid filling it.",
"hardwareBody": "The script reads the host hardware before applying settings. Log2RAM is only installed on SSD / NVMe root disks by default (it prompts if detection says otherwise). Log2RAM ramdisk size is picked from total RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). When Log2RAM is active, the journal stays on disk with its own limit.",
"upgrade": {
"heading": "Update and upgrade system",
"intro": "The very first step of the Automated bundle is the Proxmox upgrade. Proxmox's own upgrade guidance for a running host (within the same major version) is to run:",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Install Log2RAM (SSD/NVMe wear reduction)",
"intro": "Log2RAM mounts <code>/var/log</code> on a tmpfs ramdisk and periodically syncs it to the underlying disk. Buffering frequent journald writes in RAM can reduce root SSD wear and disk I/O. Periodic sync and a clean shutdown save logs to disk, but an abrupt power loss can lose entries written since the last sync.",
"intro": "Log2RAM mounts <code>/var/log</code> on a tmpfs ramdisk and writes it to disk on a schedule, so the logs that change all the time, such as the pveproxy access log, are written to RAM instead of the root SSD. The journal and the task logs of Proxmox VE and Proxmox Backup Server stay on disk. A clean shutdown writes the ramdisk to disk; an abrupt power loss loses only the text logs written since the last sync.",
"upstreamLabel": "Upstream project:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram on GitHub",
"doesLabel": "What ProxMenux does:",
"doesItems": [
"Detects whether the root disk is SSD/NVMe by reading <code>/sys/block/&lt;dev&gt;/queue/rotational</code>. On a rotational disk the Automated flow asks first before installing.",
"Clones the upstream repository (<code>azlux/log2ram</code>) into <code>/tmp/log2ram</code> and patches its <code>install.sh</code>, replacing <code>rsync -aAXv</code> with <code>rsync -aXv --no-acls</code>. That adjustment avoids the <em>set_acl: Operation not supported</em> exit 23 failure that the vanilla script triggers when moving /var/log on filesystems without ACL support. The <code>log2ram</code> systemd unit is enabled after install.",
"Installs Log2RAM 1.7.2 from the upstream project, checking that the download is that release, and leaves its code unchanged. Its error e-mail is turned off with <code>NOTIFICATION=false</code>, as Proxmox VE has no mail command by default.",
"Sizes the ramdisk based on host RAM: <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Writes the value to <code>SIZE=</code> in <code>/etc/log2ram.conf</code>.",
"Schedules a periodic disk sync via <code>/etc/cron.d/log2ram</code>: every 1h / 3h / 6h according to the same RAM tier.",
"Installs an auto-sync guard at <code>/usr/local/bin/log2ram-check.sh</code>, wired to <code>/etc/cron.d/log2ram-auto-sync</code> to run every 10 minutes. When <code>/var/log</code> reaches 80% of the ramdisk size the guard vacuums journald; at 92% it first runs <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code> when that file exists (forcing rotation of the PBS API logs, typically the largest consumer on a host running PBS) and then truncates <code>pveproxy access/error</code> and <code>pveam.log</code> before syncing. The plain <code>log2ram write</code> command copies tmpfs to disk but does NOT shrink the tmpfs, so this guard prevents PVE from crashing with <em>No space left on device</em> when logs grow uncontrolled.",
"Detects whether <code>proxmox-backup-server</code> runs as a service on the host. When present, drops <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 rotation) and <code>/etc/cron.hourly/proxmox-backup-logrotate</code>, so the PBS API logs — the usual source of growth on a PBS host — stay bounded even between Log2RAM's periodic syncs. On hosts without PBS this step is a no-op.",
"Adjusts systemd-journald limits (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) to fit within the ramdisk so a single burst cannot fill it.",
"Registers itself in <code>installed_tools.json</code> so it can be reverted from Uninstall Optimizations."
"Keeps on disk the journal (<code>/var/log/journal</code>), the Proxmox VE task logs (<code>/var/log/pve</code>) and, where it is installed, the Proxmox Backup Server logs (<code>/var/log/proxmox-backup</code>), in <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> and <code>/var/hdd.proxmox-backup</code>. Each usual path becomes a link to its folder on disk. The move happens at boot, before Log2RAM starts.",
"Writes the ramdisk to disk with the Log2RAM timer every 1h / 3h / 6h according to the same RAM tier, and flushes the disk after each write, so a finished sync survives a power cut.",
"Installs a guard in <code>/etc/cron.d/log2ram-auto-sync</code> that runs every 10 minutes. When <code>/var/log</code> passes 85% of the ramdisk, it rotates the logs, compresses the ones just rotated and writes everything to disk. No log is emptied.",
"Keeps the systemd journal on disk with a 1 GB limit, in <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. On a host running Proxmox Backup Server, adds <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 rotation) for its API logs.",
"Registers itself in <code>installed_tools.json</code> so it can be reverted from Uninstall Optimizations. An update from an earlier version keeps the size and sync interval, and moves the journal to disk at the next boot."
],
"howUseLabel": "How to use:",
"howUseBody": "On the Automated flow Log2RAM installs unattended when an SSD/NVMe root is detected. The Customizable flow asks for size, sync interval and whether to enable the auto-sync guard. Its prompt currently says 90%, but the generated guard uses the 80% cleanup and 92% aggressive thresholds described above.",
"howUseBody": "On the Automated flow Log2RAM installs unattended when an SSD/NVMe root is detected. The Customizable flow asks for size, sync interval and whether to enable the guard. The changes take effect at the next boot.",
"verifyLabel": "Verify and manage from the shell:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "Enable ZRAM swap profile",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Stops and disables the service and timer. Purges cron jobs, systemd units, binaries, config files and the /var/log.hdd directory. Also uninstalls the apt package if it was installed that way."
"restores": "Disables the service and timer and removes the ProxMenux configuration of Log2RAM. At the next shutdown Log2RAM writes /var/log to disk; at the next boot the journal and the task logs return to /var/log and the Log2RAM files are removed."
},
{
"tool": "ZFS autotrim",
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (según el SSD, automático)",
"what": "Reduce el desgaste del SSD/NVMe moviendo /var/log a una ramdisk tmpfs con sync periódico al disco. Se instala desde el proyecto oficial cuando el disco raíz es SSD o NVMe. Dimensiona la ramdisk según la RAM (128M / 256M / 512M), programa el sync periódico y un guardián de auto-sync que compacta al 80% y trunca los logs calientes al 92% antes de escribir. Ajusta los límites de journald para caber en la ramdisk. Detalle completo en <link>Log2RAM</link>.",
"what": "Reduce el desgaste del SSD/NVMe moviendo /var/log a una ramdisk tmpfs que se escribe en disco de forma programada. Se instala desde el proyecto oficial cuando el disco raíz es SSD o NVMe. Dimensiona la ramdisk según la RAM del host (128M / 256M / 512M) y añade una vigilancia que rota y escribe los logs cuando la ramdisk supera el 85%. El journal y los registros de tareas de Proxmox VE y Proxmox Backup Server se quedan en disco. Todos los detalles en <link>Log2RAM</link>.",
"category": "Almacenamiento",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Valores predeterminados adaptados al hardware",
"hardwareBody": "El script lee el hardware del host antes de aplicar los ajustes. Log2RAM solo se instala en discos raíz SSD / NVMe por defecto (pregunta si la detección dice lo contrario). El tamaño del ramdisk de Log2RAM se elige a partir de la RAM total (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Los límites de journald se ajustan al tamaño del ramdisk cuando Log2RAM está activo, para no llenarlo.",
"hardwareBody": "El script lee el hardware del host antes de aplicar los ajustes. Log2RAM solo se instala en discos raíz SSD / NVMe por defecto (pregunta si la detección dice lo contrario). El tamaño del ramdisk de Log2RAM se elige a partir de la RAM total (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Con Log2RAM activo, el journal se queda en disco con su propio límite.",
"upgrade": {
"heading": "Actualizar y hacer upgrade del sistema",
"intro": "El primer paso del bundle Automatizado es el upgrade de Proxmox. La guía oficial de Proxmox para hacer upgrade de un host en ejecución (dentro de la misma versión mayor) es ejecutar:",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Instalar Log2RAM (reducción de desgaste en SSD/NVMe)",
"intro": "Log2RAM monta <code>/var/log</code> en una ramdisk tmpfs y lo sincroniza periódicamente al disco. Almacenar temporalmente en RAM las escrituras frecuentes de journald puede reducir el desgaste del SSD y la E/S. La sincronización y un apagado limpio guardan los registros, pero un corte brusco puede perder las entradas posteriores a la última sincronización.",
"intro": "Log2RAM monta <code>/var/log</code> en una ramdisk tmpfs y la escribe en disco de forma programada, de modo que los registros que cambian constantemente, como el log de accesos de pveproxy, se escriben en RAM en lugar de en el SSD raíz. El journal y los registros de tareas de Proxmox VE y Proxmox Backup Server se quedan en disco. Un apagado limpio escribe la ramdisk en disco; un corte de luz brusco solo pierde los logs de texto escritos desde la última sincronización.",
"upstreamLabel": "Proyecto oficial:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram en GitHub",
"doesLabel": "Qué hace ProxMenux:",
"doesItems": [
"Detecta si el disco raíz es SSD/NVMe leyendo <code>/sys/block/&lt;dev&gt;/queue/rotational</code>. En un disco rotacional el flujo Automatizado pregunta antes de instalar.",
"Clona el repositorio oficial (<code>azlux/log2ram</code>) en <code>/tmp/log2ram</code> y aplica un patch a su <code>install.sh</code>, sustituyendo <code>rsync -aAXv</code> por <code>rsync -aXv --no-acls</code>. Ese ajuste evita el fallo <em>set_acl: Operation not supported</em> con exit 23 que el script vanilla produce al mover /var/log en sistemas de archivos sin soporte de ACLs. La unit systemd <code>log2ram</code> se habilita después de la instalación.",
"Instala Log2RAM 1.7.2 desde el proyecto oficial, comprobando que lo descargado es esa versión, y deja su código sin modificar. Su correo de error se desactiva con <code>NOTIFICATION=false</code>, ya que Proxmox VE no incluye un comando de correo.",
"Dimensiona la ramdisk según la RAM del host: <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Escribe el valor en <code>SIZE=</code> de <code>/etc/log2ram.conf</code>.",
"Programa una sincronización periódica a disco vía <code>/etc/cron.d/log2ram</code>: cada 1h / 3h / 6h según el mismo tramo de RAM.",
"Instala un guardián de auto-sync en <code>/usr/local/bin/log2ram-check.sh</code>, conectado a <code>/etc/cron.d/log2ram-auto-sync</code> para ejecutarse cada 10 minutos. Cuando <code>/var/log</code> alcanza el 80% del tamaño de la ramdisk el guardián compacta journald; al 92% primero ejecuta <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code> si ese archivo existe (para forzar la rotación de los logs del API de PBS, que suelen ser los que más crecen en un host con PBS) y a continuación trunca <code>pveproxy access/error</code> y <code>pveam.log</code> antes de sincronizar. El comando <code>log2ram write</code> por sí solo copia tmpfs a disco pero NO reduce la tmpfs, así que este guardián evita que PVE caiga con <em>No space left on device</em> cuando los logs crecen sin control.",
"Detecta si <code>proxmox-backup-server</code> corre como servicio en el host. Cuando está presente, deposita <code>/etc/logrotate.d/proxmox-backup-api</code> (rotación de 20 MB × 3) y <code>/etc/cron.hourly/proxmox-backup-logrotate</code>, de forma que los logs del API de PBS — el origen habitual del crecimiento en un host con PBS — queden acotados incluso entre las sincronizaciones periódicas de Log2RAM. En hosts sin PBS este paso es un no-op.",
"Ajusta los límites de systemd-journald (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) para que quepan en la ramdisk y así una ráfaga puntual no la llene.",
"Se registra en <code>installed_tools.json</code> para poder revertirlo desde Desinstalar optimizaciones."
"Mantiene en disco el journal (<code>/var/log/journal</code>), los registros de tareas de Proxmox VE (<code>/var/log/pve</code>) y, si está instalado, los de Proxmox Backup Server (<code>/var/log/proxmox-backup</code>), en <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> y <code>/var/hdd.proxmox-backup</code>. Cada ruta habitual pasa a ser un enlace a su carpeta en disco. El traslado se hace al arrancar, antes de que se inicie Log2RAM.",
"Escribe la ramdisk en disco con el temporizador de Log2RAM cada 1h / 3h / 6h según el mismo tramo de RAM, y vuelca el disco después de cada escritura, de modo que una sincronización terminada sobrevive a un corte de luz.",
"Instala una vigilancia en <code>/etc/cron.d/log2ram-auto-sync</code> que se ejecuta cada 10 minutos. Cuando <code>/var/log</code> supera el 85% de la ramdisk, rota los logs, comprime los recién rotados y escribe todo en disco. No vacía ningún log.",
"Mantiene el journal de systemd en disco con un límite de 1 GB, en <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. En un host con Proxmox Backup Server, añade <code>/etc/logrotate.d/proxmox-backup-api</code> (rotación de 20 MB × 3) para sus logs de la API.",
"Se registra en <code>installed_tools.json</code> para poder revertirse desde Desinstalar optimizaciones. Una actualización desde una versión anterior conserva el tamaño y el intervalo de sincronización, y lleva el journal a disco en el siguiente arranque."
],
"howUseLabel": "Cómo se usa:",
"howUseBody": "En el flujo automatizado Log2RAM se instala sin intervención al detectar un disco raíz SSD/NVMe. El personalizable pregunta por tamaño, intervalo y activación del auxiliar de sincronización. El mensaje indica 90%, pero el auxiliar generado usa los umbrales de limpieza del 80% y actuación intensiva del 92% descritos arriba.",
"howUseBody": "En el flujo automatizado Log2RAM se instala sin intervención al detectar un disco raíz SSD/NVMe. El personalizable pregunta por el tamaño, el intervalo de sincronización y si activar la vigilancia. Los cambios se aplican en el siguiente arranque.",
"verifyLabel": "Verificar y gestionar desde la shell:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "Activar el perfil de swap con ZRAM",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Para y desactiva el servicio y el timer. Purga cron jobs, units systemd, binarios, archivos de configuración y el directorio /var/log.hdd. También desinstala el paquete apt si se instaló por esa vía."
"restores": "Desactiva el servicio y el temporizador y elimina la configuración de ProxMenux para Log2RAM. En el siguiente apagado Log2RAM escribe /var/log en disco; en el siguiente arranque el journal y los registros de tareas vuelven a /var/log y se eliminan los ficheros de Log2RAM."
},
{
"tool": "TRIM automático de ZFS",
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (adapté aux SSD, automatique)",
"what": "Réduit l’usure SSD/NVMe en déplaçant /var/log dans un disque RAM tmpfs synchronisé régulièrement vers le disque. Installation depuis le projet amont si le disque racine est SSD ou NVMe. Taille selon la RAM de l’hôte (128M / 256M / 512M), synchronisation périodique et protection automatique qui purge les anciens journaux à 80% et tronque les journaux très actifs à 92% avant écriture. Adapte les limites journald au disque RAM. Détails dans <link>Log2RAM</link>.",
"what": "Réduit l'usure du SSD/NVMe en déplaçant /var/log vers un ramdisk tmpfs écrit sur le disque selon un calendrier. Installé depuis le projet officiel lorsque le disque système est un SSD ou un NVMe. Dimensionne le ramdisk selon la RAM de l'hôte (128M / 256M / 512M) et ajoute une surveillance qui fait tourner et écrit les journaux lorsque le ramdisk dépasse 85 %. Le journal et les journaux de tâches de Proxmox VE et de Proxmox Backup Server restent sur le disque. Tous les détails dans <link>Log2RAM</link>.",
"category": "Stockage",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Valeurs par défaut adaptées au matériel",
"hardwareBody": "Le script examine le matériel avant de configurer l’hôte. Par défaut, Log2RAM s’installe uniquement si le disque racine est SSD ou NVMe ; il demande confirmation sinon. La taille du disque RAM dépend de la RAM totale (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Quand Log2RAM est actif, les limites journald sont adaptées au disque RAM pour éviter de le remplir.",
"hardwareBody": "Le script examine le matériel avant de configurer l’hôte. Par défaut, Log2RAM s’installe uniquement si le disque racine est SSD ou NVMe ; il demande confirmation sinon. La taille du disque RAM dépend de la RAM totale (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Lorsque Log2RAM est actif, le journal reste sur le disque avec sa propre limite.",
"upgrade": {
"heading": "Mettre à jour les listes de paquets et le système",
"intro": "La première étape du parcours automatisé est la mise à niveau Proxmox. Pour un hôte en fonctionnement au sein de la même version majeure, Proxmox recommande :",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Installer Log2RAM (SSD/NVMe réduction de l'usure)",
"intro": "Log2RAM monte <code>/var/log</code> sur un disque RAM tmpfs et le synchronise régulièrement vers le disque. Mettre en mémoire les écritures journald fréquentes peut réduire l’usure SSD et les E/S. La synchronisation et un arrêt propre sauvegardent les journaux ; une coupure brutale peut perdre les entrées depuis la dernière synchronisation.",
"intro": "Log2RAM monte <code>/var/log</code> sur un ramdisk tmpfs et l'écrit sur le disque selon un calendrier, de sorte que les journaux qui changent en permanence, comme le journal d'accès de pveproxy, sont écrits en RAM plutôt que sur le SSD système. Le journal et les journaux de tâches de Proxmox VE et de Proxmox Backup Server restent sur le disque. Un arrêt propre écrit le ramdisk sur le disque ; une coupure de courant brutale ne fait perdre que les journaux texte écrits depuis la dernière synchronisation.",
"upstreamLabel": "Projet en amont:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram sur GitHub",
"doesLabel": "Que fait ProxMenux:",
"doesItems": [
"Détecte si le disque racine est SSD/NVMe en lisant <code>/sys/block/&lt;dev&gt;/queue/rotational</code>. Sur un disque rotatif, le flux automatisé demande d'abord avant d'installer.",
"Clone le dépôt original (<code>azlux/log2ram</code>) dans <code>/tmp/log2ram</code> et modifie <code>install.sh</code> en remplaçant <code>rsync -aAXv</code> par <code>rsync -aXv --no-acls</code>. Cela évite l’erreur <em>set_acl: Operation not supported</em> avec code de sortie 23, déclenchée par le script original lors du déplacement de /var/log sur un système sans ACL. L’unité systemd <code>log2ram</code> est activée après installation.",
"Installe Log2RAM 1.7.2 depuis le projet officiel, en vérifiant que le téléchargement correspond à cette version, sans modifier son code. Son e-mail d'erreur est désactivé avec <code>NOTIFICATION=false</code>, car Proxmox VE n'inclut pas de commande mail.",
"Dimensionne le disque RAM selon la mémoire de l’hôte : <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Écrit la valeur dans <code>SIZE=</code> de <code>/etc/log2ram.conf</code>.",
"Planifie une synchronisation périodique du disque via <code>/etc/cron.d/log2ram</code> : toutes les 1h / 3h / 6h selon le même niveau RAM.",
"Installe <code>/usr/local/bin/log2ram-check.sh</code>, lancé toutes les 10 minutes par <code>/etc/cron.d/log2ram-auto-sync</code>. Quand <code>/var/log</code> atteint 80% du disque RAM, il purge les anciens journaux journald. À 92%, il lance d’abord <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code> si le fichier existe : les journaux API PBS occupent souvent le plus d’espace sur un hôte PBS. Il tronque ensuite <code>pveproxy access/error</code> et <code>pveam.log</code> avant synchronisation. <code>log2ram write</code> seul copie tmpfs sur disque sans le réduire. Cette protection aide à éviter un arrêt de PVE avec <em>No space left on device</em> lorsque les journaux grossissent sans contrôle.",
"Détecte le service <code>proxmox-backup-server</code> sur l’hôte. S’il est présent, crée <code>/etc/logrotate.d/proxmox-backup-api</code> (20 Mo × 3 rotations) et <code>/etc/cron.hourly/proxmox-backup-logrotate</code> pour limiter les journaux API PBS, souvent à l’origine de la croissance, même entre les synchronisations Log2RAM. Sans PBS, cette étape ne change rien.",
"Ajuste les limites systemd-journald (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) pour qu'elles s'adaptent au disque virtuel afin qu'une seule rafale ne puisse pas le remplir.",
"S’enregistre dans <code>installed_tools.json</code> pour pouvoir être annulé via Désinstaller les optimisations."
"Conserve sur le disque le journal (<code>/var/log/journal</code>), les journaux de tâches de Proxmox VE (<code>/var/log/pve</code>) et, s'il est installé, ceux de Proxmox Backup Server (<code>/var/log/proxmox-backup</code>), dans <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> et <code>/var/hdd.proxmox-backup</code>. Chaque chemin habituel devient un lien vers son dossier sur le disque. Le déplacement a lieu au démarrage, avant que Log2RAM ne démarre.",
"Écrit le ramdisk sur le disque avec le minuteur de Log2RAM toutes les 1 h / 3 h / 6 h selon le même palier de RAM, et vide le cache disque après chaque écriture, de sorte qu'une synchronisation terminée résiste à une coupure de courant.",
"Installe une surveillance dans <code>/etc/cron.d/log2ram-auto-sync</code> exécutée toutes les 10 minutes. Lorsque <code>/var/log</code> dépasse 85 % du ramdisk, elle effectue la rotation des journaux, compresse ceux qui viennent d'être tournés et écrit le tout sur le disque. Aucun journal n'est vidé.",
"Conserve le journal systemd sur le disque avec une limite de 1 Go, dans <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. Sur un hôte exécutant Proxmox Backup Server, ajoute <code>/etc/logrotate.d/proxmox-backup-api</code> (rotation 20 Mo × 3) pour ses journaux d'API.",
"S'enregistre dans <code>installed_tools.json</code> afin de pouvoir être annulé depuis Désinstaller les optimisations. Une mise à jour depuis une version antérieure conserve la taille et l'intervalle de synchronisation, et déplace le journal sur le disque au démarrage suivant."
],
"howUseLabel": "Comment utiliser:",
"howUseBody": "Le parcours automatisé installe Log2RAM sans intervention si le disque racine est SSD/NVMe. Le parcours personnalisable demande taille, intervalle et activation de la protection. L’invite indique actuellement 90%, mais le script généré utilise les seuils de nettoyage à 80% et intensif à 92% décrits plus haut.",
"howUseBody": "Dans le flux automatisé, Log2RAM s'installe sans intervention lorsqu'un disque système SSD/NVMe est détecté. Le flux personnalisable demande la taille, l'intervalle de synchronisation et s'il faut activer la surveillance. Les changements prennent effet au démarrage suivant.",
"verifyLabel": "Vérifier et gérer à partir du shell:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "Activer le profil d'échange ZRAM",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Arrête et désactive le service et le minuteur. Supprime tâches cron, unités systemd, binaires, configuration et /var/log.hdd. Désinstalle aussi le paquet apt si cette méthode a été utilisée."
"restores": "Désactive le service et le minuteur et supprime la configuration ProxMenux de Log2RAM. À l'arrêt suivant, Log2RAM écrit /var/log sur le disque ; au démarrage suivant, le journal et les journaux de tâches reviennent dans /var/log et les fichiers de Log2RAM sont supprimés."
},
{
"tool": "TRIM automatique ZFS",
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (ottimizzato per SSD, automatico)",
"what": "Riduce l’usura SSD/NVMe spostando /var/log in un ramdisk tmpfs sincronizzato periodicamente sul disco. Installazione dal progetto upstream quando il disco root è SSD o NVMe. Dimensione in base alla RAM dell’host (128M / 256M / 512M), sincronizzazione periodica e protezione automatica che elimina vecchi journal all’80% e tronca i log molto attivi al 92% prima della scrittura. Adatta i limiti journald al ramdisk. Dettagli su <link>Log2RAM</link>.",
"what": "Riduce l'usura di SSD/NVMe spostando /var/log su un ramdisk tmpfs che viene scritto su disco a intervalli programmati. Viene installato dal progetto ufficiale quando il disco di sistema è SSD o NVMe. Dimensiona il ramdisk in base alla RAM dell'host (128M / 256M / 512M) e aggiunge un controllo che ruota e scrive i log quando il ramdisk supera l'85%. Il journal e i log delle attività di Proxmox VE e Proxmox Backup Server restano su disco. Tutti i dettagli in <link>Log2RAM</link>.",
"category": "Archiviazione",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Impostazioni predefinite in base all’hardware",
"hardwareBody": "Lo script legge l'hardware dell'host prima di applicare le impostazioni. Log2RAM è installato solo su dischi SSD/root NVMe per impostazione predefinita (richiede se il rilevamento indica diversamente). La dimensione del disco ram Log2RAM viene scelta dal totale RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). I limiti del journald vengono adattati alla dimensione del ramdisk quando Log2RAM è attivo, per evitare di riempirlo.",
"hardwareBody": "Lo script legge l'hardware dell'host prima di applicare le impostazioni. Log2RAM è installato solo su dischi SSD/root NVMe per impostazione predefinita (richiede se il rilevamento indica diversamente). La dimensione del disco ram Log2RAM viene scelta dal totale RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Con Log2RAM attivo, il journal resta su disco con un proprio limite.",
"upgrade": {
"heading": "Aggiorna gli elenchi dei pacchetti e il sistema",
"intro": "Il primo passo del pacchetto automatizzato è l'aggiornamento Proxmox. La guida di aggiornamento di Proxmox per un host in esecuzione (nella stessa versione principale) è quella di eseguire:",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Installare Log2RAM (SSD/NVMe riduzione dell'usura)",
"intro": "Log2RAM monta <code>/var/log</code> su un ramdisk tmpfs e lo sincronizza periodicamente sul disco. Accumulare in RAM le frequenti scritture journald può ridurre usura SSD e I/O. Sincronizzazione e arresto regolare salvano i log, ma una perdita improvvisa di alimentazione può perdere le voci dall’ultima sincronizzazione.",
"intro": "Log2RAM monta <code>/var/log</code> su un ramdisk tmpfs e lo scrive su disco a intervalli programmati, così i log che cambiano di continuo, come il log degli accessi di pveproxy, vengono scritti in RAM invece che sull'SSD di sistema. Il journal e i log delle attività di Proxmox VE e Proxmox Backup Server restano su disco. Uno spegnimento pulito scrive il ramdisk su disco; un'interruzione di corrente improvvisa fa perdere solo i log di testo scritti dopo l'ultima sincronizzazione.",
"upstreamLabel": "Progetto a monte:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram su GitHub",
"doesLabel": "Cosa fa ProxMenux:",
"doesItems": [
"Rileva se il disco root è SSD/NVMe leggendo <code>/sys/block/&lt;dev&gt;/queue/rotational</code>. Su un disco rotazionale il flusso automatizzato chiede prima di installare.",
"Clona il repository originale (<code>azlux/log2ram</code>) in <code>/tmp/log2ram</code> e modifica <code>install.sh</code>, sostituendo <code>rsync -aAXv</code> con <code>rsync -aXv --no-acls</code>. Evita l’errore <em>set_acl: Operation not supported</em> con codice di uscita 23, che lo script originale genera spostando /var/log su filesystem senza ACL. L’unità systemd <code>log2ram</code> viene abilitata dopo l’installazione.",
"Installa Log2RAM 1.7.2 dal progetto ufficiale, verificando che il download sia quella versione, e lascia il suo codice invariato. L'email di errore viene disattivata con <code>NOTIFICATION=false</code>, poiché Proxmox VE non include un comando mail.",
"Dimensiona il ramdisk in base alla RAM dell’host: <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Scrive il valore in <code>SIZE=</code> di <code>/etc/log2ram.conf</code>.",
"Pianifica una sincronizzazione periodica del disco tramite <code>/etc/cron.d/log2ram</code>: ogni 1h / 3h / 6h secondo lo stesso livello RAM.",
"Installa <code>/usr/local/bin/log2ram-check.sh</code>, eseguito ogni 10 minuti da <code>/etc/cron.d/log2ram-auto-sync</code>. Quando <code>/var/log</code> raggiunge l’80% del ramdisk, pulisce i vecchi journal. Al 92% esegue prima <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code> se il file esiste: i log API PBS sono spesso i maggiori consumatori di spazio su un host PBS. Poi tronca <code>pveproxy access/error</code> e <code>pveam.log</code> prima della sincronizzazione. <code>log2ram write</code> da solo copia tmpfs sul disco senza ridurlo. La protezione aiuta a evitare arresti di PVE con <em>No space left on device</em> per crescita incontrollata dei log.",
"Rileva il servizio <code>proxmox-backup-server</code> sull’host. Se presente, crea <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 rotazioni) e <code>/etc/cron.hourly/proxmox-backup-logrotate</code> per limitare i log API PBS, abituale fonte di crescita, anche tra le sincronizzazioni Log2RAM. Senza PBS non modifica nulla.",
"Regola i limiti systemd-journald (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) per adattarsi all'interno del ramdisk in modo che un singolo scoppio non possa riempirlo.",
"Si registra in <code>installed_tools.json</code> per consentire il ripristino da Disinstalla ottimizzazioni."
"Mantiene su disco il journal (<code>/var/log/journal</code>), i log delle attività di Proxmox VE (<code>/var/log/pve</code>) e, se installato, quelli di Proxmox Backup Server (<code>/var/log/proxmox-backup</code>), in <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> e <code>/var/hdd.proxmox-backup</code>. Ogni percorso abituale diventa un collegamento alla sua cartella su disco. Lo spostamento avviene all'avvio, prima che parta Log2RAM.",
"Scrive il ramdisk su disco con il timer di Log2RAM ogni 1h / 3h / 6h secondo la stessa fascia di RAM, e svuota la cache del disco dopo ogni scrittura, così una sincronizzazione completata sopravvive a un'interruzione di corrente.",
"Installa un controllo in <code>/etc/cron.d/log2ram-auto-sync</code> eseguito ogni 10 minuti. Quando <code>/var/log</code> supera l'85% del ramdisk, ruota i log, comprime quelli appena ruotati e scrive tutto su disco. Nessun log viene svuotato.",
"Mantiene il journal di systemd su disco con un limite di 1 GB, in <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. Su un host con Proxmox Backup Server aggiunge <code>/etc/logrotate.d/proxmox-backup-api</code> (rotazione 20 MB × 3) per i suoi log delle API.",
"Si registra in <code>installed_tools.json</code> per poter essere annullato da Disinstalla ottimizzazioni. Un aggiornamento da una versione precedente mantiene la dimensione e l'intervallo di sincronizzazione e sposta il journal su disco al successivo avvio."
],
"howUseLabel": "Come usare:",
"howUseBody": "Il percorso automatizzato installa Log2RAM senza intervento se rileva un disco root SSD/NVMe. Quello personalizzabile chiede dimensione, intervallo e attivazione della protezione. Il messaggio indica 90%, ma lo script generato usa le soglie di pulizia all’80% e intensiva al 92% descritte sopra.",
"howUseBody": "Nel flusso automatico Log2RAM si installa senza intervento quando rileva un disco di sistema SSD/NVMe. Il flusso personalizzabile chiede la dimensione, l'intervallo di sincronizzazione e se attivare il controllo. Le modifiche hanno effetto al successivo avvio.",
"verifyLabel": "Verificare e gestire dalla shell:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "Abilita il profilo di scambio ZRAM",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Ferma e disabilita servizio e timer. Elimina processi cron, unità systemd, binari, configurazione e /var/log.hdd. Rimuove anche il pacchetto apt se installato in quel modo."
"restores": "Disattiva il servizio e il timer e rimuove la configurazione di ProxMenux per Log2RAM. Al successivo spegnimento Log2RAM scrive /var/log su disco; al successivo avvio il journal e i log delle attività tornano in /var/log e i file di Log2RAM vengono rimossi."
},
{
"tool": "TRIM automatico ZFS",
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (adaptado a SSD, automático)",
"what": "Reduz o desgaste SSD/NVMe movendo /var/log para um ramdisk tmpfs com sincronização periódica para disco. Instalação a partir do projeto original quando o disco raiz é SSD ou NVMe. Dimensiona pela RAM do host (128M / 256M / 512M), agenda sincronização periódica e proteção automática que limpa journals antigos aos 80% e trunca registos muito ativos aos 92% antes de gravar. Ajusta limites journald ao ramdisk. Detalhes em <link>Log2RAM</link>.",
"what": "Reduz o desgaste do SSD/NVMe movendo /var/log para um ramdisk tmpfs gravado no disco de forma programada. É instalado a partir do projeto oficial quando o disco do sistema é SSD ou NVMe. Dimensiona o ramdisk segundo a RAM do host (128M / 256M / 512M) e adiciona uma vigilância que rotaciona e grava os logs quando o ramdisk ultrapassa 85%. O journal e os logs de tarefas do Proxmox VE e do Proxmox Backup Server ficam no disco. Todos os detalhes em <link>Log2RAM</link>.",
"category": "Armazenamento",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Predefinições adaptadas ao hardware",
"hardwareBody": "O script lê o hardware do host antes de aplicar as configurações. Log2RAM é instalado apenas em discos raiz SSD / NVMe por padrão (ele avisa se a detecção indicar o contrário). O tamanho do ramdisk Log2RAM é escolhido do total RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Os limites journald correspondem ao tamanho do disco RAM quando Log2RAM está ativo, para evitar preenchê-lo.",
"hardwareBody": "O script lê o hardware do host antes de aplicar as configurações. Log2RAM é instalado apenas em discos raiz SSD / NVMe por padrão (ele avisa se a detecção indicar o contrário). O tamanho do ramdisk Log2RAM é escolhido do total RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Com o Log2RAM ativo, o journal fica no disco com o seu próprio limite.",
"upgrade": {
"heading": "Atualizar listas de pacotes e sistema",
"intro": "O primeiro passo do percurso automatizado é atualizar o Proxmox. Para um host em funcionamento dentro da mesma versão principal, o Proxmox recomenda:",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Instalar Log2RAM (redução do desgaste de SSD/NVMe)",
"intro": "Log2RAM monta <code>/var/log</code> num ramdisk tmpfs e sincroniza-o periodicamente para disco. Guardar temporariamente na RAM as escritas frequentes do journald pode reduzir desgaste SSD e E/S. A sincronização e o encerramento normal guardam os registos; um corte abrupto pode perder entradas desde a última sincronização.",
"intro": "O Log2RAM monta <code>/var/log</code> num ramdisk tmpfs e grava-o no disco de forma programada, para que os logs que mudam constantemente, como o log de acessos do pveproxy, sejam gravados na RAM em vez do SSD do sistema. O journal e os logs de tarefas do Proxmox VE e do Proxmox Backup Server ficam no disco. Um desligamento limpo grava o ramdisk no disco; uma queda de energia abrupta perde apenas os logs de texto gravados desde a última sincronização.",
"upstreamLabel": "Projeto a montante:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram em GitHub",
"doesLabel": "O que o ProxMenux faz:",
"doesItems": [
"Detecta se o disco raiz é SSD/NVMe lendo <code>/sys/block/&lt;dev&gt;/queue/rotational</code>. Em um disco rotacional o fluxo automatizado pede primeiro antes de instalar.",
"Clona o repositório original (<code>azlux/log2ram</code>) para <code>/tmp/log2ram</code> e modifica <code>install.sh</code>, substituindo <code>rsync -aAXv</code> por <code>rsync -aXv --no-acls</code>. Evita o erro <em>set_acl: Operation not supported</em> com código de saída 23, gerado pelo script original ao mover /var/log em sistemas sem ACL. A unidade systemd <code>log2ram</code> é ativada após instalação.",
"Instala o Log2RAM 1.7.2 a partir do projeto oficial, verificando que o download é essa versão, e mantém o seu código inalterado. O e-mail de erro é desativado com <code>NOTIFICATION=false</code>, pois o Proxmox VE não inclui um comando de e-mail.",
"Dimensiona o ramdisk pela RAM do host: <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Escreve o valor em <code>SIZE=</code> de <code>/etc/log2ram.conf</code>.",
"Agenda uma sincronização periódica do disco via <code>/etc/cron.d/log2ram</code>: a cada 1h / 3h / 6h de acordo com o mesmo nível RAM.",
"Instala <code>/usr/local/bin/log2ram-check.sh</code>, executado a cada 10 minutos por <code>/etc/cron.d/log2ram-auto-sync</code>. Quando <code>/var/log</code> chega a 80% do ramdisk, limpa journals antigos. Aos 92%, executa primeiro <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code> se o ficheiro existir: os registos API PBS costumam ocupar mais espaço num host PBS. Depois trunca <code>pveproxy access/error</code> e <code>pveam.log</code> antes de sincronizar. <code>log2ram write</code> apenas copia tmpfs para disco, sem o reduzir. A proteção ajuda a evitar falhas PVE com <em>No space left on device</em> por crescimento descontrolado dos registos.",
"Deteta o serviço <code>proxmox-backup-server</code> no host. Se existir, cria <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 rotações) e <code>/etc/cron.hourly/proxmox-backup-logrotate</code> para limitar os registos API PBS, fonte habitual de crescimento, mesmo entre sincronizações Log2RAM. Sem PBS não altera nada.",
"Ajusta os limites systemd-journald (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) ao ramdisk para que uma rajada de registos não o encha.",
"Fica registado em <code>installed_tools.json</code> para poder ser revertido em Desinstalar otimizações."
"Mantém no disco o journal (<code>/var/log/journal</code>), os logs de tarefas do Proxmox VE (<code>/var/log/pve</code>) e, se estiver instalado, os do Proxmox Backup Server (<code>/var/log/proxmox-backup</code>), em <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> e <code>/var/hdd.proxmox-backup</code>. Cada caminho habitual passa a ser um link para a sua pasta no disco. A mudança acontece na inicialização, antes de o Log2RAM arrancar.",
"Grava o ramdisk no disco com o temporizador do Log2RAM a cada 1h / 3h / 6h conforme a mesma faixa de RAM, e descarrega o disco após cada gravação, para que uma sincronização concluída sobreviva a uma queda de energia.",
"Instala uma vigilância em <code>/etc/cron.d/log2ram-auto-sync</code> executada a cada 10 minutos. Quando <code>/var/log</code> ultrapassa 85% do ramdisk, rotaciona os logs, comprime os recém-rotacionados e grava tudo no disco. Nenhum log é esvaziado.",
"Mantém o journal do systemd no disco com um limite de 1 GB, em <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. Num host com Proxmox Backup Server, adiciona <code>/etc/logrotate.d/proxmox-backup-api</code> (rotação de 20 MB × 3) para os seus logs da API.",
"Regista-se em <code>installed_tools.json</code> para poder ser revertido em Desinstalar otimizações. Uma atualização a partir de uma versão anterior mantém o tamanho e o intervalo de sincronização, e leva o journal para o disco na inicialização seguinte."
],
"howUseLabel": "Como utilizar:",
"howUseBody": "O percurso automatizado instala Log2RAM sem intervenção se detetar disco raiz SSD/NVMe. O personalizável pergunta tamanho, intervalo e ativação da proteção. A pergunta indica 90%, mas o script gerado usa os limiares de limpeza de 80% e intensiva de 92% descritos acima.",
"howUseBody": "No fluxo automatizado, o Log2RAM instala-se sem intervenção ao detetar um disco do sistema SSD/NVMe. O personalizável pergunta o tamanho, o intervalo de sincronização e se deve ativar a vigilância. As alterações aplicam-se na inicialização seguinte.",
"verifyLabel": "Verificar e gerenciar a partir da shell:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "Habilitar perfil de troca ZRAM",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Para e desativa o serviço e o timer. Purga trabalhos de cron, unidades systemd, binários, arquivos de configuração e o diretório /var/log.hdd. Também desinstala o pacote apt se ele foi instalado dessa forma."
"restores": "Desativa o serviço e o temporizador e remove a configuração do ProxMenux para o Log2RAM. No desligamento seguinte, o Log2RAM grava /var/log no disco; na inicialização seguinte, o journal e os logs de tarefas voltam para /var/log e os ficheiros do Log2RAM são removidos."
},
{
"tool": "TRIM automático do ZFS",
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (prispôsobené pre SSD, automatické)",
"what": "Znižuje opotrebenie SSD/NVMe presunom /var/log na ramdisk tmpfs s pravidelnou synchronizáciou na disk. Inštalácia z pôvodného projektu pri koreňovom disku SSD alebo NVMe. Veľkosť podľa RAM hostiteľa (128M / 256M / 512M), pravidelná synchronizácia a ochrana, ktorá pri 80% zaplnení vyčistí staré žurnály a pri 92% skráti rýchlo rastúce logy pred zápisom. Limity journald prispôsobí ramdisku. Podrobnosti v <link>Log2RAM</link>.",
"what": "Znižuje opotrebenie SSD/NVMe presunutím /var/log na ramdisk tmpfs, ktorý sa podľa plánu zapisuje na disk. Inštaluje sa z pôvodného projektu, keď je systémový disk SSD alebo NVMe. Veľkosť ramdisku určí podľa RAM hostiteľa (128M / 256M / 512M) a pridá kontrolu, ktorá zrotuje a zapíše logy, keď ramdisk prekročí 85 %. Journal a logy úloh Proxmox VE a Proxmox Backup Server zostávajú na disku. Všetky podrobnosti v <link>Log2RAM</link>.",
"category": "Úložisko",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Predvolené hodnoty podľa hardvéru",
"hardwareBody": "Skript pred nastavením preskúma hardvér hostiteľa. Log2RAM sa predvolene inštaluje iba pri koreňovom disku SSD alebo NVMe; pri inej detekcii žiada potvrdenie. Veľkosť ramdisku sa vyberá podľa celkovej RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Pri aktívnom Log2RAM sa limity journald prispôsobia ramdisku, aby sa nezaplnil.",
"hardwareBody": "Skript pred nastavením preskúma hardvér hostiteľa. Log2RAM sa predvolene inštaluje iba pri koreňovom disku SSD alebo NVMe; pri inej detekcii žiada potvrdenie. Veľkosť ramdisku sa vyberá podľa celkovej RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). Keď je Log2RAM aktívny, journal zostáva na disku s vlastným limitom.",
"upgrade": {
"heading": "Aktualizovať systém",
"intro": "Prvým krokom automatického postupu je aktualizácia Proxmoxu. Oficiálny návod pre bežiaci hostiteľ v rámci rovnakej hlavnej verzie odporúča spustiť:",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Nainštalovať Log2RAM (zníženie opotrebenia SSD/NVMe)",
"intro": "Log2RAM pripojí <code>/var/log</code> ako ramdisk tmpfs a pravidelne ho synchronizuje na disk. Ukladanie častých zápisov journald do RAM môže znížiť opotrebenie SSD a diskové I/O. Synchronizácia a riadne vypnutie uložia logy na disk, ale náhly výpadok napájania môže stratiť záznamy od poslednej synchronizácie.",
"intro": "Log2RAM pripojí <code>/var/log</code> na ramdisk tmpfs a podľa plánu ho zapisuje na disk, takže logy, ktoré sa neustále menia, napríklad prístupový log pveproxy, sa zapisujú do RAM namiesto na systémový SSD. Journal a logy úloh Proxmox VE a Proxmox Backup Server zostávajú na disku. Čisté vypnutie zapíše ramdisk na disk; pri náhlom výpadku napájania sa stratia len textové logy zapísané od poslednej synchronizácie.",
"upstreamLabel": "Pôvodný projekt:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram na GitHub",
"doesLabel": "Čo robí ProxMenux:",
"doesItems": [
"Čítaním <code>/sys/block/&lt;dev&gt;/queue/rotational</code> zistí, či je koreňový disk SSD/NVMe. Pri rotačnom disku sa automatický postup pred inštaláciou opýta.",
"Naklonuje pôvodný repozitár (<code>azlux/log2ram</code>) do <code>/tmp/log2ram</code> a upraví <code>install.sh</code>: nahradí <code>rsync -aAXv</code> príkazom <code>rsync -aXv --no-acls</code>. Predíde tak chybe <em>set_acl: Operation not supported</em> s návratovým kódom 23 pri presune /var/log na súborovom systéme bez ACL. Jednotka systemd <code>log2ram</code> sa po inštalácii zapne.",
"Nainštaluje Log2RAM 1.7.2 z pôvodného projektu, overí, že stiahnutý súbor je táto verzia, a jeho kód ponechá bez zmien. Chybový e-mail vypne pomocou <code>NOTIFICATION=false</code>, pretože Proxmox VE neobsahuje príkaz mail.",
"Nastaví veľkosť ramdisku podľa RAM hostiteľa: <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Zapíše hodnotu do <code>SIZE=</code> v <code>/etc/log2ram.conf</code>.",
"Plánuje periodickú synchronizáciu disku cez <code>/etc/cron.d/log2ram</code>: každý 1h / 3h / 6h podľa rovnakej úrovne RAM.",
"Nainštaluje <code>/usr/local/bin/log2ram-check.sh</code>, spúšťaný cez <code>/etc/cron.d/log2ram-auto-sync</code> každých 10 minút. Keď <code>/var/log</code> dosiahne 80% ramdisku, vyčistí staré žurnály. Pri 92% najprv spustí <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code>, ak súbor existuje: logy API PBS bývajú najväčším spotrebiteľom miesta na hostiteľovi PBS. Potom skráti <code>pveproxy access/error</code> a <code>pveam.log</code> pred synchronizáciou. Samotný <code>log2ram write</code> skopíruje tmpfs na disk, ale nezmenší ho. Ochrana pomáha predchádzať pádom PVE s <em>No space left on device</em> pri nekontrolovanom raste logov.",
"Zistí službu <code>proxmox-backup-server</code> na hostiteľovi. Ak existuje, vytvorí <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 rotácie) a <code>/etc/cron.hourly/proxmox-backup-logrotate</code>, aby obmedzil logy API PBS, častý zdroj rastu, aj medzi synchronizáciami Log2RAM. Bez PBS nič nezmení.",
"Prispôsobí limity systemd-journald (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) ramdisku, aby ho nárazový príval záznamov nezaplnil.",
"Zaznamená sa v <code>installed_tools.json</code>, aby sa dal vrátiť cez Odinštalovať optimalizácie."
"Ponechá na disku journal (<code>/var/log/journal</code>), logy úloh Proxmox VE (<code>/var/log/pve</code>) a, ak je nainštalovaný, logy Proxmox Backup Server (<code>/var/log/proxmox-backup</code>), v <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> a <code>/var/hdd.proxmox-backup</code>. Každá bežná cesta sa zmení na odkaz na svoj priečinok na disku. Presun prebehne pri štarte, ešte pred spustením Log2RAM.",
"Zapisuje ramdisk na disk časovačom Log2RAM každú 1 h / 3 h / 6 h podľa rovnakého pásma RAM a po každom zápise vyprázdni vyrovnávaciu pamäť disku, takže dokončená synchronizácia prežije výpadok napájania.",
"Nainštaluje kontrolu v <code>/etc/cron.d/log2ram-auto-sync</code>, ktorá sa spúšťa každých 10 minút. Keď <code>/var/log</code> prekročí 85 % ramdisku, zrotuje logy, skomprimuje práve zrotované a všetko zapíše na disk. Žiadny log sa nevyprázdňuje.",
"Ponechá journal systemd na disku s limitom 1 GB, v <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. Na hostiteľovi s Proxmox Backup Server pridá <code>/etc/logrotate.d/proxmox-backup-api</code> (rotácia 20 MB × 3) pre jeho logy API.",
"Zaregistruje sa v <code>installed_tools.json</code>, aby ho bolo možné vrátiť v časti Odinštalovať optimalizácie. Aktualizácia zo staršej verzie zachová veľkosť a interval synchronizácie a pri ďalšom štarte presunie journal na disk."
],
"howUseLabel": "Ako používať:",
"howUseBody": "Automatický postup nainštaluje Log2RAM bez zásahu pri zistení koreňového SSD/NVMe. Prispôsobiteľný postup sa pýta na veľkosť, interval a ochranu synchronizácie. Výzva uvádza 90%, no vytvorený skript používa vyššie opísané limity 80% na čistenie a 92% na intenzívne čistenie.",
"howUseBody": "V automatickom postupe sa Log2RAM nainštaluje bez zásahu, keď zistí systémový disk SSD/NVMe. Prispôsobiteľný postup sa pýta na veľkosť, interval synchronizácie a na to, či zapnúť kontrolu. Zmeny sa uplatnia pri ďalšom štarte.",
"verifyLabel": "Overiť a spravovať zo shellu:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "Povoliť výmenný profil ZRAM",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Zastaví a zakáže službu a časovač. Čistí úlohy cron, jednotky systemd, binárne súbory, konfiguračné súbory a adresár /var/log.hdd. Tiež odinštaluje balík apt, ak bol nainštalovaný týmto spôsobom."
"restores": "Vypne službu a časovač a odstráni konfiguráciu ProxMenux pre Log2RAM. Pri ďalšom vypnutí Log2RAM zapíše /var/log na disk; pri ďalšom štarte sa journal a logy úloh vrátia do /var/log a súbory Log2RAM sa odstránia."
},
{
"tool": "Automatický TRIM ZFS",
@@ -79,7 +79,7 @@
},
{
"tool": "Log2RAM (SSD-medveten, auto)",
"what": "Minskar SSD-/NVMe-slitage genom att flytta /var/log till en tmpfs-ramdisk med regelbunden synkronisering till disk. Installation från ursprungsprojektet när rotdisken är SSD eller NVMe. Storlek efter värdens RAM (128M / 256M / 512M), periodisk synkronisering och skydd som rensar äldre journaler vid 80% fyllnadsgrad och trunkerar snabbt växande loggar vid 92% före skrivning. Anpassar journald-gränser till ramdisken. Detaljer på <link>Log2RAM</link>.",
"what": "Minskar slitaget på SSD/NVMe genom att flytta /var/log till en tmpfs-ramdisk som skrivs till disken enligt ett schema. Installeras från uppströmsprojektet när systemdisken är SSD eller NVMe. Ramdiskens storlek väljs efter värdens RAM (128M / 256M / 512M) och en bevakning roterar och skriver loggarna när ramdisken passerar 85 %. Journalen och uppgiftsloggarna för Proxmox VE och Proxmox Backup Server ligger kvar på disken. Alla detaljer under <link>Log2RAM</link>.",
"category": "Lagring",
"categorySlug": "storage"
},
@@ -109,7 +109,7 @@
}
],
"hardwareTitle": "Hårdvaruanpassade standardvärden",
"hardwareBody": "Skriptet läser värdhårdvaran innan inställningar tillämpas. Log2RAM är bara installerat på SSD / NVMe rotdiskar som standard (den frågar om upptäckten säger något annat). Log2RAM ramdiskstorlek väljs från totalt RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). De journald gränser matchas till ramdiskstorleken när Log2RAM är aktivt, för att undvika att fylla det.",
"hardwareBody": "Skriptet läser värdhårdvaran innan inställningar tillämpas. Log2RAM är bara installerat på SSD / NVMe rotdiskar som standard (den frågar om upptäckten säger något annat). Log2RAM ramdiskstorlek väljs från totalt RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). När Log2RAM är aktivt ligger journalen kvar på disken med en egen gräns.",
"upgrade": {
"heading": "Uppdatera och uppgradera systemet",
"intro": "Det första steget i Automated-paketet är Proxmox-uppgraderingen. Proxmox egen uppgraderingsvägledning för en löpande värd (inom samma stora version) är att köra:",
@@ -133,25 +133,25 @@
},
"log2ram": {
"title": "Installera Log2RAM (SSD/NVMe slitage reduktion)",
"intro": "Log2RAM monterar <code>/var/log</code> som en tmpfs-ramdisk och synkroniserar regelbundet till disk. Att buffra journalds täta skrivningar i RAM kan minska SSD-slitage och disk-I/O. Synkronisering och normal avstängning sparar loggar, men ett plötsligt strömavbrott kan förlora poster sedan senaste synkroniseringen.",
"intro": "Log2RAM monterar <code>/var/log</code> på en tmpfs-ramdisk och skriver den till disken enligt ett schema, så att loggar som ändras hela tiden, som pveproxys åtkomstlogg, skrivs till RAM i stället för till systemets SSD. Journalen och uppgiftsloggarna för Proxmox VE och Proxmox Backup Server ligger kvar på disken. En ren avstängning skriver ramdisken till disken; ett plötsligt strömavbrott förlorar bara de textloggar som skrivits sedan den senaste synkroniseringen.",
"upstreamLabel": "Upstream projekt:",
"upstreamUrl": "https://github.com/azlux/log2ram",
"upstreamLinkLabel": "azlux/log2ram på GitHub",
"doesLabel": "Vad ProxMenux gör:",
"doesItems": [
"Detekterar om rotskivan är SSD/NVMe genom att läsa <code>/sys/block/&lt;dev&gt;/queue/rotational</code>. På en rotationsdisk frågar det automatiska flödet först innan du installerar.",
"Kloner uppströms repository (<code>azlux/log2ram</code>) i <code>/tmp/log2ram</code> och patchar sin <code>install.sh</code>, ersätta <code>rsync -aAXv</code> med <code>rsync -aXv --no-acls</code>. Denna justering undviker <em>set_acl: Operation not supported</em> exit 23 misslyckande att vaniljskriptet utlöser när man flyttar /var/log på filsystem utan ACL stöd. <code>log2ram</code> systemd-enheten är aktiverad efter installation.",
"Installerar Log2RAM 1.7.2 från uppströmsprojektet, kontrollerar att nedladdningen är den versionen och lämnar koden oförändrad. Felmejlet stängs av med <code>NOTIFICATION=false</code>, eftersom Proxmox VE inte har något mail-kommando.",
"Anpassar ramdiskens storlek efter värdens RAM: <code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>&gt; 16 GB → 512M</code>. Skriver värdet till <code>SIZE=</code> i <code>/etc/log2ram.conf</code>.",
"Schemalägger regelbunden disksynkronisering via <code>/etc/cron.d/log2ram</code>: var 1 / 3 / 6 timme enligt samma RAM-nivå.",
"Installerar <code>/usr/local/bin/log2ram-check.sh</code>, som körs var tionde minut via <code>/etc/cron.d/log2ram-auto-sync</code>. När <code>/var/log</code> når 80% av ramdisken rensas äldre journaler. Vid 92% körs först <code>logrotate -f /etc/logrotate.d/proxmox-backup-api</code> om filen finns: PBS API-loggar tar ofta mest utrymme på en PBS-värd. Sedan trunkeras <code>pveproxy access/error</code> och <code>pveam.log</code> före synkronisering. <code>log2ram write</code> kopierar bara tmpfs till disk utan att krympa det. Skyddet hjälper till att förebygga PVE-fel med <em>No space left on device</em> när loggar växer okontrollerat.",
"Upptäcker tjänsten <code>proxmox-backup-server</code> på värden. Om den finns skapas <code>/etc/logrotate.d/proxmox-backup-api</code> (20 MB × 3 rotationer) och <code>/etc/cron.hourly/proxmox-backup-logrotate</code> för att begränsa PBS API-loggar, den vanliga tillväxtkällan, även mellan Log2RAM-synkroniseringar. Utan PBS görs ingen ändring.",
"Justerar systemd-journald gränser (<code>SystemMaxUse</code>, <code>RuntimeMaxUse</code>) för att passa in i ramdisken så att en enda burst inte kan fylla den.",
"Registreras i <code>installed_tools.json</code> så att det kan återställas via Avinstallera optimeringar."
"Behåller journalen (<code>/var/log/journal</code>), uppgiftsloggarna för Proxmox VE (<code>/var/log/pve</code>) och, där det är installerat, loggarna för Proxmox Backup Server (<code>/var/log/proxmox-backup</code>) på disken, i <code>/var/hdd.journal</code>, <code>/var/hdd.pve</code> och <code>/var/hdd.proxmox-backup</code>. Varje vanlig sökväg blir en länk till sin mapp på disken. Flytten sker vid uppstart, innan Log2RAM startar.",
"Skriver ramdisken till disken med Log2RAMs timer var 1:e / 3:e / 6:e timme enligt samma RAM-nivå och tömmer diskens cache efter varje skrivning, så att en avslutad synkronisering klarar ett strömavbrott.",
"Installerar en bevakning i <code>/etc/cron.d/log2ram-auto-sync</code> som körs var 10:e minut. När <code>/var/log</code> passerar 85 % av ramdisken roterar den loggarna, komprimerar de nyss roterade och skriver allt till disken. Ingen logg töms.",
"Behåller systemd-journalen på disken med en gräns på 1 GB, i <code>/etc/systemd/journald.conf.d/proxmenux-log2ram.conf</code>. På en värd med Proxmox Backup Server läggs <code>/etc/logrotate.d/proxmox-backup-api</code> (rotation 20 MB × 3) till för dess API-loggar.",
"Registrerar sig i <code>installed_tools.json</code> så att den kan återställas från Avinstallera optimeringar. En uppdatering från en tidigare version behåller storleken och synkroniseringsintervallet och flyttar journalen till disken vid nästa uppstart."
],
"howUseLabel": "Hur man använder:",
"howUseBody": "Det automatiserade flödet installerar Log2RAM utan åtgärd när en SSD-/NVMe-rotdisk upptäcks. Det anpassningsbara flödet frågar om storlek, intervall och synkskydd. Frågan anger 90%, men det genererade skriptet använder trösklarna 80% för rensning och 92% för intensiv rensning som beskrivs ovan.",
"howUseBody": "I det automatiserade flödet installeras Log2RAM utan ingrepp när en SSD/NVMe-systemdisk upptäcks. Det anpassningsbara flödet frågar efter storlek, synkroniseringsintervall och om bevakningen ska aktiveras. Ändringarna träder i kraft vid nästa uppstart.",
"verifyLabel": "Verifiera och hantera från skalet:",
"verifyCode": "# Service state and configured timers\nsystemctl status log2ram\nsystemctl list-timers log2ram*\n\n# Current ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Force a sync now (tmpfs → disk); does NOT shrink the tmpfs\nlog2ram write\n\n# Trigger the auto-sync guard on demand (vacuum + sync when usage is high)\n/usr/local/bin/log2ram-check.sh\n\n# Current config: SIZE, mail settings, path\ncat /etc/log2ram.conf\n\n# ProxMenux-specific cron jobs\ncat /etc/cron.d/log2ram /etc/cron.d/log2ram-auto-sync\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
"verifyCode": "# Service state and sync timer\nsystemctl status log2ram\nsystemctl list-timers log2ram-daily.timer\n\n# Ramdisk usage — /var/log IS the tmpfs itself\ndf -h /var/log\n\n# Folders kept on disk, and the journal size\nls -l /var/log | grep -- '->'\njournalctl --disk-usage\n\n# Write the ramdisk to disk now\nsystemctl reload log2ram\n\n# Current configuration\ncat /etc/log2ram.conf\nsystemctl cat log2ram\n\n# Recent Log2RAM activity\njournalctl -u log2ram -n 50 --no-pager"
},
"zram": {
"title": "Aktivera ZRAM-swap-profil",
@@ -125,7 +125,7 @@
},
{
"tool": "Log2RAM",
"restores": "Stoppar och inaktiverar tjänst och timer. Tar bort cron-jobb, systemd-enheter, binärer, konfiguration och /var/log.hdd. Avinstallerar även apt-paketet om det installerats så."
"restores": "Inaktiverar tjänsten och timern och tar bort ProxMenux-konfigurationen för Log2RAM. Vid nästa avstängning skriver Log2RAM /var/log till disken; vid nästa uppstart flyttas journalen och uppgiftsloggarna tillbaka till /var/log och Log2RAM-filerna tas bort."
},
{
"tool": "Automatisk ZFS-TRIM",