OCI catalog verification, console start marks and log cleanup

This commit is contained in:
MacRimi
2026-09-27 21:02:16 +02:00
parent 24617f9924
commit f3c4959fa4
34 changed files with 365 additions and 20 deletions
+22 -2
View File
@@ -25,6 +25,17 @@ import sys
NO_LOGIN = ('nologin', 'false')
LOG_DIR = Path('/var/log/proxmenux/oci')
# Each start is marked in the console log by a pre-start hook. The hook runs
# the script only when it exists and always succeeds: a hook that fails would
# stop the container from starting.
START_MARK_SCRIPT = Path(__file__).resolve().with_name('oci_console_mark.sh')
START_MARK = '=== ProxMenux: container started '
def start_mark_hook(vmid: int) -> str:
script = START_MARK_SCRIPT
# `test`, not `[`: a bracket in the configuration reads as a snapshot section.
return f"lxc.hook.pre-start: /bin/sh -c 'test -x {script} && {script} {int(vmid)}; exit 0'"
LOGROTATE = Path('/etc/logrotate.d/proxmenux-oci')
# copytruncate, because liblxc keeps the file open for as long as the
# container runs; moving it away would leave the application writing into the
@@ -165,8 +176,9 @@ def enable_log(vmid: int) -> Path:
text = conf.read_text()
current, _, snapshots = text.partition('\n[')
wanted = f'lxc.console.logfile: {path}'
kept = [line for line in current.splitlines() if not line.startswith('lxc.console.logfile:')]
kept.append(wanted)
kept = [line for line in current.splitlines()
if not line.startswith('lxc.console.logfile:') and START_MARK_SCRIPT.name not in line]
kept += [wanted, start_mark_hook(vmid)]
rebuilt = '\n'.join(kept) + '\n'
if snapshots:
rebuilt += '\n[' + snapshots
@@ -176,6 +188,14 @@ def enable_log(vmid: int) -> Path:
return path
def remove_log(vmid: int) -> None:
"""Delete the console log of a removed container and its rotated copies."""
base = log_path(vmid)
for path in [base, *LOG_DIR.glob(f'{base.name}.*')]:
if path.is_file() and not path.is_symlink():
path.unlink()
def configure(vmid: int) -> dict:
"""Console log and Proxmox terminal of a container being created."""
path = enable_log(vmid)
+9
View File
@@ -0,0 +1,9 @@
#!/bin/sh
# Marks each start of an OCI container in its console log, so the log can be
# read from the last start. Run by the container's lxc.hook.pre-start.
case "$1" in
''|*[!0-9]*) exit 0 ;;
esac
printf '\n=== ProxMenux: container started %s ===\n' "$(date '+%Y-%m-%d %H:%M:%S')" \
>> "/var/log/proxmenux/oci/$1.console.log" 2>/dev/null
exit 0
+3 -1
View File
@@ -44,7 +44,9 @@ BASIC = {'arch', 'cmode', 'console', 'tty', 'cores', 'cpulimit', 'cpuunits', 'de
'lxc.signal.halt', 'lxc.environment.runtime',
# The container's console log, set by the installer on every
# creation; the rebuilt container gets it again the same way.
'lxc.console.logfile'}
'lxc.console.logfile',
# The hook that marks each start in that log, set the same way.
'lxc.hook.pre-start'}
# Their output is data (and may hold saved secrets); it is never logged.
DATA_COMMANDS = {('pct', 'config'), ('pvesh', 'get')}
LOG_DIR = Path(os.environ.get('OCI_LOG_DIR', '/var/log/proxmenux/oci'))
+3
View File
@@ -18,6 +18,7 @@ import sys
import oci_image_cache as image_cache
import oci_instances as instances
from oci_installation_state import parse_config
import oci_console
from oci_ui import translate, msg_info, msg_ok, msg_warn, msg_error
# The private networks ProxMenux creates for multi-container applications.
@@ -118,11 +119,13 @@ def remove(root, vmid):
config = guest_config(member)
if config is None:
msg_warn(f"{translate('The container no longer exists:')} CT {member}")
oci_console.remove_log(member)
elif instances.identity(config) != record['installation_id']:
msg_warn(f"{translate('The VMID belongs to another container now and is not touched:')} CT {member}")
else:
subprocess.run(['pct', 'stop', str(member), '--skiplock', '1'], check=False, capture_output=True)
run('pct', 'destroy', str(member), '--purge', '1', '--destroy-unreferenced-disks', '1')
oci_console.remove_log(member)
msg_ok(f"{translate('Container removed:')} CT {member}")
if bridge and not bridge_in_use(bridge, set(members)):
release_bridge(bridge)