Merge claude/1
This commit is contained in:
commit
0f53fb0b47
@ -44,8 +44,8 @@ Object.assign(TasksManager.prototype, {
|
||||
{ match: /^libreportal system reclaim\b/, title: 'LibrePortal - Reclaim Space' },
|
||||
{ match: /^libreportal system image rm\b/, title: 'LibrePortal - Remove Images' },
|
||||
{ match: /^libreportal verify\b/, title: 'LibrePortal - Verify System' },
|
||||
{ match: /^libreportal system health heal\b/, title: 'LibrePortal - Repair Control Plane' },
|
||||
{ match: /^libreportal system health check\b/, title: 'LibrePortal - Check Control Plane' },
|
||||
{ match: /^libreportal system health heal\b/, title: 'LibrePortal - Fix System Issues' },
|
||||
{ match: /^libreportal system health check\b/, title: 'LibrePortal - System Health Check' },
|
||||
{ match: /^libreportal system network heal\b/, title: 'LibrePortal - Heal Network' },
|
||||
{ match: /^libreportal system network check\b/, title: 'LibrePortal - Check Network' },
|
||||
|
||||
@ -142,7 +142,7 @@ Object.assign(TasksManager.prototype, {
|
||||
'config_update': 'Update Config', 'update_config': 'Update Config',
|
||||
'system_update': 'Update System', 'system_reclaim': 'Reclaim Space',
|
||||
'system_image_rm': 'Remove Images', 'verify': 'Verify System',
|
||||
'system_health_heal': 'Repair Control Plane', 'system_network_heal': 'Heal Network',
|
||||
'system_health_heal': 'Fix System Issues', 'system_network_heal': 'Heal Network',
|
||||
'updater_check': 'Check for Updates', 'updater_apply': 'Update',
|
||||
'updater_apply_all': 'Update All', 'updater_rollback': 'Roll Back',
|
||||
'artifact_apply': 'Apply Hotfix', 'artifact_revert': 'Revert Hotfix',
|
||||
|
||||
@ -13,11 +13,11 @@
|
||||
// The backend already SELF-HEALS most of this (the task-processor poll dispatches
|
||||
// `system health heal` when the WebUI's own port is down — you can't click a
|
||||
// button on a dead WebUI). These surfaces are for visibility and for a manual
|
||||
// "Repair now" when the WebUI is still reachable (e.g. a crash-loop caught early).
|
||||
// "Fix now" when the WebUI is still reachable (e.g. a crash-loop caught early).
|
||||
//
|
||||
// Actions go through the normal task pipeline so progress streams on Tasks:
|
||||
// * "Repair now" -> task `libreportal system health heal`
|
||||
// * "Re-check" -> task `libreportal system health check`
|
||||
// * "Fix now" -> task `libreportal system health heal`
|
||||
// * "Re-check" -> task `libreportal system health check`
|
||||
//
|
||||
// This file owns no detection logic — it only reads the status file.
|
||||
|
||||
@ -120,7 +120,7 @@ class HealthNotifier {
|
||||
}
|
||||
|
||||
const n = Array.isArray(this.status.crash_loops) ? this.status.crash_loops.length : 0;
|
||||
badge.title = 'Control plane needs attention';
|
||||
badge.title = 'System needs attention';
|
||||
badge.setAttribute('aria-label', badge.title);
|
||||
badge.innerHTML = `
|
||||
<span class="health-badge-dot" aria-hidden="true"></span>
|
||||
@ -155,7 +155,7 @@ class HealthNotifier {
|
||||
}
|
||||
|
||||
const s = this.status;
|
||||
const sub = s.summary ? this._escape(s.summary) : 'The docker control plane needs attention';
|
||||
const sub = s.summary ? this._escape(s.summary) : 'The system needs attention';
|
||||
|
||||
const heartIcon = `
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
@ -166,12 +166,12 @@ class HealthNotifier {
|
||||
banner.innerHTML = `
|
||||
<div class="health-banner-icon" aria-hidden="true">${heartIcon}</div>
|
||||
<div class="health-banner-text">
|
||||
<div class="health-banner-title">Control plane attention needed</div>
|
||||
<div class="health-banner-title">System needs attention</div>
|
||||
<div class="health-banner-sub">${sub}</div>
|
||||
</div>
|
||||
<div class="health-banner-actions">
|
||||
<button type="button" class="health-btn-secondary" id="health-banner-details">Details</button>
|
||||
${s.can_auto_heal ? '<button type="button" class="health-btn-primary" id="health-banner-heal">Repair now</button>' : ''}
|
||||
${s.can_auto_heal ? '<button type="button" class="health-btn-primary" id="health-banner-heal">Fix now</button>' : ''}
|
||||
</div>`;
|
||||
|
||||
const details = banner.querySelector('#health-banner-details');
|
||||
@ -219,13 +219,13 @@ class HealthNotifier {
|
||||
: '';
|
||||
|
||||
const statusLine = this._hasIssues()
|
||||
? (s.summary || 'The docker control plane needs attention.')
|
||||
: 'Control plane healthy.';
|
||||
? (s.summary || 'The system needs attention.')
|
||||
: 'System healthy.';
|
||||
|
||||
overlay.innerHTML = `
|
||||
<div class="health-panel" role="dialog" aria-modal="true" aria-label="Control plane health">
|
||||
<div class="health-panel" role="dialog" aria-modal="true" aria-label="System health">
|
||||
<div class="health-panel-header">
|
||||
<h3>Control Plane Health</h3>
|
||||
<h3>System Health</h3>
|
||||
<button type="button" class="health-panel-close" id="health-panel-close" aria-label="Close">×</button>
|
||||
</div>
|
||||
<div class="health-panel-status ${this._hasIssues() ? 'is-issue' : ''}">${this._escape(statusLine)}</div>
|
||||
@ -234,10 +234,10 @@ class HealthNotifier {
|
||||
${rows.map(([k, v, cls]) => `<div class="health-panel-row"><dt>${this._escape(k)}</dt><dd class="${cls || ''}">${this._escape(v)}</dd></div>`).join('')}
|
||||
</dl>
|
||||
${loopList}
|
||||
${s.can_auto_heal && this._hasIssues() ? '<p class="health-panel-note">Repair stops any crash-looping container and, if the WebUI’s host port is down, restarts it — recycling the rootless docker daemon only if needed. Progress streams on the Tasks page.</p>' : ''}
|
||||
${s.can_auto_heal && this._hasIssues() ? '<p class="health-panel-note">Fixing stops any app stuck in a restart loop and, if the WebUI is unreachable, restarts it — restarting Docker only if needed. Progress streams on the Tasks page.</p>' : ''}
|
||||
<div class="health-panel-actions">
|
||||
<button type="button" class="health-btn-secondary" id="health-panel-check">Re-check</button>
|
||||
${s.can_auto_heal && this._hasIssues() ? '<button type="button" class="health-btn-primary" id="health-panel-heal">Repair now</button>' : ''}
|
||||
${s.can_auto_heal && this._hasIssues() ? '<button type="button" class="health-btn-primary" id="health-panel-heal">Fix now</button>' : ''}
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
@ -266,7 +266,7 @@ class HealthNotifier {
|
||||
this.closePanel();
|
||||
try {
|
||||
await this._createTask('libreportal system health heal');
|
||||
this._toast('Control-plane repair started — follow progress on the Tasks page.', 'info');
|
||||
this._toast('Fixing system issues — follow progress on the Tasks page.', 'info');
|
||||
this._goToTasks();
|
||||
} catch (e) {
|
||||
this._toast('Could not start the repair: ' + e.message, 'error');
|
||||
@ -276,7 +276,7 @@ class HealthNotifier {
|
||||
async checkNow() {
|
||||
try {
|
||||
await this._createTask('libreportal system health check');
|
||||
this._toast('Re-checking control-plane health…', 'info');
|
||||
this._toast('Re-checking system health…', 'info');
|
||||
setTimeout(() => this.refresh(), 4000);
|
||||
} catch (e) {
|
||||
this._toast('Could not re-check health: ' + e.message, 'error');
|
||||
|
||||
@ -22,12 +22,12 @@
|
||||
#
|
||||
# dockerHealthHeal
|
||||
dockerHealthHeal() {
|
||||
isHeader "Healing docker / control-plane health"
|
||||
isHeader "Fixing system issues"
|
||||
|
||||
dockerHealthScan # populate HEALTH_* (call direct, NOT in $(...))
|
||||
|
||||
if [[ "$HEALTH_DAEMON_OK" != "true" ]]; then
|
||||
isError "Docker daemon unreachable — cannot heal from here."
|
||||
isError "Docker engine unreachable — cannot fix from here."
|
||||
declare -f webuiSystemHealthCheck >/dev/null 2>&1 && webuiSystemHealthCheck "force" >/dev/null 2>&1
|
||||
return 1
|
||||
fi
|
||||
@ -42,7 +42,7 @@ dockerHealthHeal() {
|
||||
for row in "${HEALTH_CRASHLOOPS[@]}"; do
|
||||
cname="${row#*|}"; cname="${cname%%|*}" # app|container|rc -> container
|
||||
[[ "$cname" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]*$ ]] || continue
|
||||
isNotice "Stopping crash-looping container '$cname' (restart storm churning the network)…"
|
||||
isNotice "Stopping '$cname' — stuck in a restart loop (churning the network)…"
|
||||
dockerCommandRun "docker stop '$cname'" >/dev/null 2>&1
|
||||
((acted++))
|
||||
done
|
||||
@ -50,14 +50,14 @@ dockerHealthHeal() {
|
||||
# 2/3) Restore the WebUI host port if the container is up but unreachable.
|
||||
if [[ "$HEALTH_WEBUI_RUNNING" == "true" && "$HEALTH_WEBUI_REACHABLE" == "false" ]]; then
|
||||
local webui; webui="$(_healthWebuiContainer)"
|
||||
isNotice "WebUI up but host port ${HEALTH_WEBUI_PORT:-?} unreachable — restarting '$webui' to re-publish…"
|
||||
isNotice "WebUI unreachable on port ${HEALTH_WEBUI_PORT:-?} — restarting '$webui' to restore access…"
|
||||
dockerCommandRun "docker restart '$webui'" >/dev/null 2>&1
|
||||
((acted++))
|
||||
sleep 4
|
||||
dockerHealthScan
|
||||
|
||||
if [[ "$HEALTH_WEBUI_REACHABLE" != "true" && "$rootless" == "true" ]]; then
|
||||
isNotice "Still unreachable — recycling the rootless docker daemon to rebuild port-forward state…"
|
||||
isNotice "Still unreachable — restarting Docker to restore access…"
|
||||
dockerCommandRun "systemctl --user restart docker.service" >/dev/null 2>&1
|
||||
sleep 8
|
||||
# The core container may have no restart policy — bring it back explicitly.
|
||||
@ -72,12 +72,12 @@ dockerHealthHeal() {
|
||||
dockerHealthScan
|
||||
|
||||
if [[ "$HEALTH_WEBUI_RUNNING" == "true" && "$HEALTH_WEBUI_REACHABLE" == "false" ]]; then
|
||||
isError "Health heal ran ${acted} action(s); WebUI still unreachable on port ${HEALTH_WEBUI_PORT:-?} — manual inspection needed."
|
||||
isError "Ran ${acted} fix action(s); WebUI still unreachable on port ${HEALTH_WEBUI_PORT:-?} — manual check needed."
|
||||
return 1
|
||||
fi
|
||||
if (( acted == 0 )); then
|
||||
isSuccessful "Nothing to heal — control plane healthy."
|
||||
isSuccessful "Nothing to fix — system healthy."
|
||||
else
|
||||
isSuccessful "Health heal complete — ${acted} action(s); control plane reachable."
|
||||
isSuccessful "Fixed — ${acted} action(s); WebUI reachable."
|
||||
fi
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ webuiSystemHealthCheck() {
|
||||
if [[ "$HEALTH_DAEMON_OK" != "true" ]]; then
|
||||
# Daemon unreachable — neutral status; never alarm on what we can't check.
|
||||
error_json="\"${HEALTH_SCAN_ERROR//\"/\\\"}\""
|
||||
summary="Docker daemon unreachable"
|
||||
summary="Docker engine unreachable"
|
||||
else
|
||||
local row app cname rc _a _c
|
||||
for row in "${HEALTH_CRASHLOOPS[@]}"; do
|
||||
@ -68,12 +68,12 @@ webuiSystemHealthCheck() {
|
||||
if [[ -n "$crash_json" || "$webui_unreachable" == "true" ]]; then
|
||||
healthy="false"; issues_found="true"; can_auto_heal="true"
|
||||
if [[ "$webui_unreachable" == "true" ]]; then
|
||||
summary="WebUI unreachable on host port ${HEALTH_WEBUI_PORT:-?} (container is up) — port forward needs repair"
|
||||
summary="WebUI unreachable on port ${HEALTH_WEBUI_PORT:-?} — needs a fix"
|
||||
else
|
||||
summary="Crash-looping container(s) churning the network"
|
||||
summary="An app is stuck in a restart loop"
|
||||
fi
|
||||
else
|
||||
summary="Control plane healthy"
|
||||
summary="System healthy"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user