fix(oci): clarify removal and host firewall diagnostics

This commit is contained in:
martino
2026-09-28 18:07:21 +02:00
parent 33245a423a
commit 0c754bda60
4 changed files with 253 additions and 10 deletions
+1 -1
View File
@@ -244,7 +244,7 @@ PY
contract_count=$(jq --argjson port "$HOST_FIREWALL_PORT" '[.container_contract.ports[]? | select(
.protocol == "tcp" and .container_port == $port)] | length' "$TEMPLATE_FILE")
[[ $contract_count == 1 ]] \
|| die "$(translate "The host-monitor firewall port is not declared as the web port")"
|| die "$(translate "The host-monitor firewall port does not match exactly one TCP port in the container contract")"
HOST_FIREWALL_ENABLED=1
}
+3 -3
View File
@@ -138,7 +138,7 @@ def remove_owned_host_firewall(record):
except (OSError, ValueError, subprocess.CalledProcessError, json.JSONDecodeError):
# Removal already destroyed the CT. A firewall API failure must not
# turn that successful lifecycle operation into a failed one.
msg_warn(translate('The managed host firewall rule could not be removed and was left unchanged.'))
msg_warn(translate('Could not verify removal of the managed host firewall rule.'))
def remove(root, vmid):
@@ -166,7 +166,7 @@ def remove(root, vmid):
msg_ok(f"{translate('Container removed:')} CT {member}")
if bridge and not bridge_in_use(bridge, set(members)):
release_bridge(bridge)
msg_ok(f"{translate('Private network of the application released:')} {bridge}")
msg_ok(f"{translate('Private network release attempted:')} {bridge}")
elif bridge:
msg_warn(f"{translate('The private network is still used by another container and is kept:')} {bridge}")
remove_owned_host_firewall(primary)
@@ -200,7 +200,7 @@ def main():
except (OSError, ValueError, KeyError, RuntimeError, subprocess.CalledProcessError) as error:
msg_error(str(error) or type(error).__name__)
return 1
msg_ok(translate('The application was removed'))
msg_ok(translate('Removal command finished; review any warnings above.'))
return 0
+8 -6
View File
@@ -308,16 +308,17 @@ def _removal_summary(project, vmid):
text = []
if len(members) > 1 and vmid == primary_id:
text += [f"{application} {translate('runs in')} {len(members)} {translate('containers')}. "
f"{translate('All of them are removed.')}", '']
f"{translate('All of them are targeted for removal.')}", '']
elif len(members) > 1:
alone = translate('It cannot be removed on its own, because the application would stop '
'working: continuing removes the whole application.')
'working: continuing targets the whole application for removal.')
text += [f"CT {vmid} {translate('is one of the')} {len(members)} "
f"{translate('containers of')} {application}. {alone}", '']
text += [translate('Containers that are removed:'), *lines, '',
translate('Data that is deleted with them:'), *volumes]
text += [translate('Containers targeted for removal:'), *lines, '',
translate('Container data targeted for deletion:'), *volumes]
if bridge:
text += ['', f"{translate('Private network of the application that is released:')} {bridge}"]
text += ['', f"{translate('Private network targeted for release if no other guest uses it:')} {bridge}"]
text += ['', translate('A matching managed host firewall rule may also be removed.')]
if kept:
text += ['', translate('Host paths found in container configs or saved records (not targeted for removal):'),
*[f' {path}' for path in kept]]
@@ -333,7 +334,8 @@ def _remove(project, ui, vmid):
ui.message(f"{translate('The removal could not be prepared:')} {error}", translate('Remove OCI'))
return False
if not ui.review(summary, translate('Remove OCI'),
question=translate('Remove it? The data of its containers cannot be recovered afterwards.'),
question=translate('Remove the application? Its container disks are targeted for deletion; '
'recovery from backups is not checked here.'),
default=False):
return False
return _run_lifecycle([sys.executable, str(project / 'remote/oci_remove.py'), str(vmid)],