1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/instances/templates/instances/destroy_instance_form.html
catborise 02412b7ea5 feat(jobs): deleting a VM is a job that recovery finishes
The delete ran in the request: undefine, then the VM's record, then its
disk files. A request that died in between (a gunicorn worker past its
timeout, OOM, a restart), or a database write that failed after the
undefine, left a record that later showed as removed outside the panel,
and the disk files the user asked to delete were never deleted.

Deleting a VM is now an instance.delete job. It holds the compute
exclusively, as the request did, so no other VM attaches a file it is
about to delete. The job chooses the files before it stops the VM (a host
that cannot be checked still stops nothing) and records them first. It
then stops and undefines the VM, removes its record, and deletes the
files, each with its own Logs row. Recovery decides from libvirt: a VM
still on its host means the delete failed; a VM gone means libvirt did
it, so recovery removes the record and deletes the recorded files that
are still there.

The page queues the job and returns to the VM page, where the job panel
follows it and opens the VM list when it ends; disks that were kept are
the result's warning. The API's delete answers 202 with the job and
needs a submission_key. backing_path moves to wvmConnect, as recovery
has no domain to ask.
2026-11-06 09:49:31 +03:00

56 lines
3.4 KiB
HTML

{% extends 'base.html' %}
{% load i18n %}
{% load operations %}
{% block title %}{% blocktrans with name=instance.name %}Destroy {{ name }}{% endblocktrans %}{% endblock title %}
{% block page_heading %}
{% blocktrans with name=instance.name %}Destroy {{ name }}{% endblocktrans %} <small class="text-body-secondary fs-6">{% blocktrans with host=instance.compute.name %}on {{ host }}{% endblocktrans %}</small>
{% endblock page_heading %}
{% block content %}
<p class="small">{% trans "The VM's definition, saved state and snapshot records are removed. A running VM is forced off first; what the guest has not written to disk is lost." %}</p>
<form action="{% url 'instances:destroy' instance.id %}" method="post" id="delete_form">{% csrf_token %}{% submission_key %}
<fieldset class="mb-3">
<legend class="h6">{% trans "What should happen to the files?" %}</legend>
<div class="row g-2">
<div class="col-12 col-md-6">
<label class="border rounded p-3 d-block h-100">
<input class="form-check-input me-2" type="radio" name="delete_disk" value="true" checked>
<strong>{% trans "Delete disk files" %}</strong>
<span class="small d-block mt-2">{% trans "With them go this VM's external snapshot files, snapshot memory files and cloud-init seed." %}</span>
</label>
</div>
<div class="col-12 col-md-6">
<label class="border rounded p-3 d-block h-100">
<input class="form-check-input me-2" type="radio" name="delete_disk" value="false">
<strong>{% trans "Keep the disk files" %}</strong>
<span class="small d-block mt-2">{% trans "They stay with their internal snapshot data; the snapshot records still go with the VM." %}</span>
</label>
</div>
</div>
</fieldset>
{% if instance.config_disks %}
<p class="small fw-semibold mb-1">{% trans "Disks" %}</p>
<ul class="small ps-3">
{% for disk in instance.config_disks %}
<li><strong>{{ disk.dev }}</strong> <span class="text-break">{{ disk.path|default:_("no file") }}</span></li>
{% endfor %}
</ul>
{% endif %}
<p class="small text-body-secondary">{% trans "A file another VM uses on any of the panel's hosts, directly or under its own disk, is kept, and so is the template a disk was made from. If a host cannot be checked, the VM is not destroyed." %}</p>
{% if instance.nvram %}
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="delete_nvram" value="true" id="delete_nvram" checked>
<label class="form-check-label" for="delete_nvram">{% trans "Delete the NVRAM file (firmware settings). Untick to keep it." %}</label>
</div>
{% endif %}
{% if instance.config_tpm == "emulator" %}
<p class="small text-body-secondary" id="destroy-tpm">{% trans "Its TPM state is deleted with it, and the keys in it, such as BitLocker's." %}</p>
{% endif %}
<div class="border-top pt-3 d-flex flex-wrap align-items-center gap-2">
<span class="small text-danger me-auto">{% trans "This cannot be undone." %}</span>
<a class="btn btn-secondary" href="{% url 'instances:instance' instance.id %}">{% trans "Cancel" %}</a>
<button class="btn btn-danger" type="submit" name="delete">{% trans "Destroy VM" %}</button>
</div>
</form>
{% endblock content %}