mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-02 02:42:08 +00:00
Merge develop and preserve generic i18n regression coverage
This commit is contained in:
@@ -22274,6 +22274,7 @@ def api_proxmenux_self_update_status():
|
||||
# so scheduled and manual applies cannot overlap.
|
||||
|
||||
_APPLY_UPDATES_SCRIPT = _LXC_APPLY_UPDATES_SCRIPT
|
||||
_SCHEDULED_STOPPED_EXIT = 9
|
||||
_DOCKER_ENGINE_INTEGRATED_COMMAND = (
|
||||
'python3 /usr/local/share/proxmenux/monitor-app/usr/bin/'
|
||||
'update_docker_engine.py --vmid "$VMID"'
|
||||
@@ -22315,6 +22316,23 @@ def _append_lxc_update_log(path: str | None, text: str) -> None:
|
||||
print(f'[ProxMenux] scheduler: could not append update log: {exc}', flush=True)
|
||||
|
||||
|
||||
def _scheduled_runner_reported_stopped(result, log_path: str | None, marker: str) -> bool:
|
||||
"""Return true only for the scheduler's own pre-start stopped marker."""
|
||||
if result.returncode != _SCHEDULED_STOPPED_EXIT or not marker:
|
||||
return False
|
||||
if log_path:
|
||||
try:
|
||||
with open(log_path, 'rb') as stream:
|
||||
stream.seek(0, os.SEEK_END)
|
||||
stream.seek(max(0, stream.tell() - 4096))
|
||||
output = stream.read().decode('utf-8', errors='replace')
|
||||
except OSError:
|
||||
return False
|
||||
else:
|
||||
output = (result.stdout or '') + (result.stderr or '')
|
||||
return marker in output
|
||||
|
||||
|
||||
def _prune_lxc_update_logs(vmid: int) -> None:
|
||||
try:
|
||||
candidates = sorted(
|
||||
@@ -22708,8 +22726,10 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
requested_targets = _normalise_schedule_targets(sched)
|
||||
targets = list(requested_targets)
|
||||
before = _lxc_update_snapshot(vmid)
|
||||
requested_target = sched.get("target") or "both"
|
||||
deferred_targets: list[str] = []
|
||||
reasons: list[str] = []
|
||||
reason_code: str | None = None
|
||||
reboot_required: bool | None = None
|
||||
reboot_packages: list[str] = []
|
||||
reboot_check_error: str | None = None
|
||||
@@ -22761,6 +22781,7 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
'status': status,
|
||||
'target': actual_target,
|
||||
'reason': reason,
|
||||
'reason_code': reason_code,
|
||||
'run_id': run_id,
|
||||
'requested_targets': requested_targets,
|
||||
'executed_targets': list(executed),
|
||||
@@ -22772,10 +22793,23 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
'finalization': finalization,
|
||||
}
|
||||
|
||||
requested_target = sched.get("target") or "both"
|
||||
if not originally_running:
|
||||
reason_code = 'stopped_container'
|
||||
reasons.append('container is stopped; scheduled update was skipped')
|
||||
return finish('skipped', requested_target, [])
|
||||
|
||||
if requested_targets == ['oci_image']:
|
||||
# A container installed by OCI manager Apps is updated by replacing
|
||||
# its image, through the same flow as the OCI menu, unattended.
|
||||
# OCI updates have their own runner rather than apply_updates.sh.
|
||||
# Check once more immediately before handing control to it: a user
|
||||
# may have intentionally stopped the CT after the scheduler's first
|
||||
# observation, and the OCI transaction can start a replacement CT
|
||||
# while validating its new image.
|
||||
if _fast_guest_status(vmid, 'lxc') != 'running':
|
||||
reason_code = 'stopped_container'
|
||||
reasons.append('container was stopped before scheduled update could begin')
|
||||
return finish('skipped', 'oci_image', [])
|
||||
command = ['bash', '/usr/local/share/proxmenux/scripts/oci/oci_manager_apps.sh',
|
||||
'manage', str(vmid), '--action', 'update', '--unattended']
|
||||
storage = (sched.get('backup_storage') or '').strip()
|
||||
@@ -22916,6 +22950,9 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
target = "both" if has_os_target and has_app_targets else ("os" if has_os_target else "app")
|
||||
env = dict(os.environ)
|
||||
env["VMID"] = str(vmid)
|
||||
env["EXECUTION_MODE"] = "scheduled"
|
||||
scheduled_stopped_marker = f"PROXMENUX_SCHEDULED_STOPPED:{run_id}"
|
||||
env["SCHEDULED_STOPPED_MARKER"] = scheduled_stopped_marker
|
||||
env["TARGET"] = target
|
||||
env["BACKUP"] = "1" if sched.get("backup") else "0"
|
||||
env["BACKUP_STORAGE"] = sched.get("backup_storage") or ""
|
||||
@@ -22981,6 +23018,10 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
text=True,
|
||||
timeout=60 * 60,
|
||||
)
|
||||
if _scheduled_runner_reported_stopped(r, log_path, scheduled_stopped_marker):
|
||||
reason_code = 'stopped_container'
|
||||
reasons.append('container was stopped before scheduled update could begin')
|
||||
return finish('skipped', target, [])
|
||||
reboot_required, reboot_packages, reboot_check_error = (
|
||||
_inspect_lxc_reboot_requirement(
|
||||
vmid,
|
||||
@@ -23056,12 +23097,14 @@ def _scheduler_loop():
|
||||
status = outcome.get('status') or 'failure'
|
||||
actual_target = outcome.get('target') or 'both'
|
||||
reason = outcome.get('reason')
|
||||
reason_code = outcome.get('reason_code')
|
||||
try:
|
||||
lxc_apps.record_schedule_run(
|
||||
_vmid,
|
||||
status,
|
||||
actual_target,
|
||||
reason,
|
||||
reason_code=reason_code,
|
||||
log_name=outcome.get('log_name'),
|
||||
reboot_required=outcome.get('reboot_required'),
|
||||
reboot_packages=outcome.get('reboot_packages'),
|
||||
|
||||
Reference in New Issue
Block a user