1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 11:46:49 +00:00
webvirtcloud/instances/templates/instances/settings_tab.html
catborise 8a809443a4 feat(instances): a clone takes the size asked and starts if asked
A VM made from a template came out at the template's size and shut off,
and was then resized and started by hand. The Clone tab now asks for the
clone's vCPUs and memory, filled in with the VM's, and whether to start
it. After the copy, before the clone is recorded, it is resized with the
Resize tab's own functions and started; a step that fails is a warning
of the job, and the clone stays. The quota counts the larger of the size
asked and the VM's, so a resize that fails leaves the clone at a size it
allowed.

When the job ends the page opens the clone's, not the cloned VM's again:
a template's page, shut off, read as a clone that had not started. An
outcome kept for a warning links to it.
2026-11-01 22:38:43 +03:00

1038 lines
81 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% load i18n %}
{% load django_bootstrap5 %}
{% load bootstrap_icons %}
{% load operations %}
<div class="tab-pane" id="settings" role="tabpanel">
<!-- Nav tabs -->
<div class="card">
<div class="card-header bg-transparent pb-0">
<ul class="nav nav-underline small" role="tablist" aria-label="Instance settings">
{% if instance.guest_agent_ready %}
<li class="nav-item" role="presentation">
<button class="px-1 nav-link" data-bs-toggle="tab" id="osinfo-tab" data-bs-target="#osinfo" type="button" role="tab" aria-controls="osinfo" aria-selected="false" onclick="get_osinfo();">
<span>{% bs_icon 'info-circle' %} </span>
</button>
</li>
{% endif %}
{% if request.user.is_superuser %}
<li class="nav-item" role="presentation">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#boot_opt" type="button" role="tab" aria-controls="boot_opt" aria-selected="true">
{% trans "Boot" %}
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#disks" type="button" role="tab" aria-controls="disks" aria-selected="false">
{% trans "Disk" %}
</button>
</li>
{% endif %}
{% if can_manage_console %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#vncsettings" type="button" role="tab" aria-controls="vncsettings" aria-selected="false">
{% trans "Console" %}
</button>
</li>
{% endif %}
{% if request.user.is_superuser %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#network" type="button" role="tab" aria-controls="network" aria-selected="false">
{% trans "Network" %}
</button>
</li>
{% endif %}
{% if show_hostdevs %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#hostdevs" type="button" role="tab" aria-controls="hostdevs" aria-selected="false">
{% trans "Host devices" %}
</button>
</li>
{% endif %}
{% if can_clone %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#clone" type="button" role="tab" aria-controls="clone" aria-selected="false">
{% trans "Clone" %}
</button>
</li>
{% endif %}
{% if request.user.is_superuser %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#migrate" type="button" role="tab" aria-controls="migrate" aria-selected="false">
{% trans "Migrate" %}
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#xmledit" type="button" role="tab" aria-controls="xmledit" aria-selected="false">
{% trans "XML" %}
</button>
</li>
{% endif %}
{% if can_change %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#options" type="button" role="tab" aria-controls="options" aria-selected="false">
{% trans "Options" %}
</button>
</li>
{% endif %}
{% if request.user.is_superuser %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#users" type="button" role="tab" aria-controls="users" aria-selected="false">
{% trans "Users" %}
</button>
</li>
{% endif %}
</ul>
</div>
{% if instance.status != 5 %}
<p class="small text-body-secondary px-3 pt-3 mb-0" id="next-start-note">{% trans "While the VM runs, most settings here apply at its next start." %}</p>
{% endif %}
<!-- Tab panes -->
<div class="tab-content card-body">
{% if instance.guest_agent_ready %}
{% include 'instances/info_tab.html' %}
{% endif %}
{% if request.user.is_superuser %}
<div role="tabpanel" class="tab-pane active" id="boot_opt">
<section class="mb-4" aria-labelledby="startup-heading">
<h2 class="h6" id="startup-heading">{% trans "Startup settings" %}</h2>
<div class="list-group">
<div class="list-group-item py-3">
<form action="{% if instance.autostart %}{% url 'instances:unset_autostart' instance.id %}{% else %}{% url 'instances:set_autostart' instance.id %}{% endif %}" method="post">{% csrf_token %}
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="autostart" aria-describedby="autostart-help"{% if instance.autostart %} checked{% endif %} onchange="this.form.submit()">
<label class="form-check-label fw-semibold" for="autostart">{% trans "Autostart" %}</label>
</div>
<p class="small text-body-secondary mb-0 mt-1" id="autostart-help">{% trans "Start this VM when the host starts." %}</p>
</form>
</div>
<div class="list-group-item py-3">
<form action="{% if instance.config_bootmenu %}{% url 'instances:unset_bootmenu' instance.id %}{% else %}{% url 'instances:set_bootmenu' instance.id %}{% endif %}" method="post">{% csrf_token %}
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="bootmenu" aria-describedby="bootmenu-help"{% if instance.config_bootmenu %} checked{% endif %} onchange="this.form.submit()">
<label class="form-check-label fw-semibold" for="bootmenu">{% trans "Boot menu" %}</label>
</div>
<p class="small text-body-secondary mb-0 mt-1" id="bootmenu-help">{% trans "Show a device chooser when the VM starts." %}</p>
</form>
</div>
</div>
</section>
<section aria-labelledby="boot-order-heading">
<h2 class="h6" id="boot-order-heading">{% trans "Boot order" %}</h2>
<p class="small text-body-secondary" id="boot-order-help">{% trans "Checked devices boot from top to bottom. Up and Down move all checked devices." %}</p>
{% if instance.config_boot_order and not instance.config_boot_devices.0.checked %}
<p class="small text-body-secondary" id="boot-by-type">
{% trans "The VM now boots by device type:" %}
{% for b in instance.config_boot_order.values %}{{ b.target }}{% if not forloop.last %}, {% endif %}{% endfor %}.
{% trans "Checking devices replaces this order." %}
</p>
{% endif %}
<form action="{% url 'instances:set_bootorder' instance.id %}" method="post" aria-labelledby="boot-order-heading" aria-describedby="boot-order-help">{% csrf_token %}
<input type="hidden" id="bootorder" name="bootorder">
<div id="b_order" class="list-group boot-sequence mb-3">
{% for device in instance.config_boot_devices %}
<label class="list-group-item d-flex align-items-center gap-3">
<input class="form-check-input flex-shrink-0 m-0" type="checkbox" value="{{ device.value }}"{% if device.checked %} checked{% endif %}>
<span class="boot-rank small text-body-secondary" aria-hidden="true"></span>
<span class="text-break"><strong>{{ device.name }}</strong><span class="d-block small text-body-secondary">{{ device.kind }} · {{ device.source|default:_("empty") }}</span></span>
</label>
{% endfor %}
</div>
<div class="d-flex flex-wrap gap-2">
<button type="button" id="boot_order_up" class="btn btn-sm btn-secondary">{% bs_icon 'arrow-up' %} {% trans "Up" %}</button>
<button type="button" id="boot_order_down" class="btn btn-sm btn-secondary">{% bs_icon 'arrow-down' %} {% trans "Down" %}</button>
<button type="submit" class="btn btn-sm btn-primary ms-auto">{% trans "Apply order" %}</button>
</div>
</form>
</section>
</div>
<div role="tabpanel" class="tab-pane" id="disks">
{# its CD-ROM drives, then its disks as list rows; the forms are those of the actions #}
{% if instance.status != 5 %}
<p class="small text-body-secondary">{% bs_icon 'lock' %} {% trans "The VM is running: CD-ROM drives added now use the USB or SCSI bus. Shut it down to detach a SATA or IDE CD-ROM drive, or to detach or delete disks." %}</p>
{% endif %}
<section class="mb-4" aria-labelledby="media-heading">
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-2">
<h2 class="h6 mb-0" id="media-heading">{% trans "Removable media" %}</h2>
{% include 'add_instance_cdrom.html' %}
</div>
{% for cd in instance.media %}
<div class="card mb-2">
<form class="card-body" method="post" action="{% if cd.image %}{% url 'instances:unmount_iso' instance.id %}{% else %}{% url 'instances:mount_iso' instance.id %}{% endif %}">
{% csrf_token %}
<div class="d-flex flex-wrap justify-content-between align-items-start gap-2 mb-2">
<div class="d-flex align-items-center gap-3">
<span class="fs-4 text-body-secondary" aria-hidden="true">{% bs_icon 'disc' %}</span>
<div>
<div class="fw-semibold">{% trans "CD-ROM" %} {{ forloop.counter }}</div>
<div class="small text-body-secondary">{{ cd.dev }} · {{ cd.bus }} · {% if cd.image %}{{ cd.image }}{% else %}{% trans "No media" %}{% endif %}</div>
</div>
</div>
{% if not cd.image or cd.bus == "usb" %}
<button type="submit" class="btn btn-sm btn-secondary" formaction="{% url 'instances:detach_cdrom' instance.id cd.dev %}" formmethod="post"{% if instance.status != 5 and cd.bus != "scsi" and cd.bus != "usb" %} disabled{% endif %}>{% trans "Detach" %}</button>
{% endif %}
</div>
{% if cd.bus == "usb" %}
{# libvirt has no empty USB drive: it is detached, not ejected #}
{% elif cd.image %}
<input type="hidden" name="path" value="{{ cd.path }}">
<button type="submit" class="btn btn-sm btn-primary" value="{{ cd.dev }}" name="umount_iso">{% bs_icon 'eject' %} {% trans "Unmount" %}</button>
{% else %}
<label class="form-label small" for="media-{{ cd.dev }}">{% trans "ISO image" %}</label>
<div class="row g-2">
<div class="col-12 col-sm">
<select name="media" class="form-select form-select-sm" id="media-{{ cd.dev }}">
{% for iso in instance.media_iso %}
<option value="{{ iso }}">{{ iso }}</option>
{% empty %}
<option value="none">{% trans "None" %}</option>
{% endfor %}
</select>
</div>
<div class="col-12 col-sm-auto d-grid">
<button type="submit" class="btn btn-sm btn-primary" name="mount_iso" value="{{ cd.dev }}"{% if not instance.media_iso %} disabled{% endif %}>{% trans "Mount" %}</button>
</div>
</div>
{% endif %}
</form>
</div>
{% empty %}
<p class="small text-body-secondary mb-0">{% trans "The VM has no CD-ROM drive." %}</p>
{% endfor %}
</section>
<section aria-labelledby="disks-heading">
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-2">
<h2 class="h6 mb-0" id="disks-heading">{% trans "Disks" %} <span class="text-body-secondary fw-normal">· {{ instance.config_disks|length }}</span></h2>
{% include 'add_instance_volume.html' %}
</div>
<div class="card">
<div class="list-group list-group-flush">
{% for disk in instance.config_disks %}
<article class="list-group-item py-3" aria-labelledby="disk-{{ disk.dev }}">
<div class="row g-3 align-items-start small">
<div class="col-12 col-md-2">
<h3 class="h6 mb-1" id="disk-{{ disk.dev }}">{% bs_icon 'device-hdd' %} {{ disk.dev }}</h3>
<div class="text-body-secondary">{{ disk.bus }} · {{ disk.format }}</div>
</div>
<div class="col-12 col-md-6">
{% if disk.storage is None %}
<div class="alert alert-danger mb-0">{% trans "Error getting disk info" %}</div>
{% else %}
{% widthratio disk.used disk.size 100 as used_percent %}
{# a qcow2 file's metadata can take it past its capacity: the bar stops full #}
{% if used_percent|add:0 > 100 %}{% widthratio 100 1 1 as used_percent %}{% endif %}
<div class="d-flex flex-wrap justify-content-between gap-1">
<strong>{% trans "Capacity" %} {{ disk.size|filesizeformat }}</strong>
<span class="text-body-secondary">{% blocktrans with used=disk.used|filesizeformat %}{{ used }} used{% endblocktrans %}</span>
</div>
<div class="progress my-2" style="height: .25rem;" role="progressbar" aria-label="{% blocktrans with dev=disk.dev %}{{ dev }} used{% endblocktrans %}" aria-valuenow="{{ used_percent }}" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar" style="width: {{ used_percent }}%"></div>
</div>
<div><span class="text-body-secondary">{% trans "Storage pool" %}</span> <strong>{{ disk.storage }}</strong></div>
<div class="text-body-secondary text-break"><span class="visually-hidden">{% trans "Source" %}: </span>{{ disk.path }}</div>
{% endif %}
</div>
<div class="col-12 col-md-4 d-flex flex-wrap justify-content-md-end gap-2">
<form class="d-inline" action="{% url 'instances:edit_volume' instance.id %}" method="post" aria-label="{% trans "Edit instance volume form" %}">
{% csrf_token %}
<input type="hidden" name="path" value="{{ disk.path }}">
<input type="hidden" name="dev" value="{{ disk.dev }}">
<input type="hidden" name="storage" value="{{ disk.storage }}">
<input type="hidden" name="name" value="{{ disk.image }}">
{% include 'instances/edit_instance_volume.html' with id=forloop.counter0 %}
</form>
{% if request.user.is_superuser %}{% include 'instances/move_disk.html' with id=forloop.counter0 %}{% endif %}
<form class="d-inline" action="{% url 'instances:detach_vol' instance.id %}" method="post">
{% csrf_token %}
<input type="hidden" name="path" value="{{ disk.path }}">
<input type="hidden" name="dev" value="{{ disk.dev }}">
<input type="hidden" name="storage" value="{{ disk.storage }}">
<input type="hidden" name="name" value="{{ disk.image }}">
<button type="submit" class="btn btn-sm btn-secondary" value="{{ disk.dev }}"{% if instance.status != 5 %} disabled{% endif %} data-confirm="{% blocktrans with dev=disk.dev %}Detach {{ dev }}? Its file is kept.{% endblocktrans %}">{% trans "Detach" %}</button>
</form>
<form class="d-inline" action="{% url 'instances:delete_vol' instance.id %}" method="post">
{% csrf_token %}
<input type="hidden" name="path" value="{{ disk.path }}">
<input type="hidden" name="dev" value="{{ disk.dev }}">
<input type="hidden" name="storage" value="{{ disk.storage }}">
<input type="hidden" name="name" value="{{ disk.image }}">
<button type="submit" class="btn btn-sm btn-danger"{% if instance.status != 5 %} disabled{% endif %} data-confirm="{% blocktrans with dev=disk.dev %}Delete {{ dev }}? It is detached and its file and data are removed.{% endblocktrans %}">{% trans "Delete" %}</button>
</form>
</div>
</div>
<details class="small mt-2">
<summary class="text-body-secondary">{% trans "Device details" %}</summary>
<dl class="row mb-0 mt-2" style="max-width: 32rem">
<dt class="col-6 fw-normal text-body-secondary">{% trans "Cache" %}</dt><dd class="col-6 mb-1">{{ disk.cache }}</dd>
<dt class="col-6 fw-normal text-body-secondary">{% trans "IO mode" %}</dt><dd class="col-6 mb-1">{{ disk.io }}</dd>
<dt class="col-6 fw-normal text-body-secondary">{% trans "Discard" %}</dt><dd class="col-6 mb-1">{{ disk.discard }}</dd>
<dt class="col-6 fw-normal text-body-secondary">{% trans "Detect zeroes" %}</dt><dd class="col-6 mb-1">{{ disk.detect_zeroes }}</dd>
<dt class="col-6 fw-normal text-body-secondary">{% trans "Serial" %}</dt><dd class="col-6 mb-1">{{ disk.serial|default:"—" }}</dd>
<dt class="col-6 fw-normal text-body-secondary">{% trans "Read-only" %}</dt><dd class="col-6 mb-1">{{ disk.readonly|yesno }}</dd>
<dt class="col-6 fw-normal text-body-secondary">{% trans "Shareable" %}</dt><dd class="col-6 mb-0">{{ disk.shareable|yesno }}</dd>
</dl>
</details>
</article>
{% endfor %}
</div>
</div>
{% if instance.pcie_slots %}
{# a PCIe machine gives each virtio disk and network device a slot; a running VM gets no new one #}
{% with total=instance.pcie_slots.0 free=instance.pcie_slots.1 next=instance.config_pcie_slots %}
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 small mt-3">
<span class="{% if not free %}text-danger{% else %}text-body-secondary{% endif %}">
{% blocktrans %}PCIe slots: {{ free }} free of {{ total }}{% endblocktrans %}{% if next and next.1 != free %} · {% blocktrans with next_free=next.1 %}{{ next_free }} free from the next start{% endblocktrans %}{% endif %}
</span>
{% if request.user.is_superuser %}
<form action="{% url 'instances:add_pcie_slots' instance.id %}" method="post">{% csrf_token %}
<button type="submit" class="btn btn-sm btn-outline-secondary">{% trans "Add PCIe slots" %}</button>
</form>
{% endif %}
</div>
{% endwith %}
{% endif %}
</section>
</div>
<div role="tabpanel" class="tab-pane" id="network">
{# a row per NIC in one list, as the disks; its QoS limits fold out like its device details #}
<section aria-labelledby="nics-heading">
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-2">
<h2 class="h6 mb-0" id="nics-heading">{% trans "Network devices" %} <span class="text-body-secondary fw-normal">· {{ instance.config_networks|length }}</span></h2>
{% include 'add_instance_network_block.html' %}
</div>
<div class="card">
<div class="list-group list-group-flush">
{% for network in instance.config_networks %}
<article class="list-group-item py-3" aria-labelledby="nic-{{ forloop.counter0 }}">
<div class="row g-3 align-items-start small">
<div class="col-12 col-md-2">
<h3 class="h6 mb-1" id="nic-{{ forloop.counter0 }}">{% bs_icon 'ethernet' %} eth{{ forloop.counter0 }}</h3>
<div class="text-body-secondary text-break">{{ network.target|default:_("no target") }}</div>
</div>
<div class="col-12 col-md-6">
<div class="text-break"><span class="text-body-secondary">{% trans "Source" %}</span> <strong class="ms-1">{{ network.nic|default:"—" }}</strong></div>
<div class="mb-2"><span class="text-body-secondary">{% trans "IPv4" %}</span> <span class="ms-1">{{ network.ipv4|join:", "|default:_("unknown") }}</span></div>
<form action="{% url 'instances:set_link_state' instance.id %}" method="post" aria-label="{% trans "Link state form" %}">{% csrf_token %}
<input type="hidden" name="mac" value="{{ network.mac }}">
<input type="hidden" name="set_link_state" value="{{ network.state }}">
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" role="switch" id="link-{{ forloop.counter0 }}"{% if network.state == 'up' %} checked{% endif %} onchange="this.form.submit()">
<label class="form-check-label" for="link-{{ forloop.counter0 }}">{% if network.state == 'up' %}{% trans "Link up" %}{% else %}{% trans "Link down" %}{% endif %}</label>
</div>
</form>
</div>
<div class="col-12 col-md-4 d-flex flex-wrap justify-content-md-end gap-2">
{# a NIC that is a host device is changed in the XML editor #}
{% if network.type != "hostdev" %}
<button class="btn btn-sm btn-secondary" type="button" data-bs-toggle="modal" data-bs-target="#editInstanceNetwork{{ forloop.counter0 }}">{% trans "Edit" %}</button>
{% endif %}
<button class="btn btn-sm btn-secondary" type="button" data-bs-toggle="modal" data-bs-target="#AddQos{{ forloop.counter0 }}">{% trans "Add QoS" %}</button>
{% if network.type != "hostdev" %}
<form action="{% url 'instances:delete_network' instance.id %}" method="post" aria-label="{% trans "Delete network device form" %}">{% csrf_token %}
<button class="btn btn-sm btn-danger" value="{{ network.mac }}" name="delete_network"
data-confirm="{% blocktrans with mac=network.mac %}Remove network card {{ mac }}? A running VM loses its connection through it at once.{% endblocktrans %}">{% trans "Delete" %}</button>
</form>
{% endif %}
</div>
</div>
<details class="small mt-2">
<summary class="text-body-secondary">{% trans "Device details" %}</summary>
<dl class="row mb-0 mt-2" style="max-width: 32rem">
<dt class="col-4 fw-normal text-body-secondary">{% trans "Type" %}</dt><dd class="col-8 mb-1">{{ network.type }}</dd>
<dt class="col-4 fw-normal text-body-secondary">{% trans "MAC" %}</dt><dd class="col-8 mb-1 text-break">{{ network.mac }}</dd>
<dt class="col-4 fw-normal text-body-secondary">{% trans "Model" %}</dt><dd class="col-8 mb-1">{{ network.model|default:"—" }}</dd>
<dt class="col-4 fw-normal text-body-secondary">{% trans "NWFilter" %}</dt><dd class="col-8 mb-1 text-break">{{ network.filterref|default:_("None") }}</dd>
<dt class="col-4 fw-normal text-body-secondary">{% trans "IPv6" %}</dt><dd class="col-8 mb-1 text-break">{{ network.ipv6|join:", "|default:_("unknown") }}</dd>
</dl>
</details>
<details class="small">
<summary class="text-body-secondary">{% trans "QoS limits" %} · {% if network.inbound and network.outbound %}{% trans "inbound, outbound" %}{% elif network.inbound %}{% trans "inbound" %}{% elif network.outbound %}{% trans "outbound" %}{% else %}{% trans "none" %}{% endif %}</summary>
{% if network.inbound %}{% include 'instances/nic_qos_form.html' with nic=forloop.counter0 direction="inbound" limit=network.inbound %}{% endif %}
{% if network.outbound %}{% include 'instances/nic_qos_form.html' with nic=forloop.counter0 direction="outbound" limit=network.outbound %}{% endif %}
<p class="text-body-secondary mt-2 mb-0">{% trans "Average and peak are in KiB/s, burst in KiB. A running VM gets a change after it is powered off and on." %}</p>
</details>
{% if network.type == 'direct' %}
<p class="small text-body-secondary border-top pt-2 mt-2 mb-0">{% bs_icon 'info-circle' %} {% trans "In most configurations, macvtap does not work for host to guest network communication" %}</p>
{% endif %}
{# the dialogs of Edit and Add QoS #}
{% if network.type != "hostdev" %}
<form action="{% url 'instances:change_network' instance.id %}" method="post" name="edit_network{{ forloop.counter0 }}">{% csrf_token %}
<div class="modal fade" id="editInstanceNetwork{{ forloop.counter0 }}" tabindex="-1" aria-labelledby="editInstanceNetworkLabel{{ forloop.counter0 }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header align-items-start">
<div>
<h5 class="modal-title" id="editInstanceNetworkLabel{{ forloop.counter0 }}">{% blocktrans with nic=forloop.counter0 %}Edit eth{{ nic }}{% endblocktrans %}</h5>
<p class="small text-body-secondary mb-0 mt-1">{{ network.model|default:"—" }} · {{ network.mac }}</p>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
</div>
<div class="modal-body">
{% if instance.status != 5 %}
<p class="small text-body-secondary">{% trans "The VM is running: the changes apply at its next start." %}</p>
{% endif %}
<input type="hidden" name="net-old-mac-{{ forloop.counter0 }}" value="{{ network.mac }}">
<div class="row g-3">
<div class="col-12">
<label class="form-label" for="net-source-{{ forloop.counter0 }}">{% trans "Source" %}</label>
<select class="form-select" id="net-source-{{ forloop.counter0 }}" name="net-source-{{ forloop.counter0 }}">
{# the NIC keeps its source, whatever its kind, unless another is chosen #}
<option value="" selected>{% blocktrans with nic=network.nic|default:_("none") %}{{ nic }}, as it is{% endblocktrans %}</option>
<optgroup label="{% trans "Networks" %}">
{% for c_net in networks_host %}
<option value="net:{{ c_net }}">{{ c_net }}</option>
{% endfor %}
</optgroup>
<optgroup label="{% trans "Interfaces" %}">
{% for c_iface in interfaces_host %}
<option value="iface:{{ c_iface }}">{{ c_iface }}</option>
{% endfor %}
</optgroup>
</select>
</div>
<div class="col-sm-6">
<label class="form-label" for="net-model-{{ forloop.counter0 }}">{% trans "Model" %}</label>
<select class="form-select" id="net-model-{{ forloop.counter0 }}" name="net-model-{{ forloop.counter0 }}">
{% for model in net_models_host %}
<option value="{{ model }}"{% if model == network.model %} selected{% endif %}>{{ model }}</option>
{% endfor %}
</select>
</div>
<div class="col-sm-6">
<label class="form-label" for="net-nwfilter-{{ forloop.counter0 }}">{% trans "NWFilter" %}</label>
<select class="form-select" id="net-nwfilter-{{ forloop.counter0 }}" name="net-nwfilter-{{ forloop.counter0 }}">
<option value="">{% trans "None" %}</option>
{% for c_filters in nwfilters_host %}
<option value="{{ c_filters }}"{% if c_filters == network.filterref %} selected{% endif %}>{{ c_filters }}</option>
{% endfor %}
</select>
</div>
<div class="col-12">
<label class="form-label" for="net-mac-{{ forloop.counter0 }}">{% trans "MAC" %}</label>
<input class="form-control font-monospace" type="text" id="net-mac-{{ forloop.counter0 }}" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}">
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-outline-secondary" type="button" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button class="btn btn-primary" name="change_network">{% trans "Save" %}</button>
</div>
</div>
</div>
</div>
</form>
{% endif %}
<form action="{% url 'instances:set_qos' instance.id %}" method="post" name="add_qos{{ forloop.counter0 }}" aria-label="{% trans "Add network QoS form" %}">{% csrf_token %}
<input type="hidden" name="net-mac" value="{{ network.mac }}">
{% include 'add_network_qos.html' with id=forloop.counter0 %}
</form>
</article>
{% empty %}
<div class="list-group-item small text-body-secondary">{% trans "The VM has no network device." %}</div>
{% endfor %}
</div>
</div>
</section>
</div>
{% if show_hostdevs %}
<div role="tabpanel" class="tab-pane" id="hostdevs">
<p class="small text-body-secondary">{% trans "Devices of the host given to the VM. The VM starts only on a host that has them; it is not migrated while it has them, and its clones get none." %}</p>
{% if request.user.is_superuser %}
{# the add forms come when the tab opens: their choices scan every VM of the host #}
<div id="host-devices" class="mb-3" data-url="{% url 'instances:host_devices' instance.id %}">
<span class="small text-body-secondary">{% trans "Reading the host's devices…" %}</span>
</div>
{% endif %}
{% if usb_hostdevs %}
<div class="table-responsive position-relative">
<table class="table align-middle">
<thead>
<tr>
<th scope="col">{% trans "USB device" %}</th>
<th scope="col">{% trans "Chosen by" %}</th>
<th scope="col">{% trans "Running VM" %}</th>
<th scope="col">{% trans "Next start" %}</th>
{% if request.user.is_superuser %}<th scope="col"><span class="visually-hidden">{% trans "Actions" %}</span></th>{% endif %}
</tr>
</thead>
<tbody>
{% for device in usb_hostdevs %}
<tr>
<td>{{ device.name|default:"–" }} <span class="small text-body-secondary font-monospace">{{ device.vendor|slice:"2:" }}:{{ device.product|slice:"2:" }}</span></td>
<td>{% if device.address %}{% blocktrans with bus=device.address.0 device=device.address.1 %}Its address {{ bus }}/{{ device }}{% endblocktrans %}{% else %}{% trans "Its model: any device of it" %}{% endif %}</td>
<td>{% if device.now %}{% blocktrans with bus=device.now.0 device=device.now.1 %}Has {{ bus }}/{{ device }}{% endblocktrans %}{% else %}–{% endif %}</td>
<td>{% if device.next %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}</td>
{% if request.user.is_superuser %}
<td class="text-end">
<form method="post" action="{% url 'instances:delete_usb_hostdev' instance.id %}">{% csrf_token %}
<input type="hidden" name="vendor" value="{{ device.vendor }}">
<input type="hidden" name="product" value="{{ device.product }}">
<input type="hidden" name="address" value="{% if device.address %}{{ device.address.0 }}/{{ device.address.1 }}{% endif %}">
<button type="submit" class="btn btn-sm btn-outline-danger" aria-label="{% trans "Remove the USB device" %}"
data-confirm="{% trans "Remove this USB device from the VM? A running VM loses it at once." %}">{% bs_icon 'trash' %}</button>
</form>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% if pci_hostdevs %}
<div class="table-responsive position-relative">
<table class="table align-middle">
<thead>
<tr>
<th scope="col">{% trans "PCI device" %}</th>
<th scope="col">{% trans "Running VM" %}</th>
<th scope="col">{% trans "Next start" %}</th>
{% if request.user.is_superuser %}<th scope="col"><span class="visually-hidden">{% trans "Actions" %}</span></th>{% endif %}
</tr>
</thead>
<tbody>
{% for device in pci_hostdevs %}
<tr>
<td>{{ device.name|default:"–" }} <span class="small text-body-secondary font-monospace">{{ device.address }}</span></td>
<td>{% if device.now %}{% trans "Has it" %}{% else %}–{% endif %}</td>
<td>{% if device.next %}{% trans "Yes" %}{% else %}{% trans "No" %}{% endif %}</td>
{% if request.user.is_superuser %}
<td class="text-end">
<form method="post" action="{% url 'instances:delete_pci_hostdev' instance.id %}">{% csrf_token %}
<input type="hidden" name="address" value="{{ device.address }}">
<button type="submit" class="btn btn-sm btn-outline-danger" aria-label="{% trans "Remove the PCI device" %}"
{% if instance.status != 1 and instance.status != 5 or instance.has_managed_save_image %}disabled title="{% trans "A paused VM, or one with a saved state, does not change its PCI devices" %}"{% endif %}
data-confirm="{% trans "Remove this PCI device from the VM? A running VM's guest has to let it go." %}">{% bs_icon 'trash' %}</button>
</form>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% for device in other_hostdevs %}
<p class="mb-1">
{% if device.type == "nic" %}{% trans "Network interface" %}{% else %}{{ device.type|upper }}{% endif %} <span class="font-monospace">{{ device.address }}</span>
<span class="small text-body-secondary">{% if device.now and device.next %}{% trans "running VM and next start" %}{% elif device.now %}{% trans "running VM only" %}{% else %}{% trans "next start only" %}{% endif %}; {% trans "changed in the XML editor" %}</span>
</p>
{% endfor %}
{% if not usb_hostdevs and not pci_hostdevs and not other_hostdevs %}
<p class="small text-body-secondary mb-0">{% trans "The VM has no host devices." %}</p>
{% endif %}
</div>
{% endif %}
<div role="tabpanel" class="tab-pane" id="migrate">
<form action="{% url 'instances:migrate' instance.id %}" method="post" aria-labelledby="migrate-route">{% csrf_token %}{% submission_key %}
<header class="border-bottom pb-3 mb-4">
<h2 class="h6" id="migrate-route">{% trans "Migration route" %}</h2>
<div class="row g-2 align-items-end">
<div class="col">
<label class="form-label small" for="migrate-from">{% trans "From" %}</label>
<input class="form-control" id="migrate-from" value="{{ compute.name }}" readonly>
</div>
<div class="col-auto pb-2 text-body-secondary" aria-hidden="true">→</div>
<div class="col">
<label class="form-label small" for="migrate_compute">{% trans "To" %}</label>
<select class="form-select" name="compute_id" id="migrate_compute">
{% for comp in computes %}
{% if comp.id != compute.id %}<option value="{{ comp.id }}">{{ comp.name }}</option>{% endif %}
{% endfor %}
</select>
</div>
</div>
<p class="small text-body-secondary mt-3 mb-0">
{% if instance.status == 1 %}{% trans "The VM is running: it migrates live, or paused for the transfer when Live migration is off." %}
{% elif instance.status == 3 %}{% trans "The VM is paused: it stays paused on the destination." %}
{% elif instance.status == 5 %}{% trans "The VM is shut off: it moves offline." %}{% endif %}
{% trans "Both hosts need the same emulator; the VM's definition leaves the source host." %}
</p>
</header>
{# a VM that cannot go anywhere gets the reason, not the disks and settings #}
{% if not migrate_refusal %}
<section class="card mb-3" aria-labelledby="migrate-storage">
<div class="card-body">
<h2 class="h6 mb-3" id="migrate-storage">{% bs_icon 'device-hdd' %} {% trans "Storage" %}</h2>
<div id="migrate-plan" data-url="{% url 'instances:migrate_plan' instance.id %}" data-targets-url="{% url 'instances:migrate_targets' instance.id %}" aria-live="polite"></div>
</div>
</section>
<section class="card mb-4" aria-labelledby="migrate-transfer">
<div class="card-body">
<h2 class="h6 mb-3" id="migrate-transfer">{% bs_icon 'arrow-left-right' %} {% trans "Transfer settings" %}</h2>
<div class="row g-3">
{% if instance.status == 1 or instance.status == 3 %}
<div class="col-12 col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="live_migrate" value="true" id="vm_live_migrate" aria-describedby="live-help" checked>
<label class="form-check-label fw-semibold" for="vm_live_migrate">{% trans "Live migration" %}</label>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="live-help">{% trans "The VM keeps running while its memory is copied. Off, it is paused for the transfer." %}</p>
</div>
{% endif %}
{% if instance.status == 1 %}
<div class="col-12 col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="autoconverge" value="true" id="autoconverge" aria-describedby="autoconverge-help" checked>
<label class="form-check-label fw-semibold" for="autoconverge">{% trans "Auto converge" %}</label>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="autoconverge-help">{% trans "Slows the guest's CPUs so that a busy VM's live migration can finish. Only with Live migration." %}</p>
</div>
<div class="col-12 col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="compress" value="true" id="compress" aria-describedby="compress-help">
<label class="form-check-label fw-semibold" for="compress">{% trans "Compressed" %}</label>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="compress-help">{% trans "Compresses the memory sent: less network, more CPU on both hosts." %}</p>
</div>
<div class="col-12 col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="unsafe_migrate" value="true" id="vm_unsafe_migrate" aria-describedby="unsafe-help">
<label class="form-check-label fw-semibold" for="vm_unsafe_migrate">{% trans "Unsafe migration" %}</label>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="unsafe-help">{% trans "Skips libvirt's safety checks, such as a disk cache mode that can corrupt data in a migration." %}</p>
</div>
{% endif %}
<div class="col-12 col-md-6">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="delete_source" value="true" id="delete_source" aria-describedby="delete-source-help">
<label class="form-check-label fw-semibold" for="delete_source">{% trans "Delete the source files of copied disks" %}</label>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="delete-source-help">{% trans "After a migration that copied disks, their files on the source host go. Disks on shared storage stay." %}</p>
</div>
</div>
</div>
</section>
{% endif %}
<footer class="border-top pt-3">
{% if migrate_refusal %}<p class="small text-body-secondary mb-2">{{ migrate_refusal }}</p>{% endif %}
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
<p class="small text-body-secondary mb-0">{% trans "Migration runs as a background job." %}</p>
{% if migrate_refusal %}
<button type="button" class="btn btn-primary ms-auto" disabled>{% trans "Migrate" %}</button>
{% else %}
{# enabled once the disks of the chosen destination are shown #}
<button type="submit" class="btn btn-primary ms-auto" name="migrate" disabled>{% trans "Migrate" %}</button>
{% endif %}
</div>
</footer>
</form>
<div class="clearfix"></div>
</div>
<div role="tabpanel" class="tab-pane" id="xmledit">
{% if instance.status != 5 %}
<p class="small text-body-secondary" id="xml-next-start">{% trans "This is the definition for the VM's next start; a saved change applies then." %}</p>
{% endif %}
<form action="{% url 'instances:change_xml' instance.id %}" method="post" role="form" aria-label="Edit instance XML form" id="xml-form">
{% csrf_token %}
<div class="col-sm-12 xmlheight">
<textarea id="editor">{{ instance.inst_xml }}</textarea>
</div>
<button type="submit" class="btn btn-primary float-end" name="change_xml">{% trans "Review changes" %}</button>
</form>
<div class="clearfix"></div>
<div class="modal fade" id="xml-review" tabindex="-1" aria-labelledby="xml-review-title" aria-hidden="true"
data-failed="{% trans "The request did not go through; your edit is still in the editor. Try again, or copy it and reload the page." %}">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="xml-review-title">{% trans "Review the XML change" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
</div>
<div class="modal-body">
<div class="alert alert-danger d-none" role="alert" id="xml-review-error"></div>
<p class="d-none" id="xml-review-same">{% trans "The XML is the same as the VM's definition; there is nothing to save." %}</p>
<pre class="d-none mb-0" id="xml-review-diff"></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="button" class="btn btn-primary" id="xml-review-save">{% trans "Save" %}</button>
</div>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="users">
<section aria-labelledby="owners-heading">
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-2">
<h2 class="h6 mb-0" id="owners-heading">{% trans "Instance owners" %}</h2>
{% include 'add_instance_owner_block.html' %}
</div>
<p class="small text-body-secondary">{% trans "Every owner can power the VM and open its console. A new owner has no other right until it is given one." %}</p>
{% if userinstances %}
<ul class="list-group">
{% for userinstance in userinstances %}
<li class="list-group-item p-3">
<div class="row g-3 align-items-center">
<div class="col-12 col-md">
<a class="fw-semibold text-break" href="{% url 'accounts:account' userinstance.user.id %}">{{ userinstance.user }}</a>
<p class="small mb-0 mt-1">
{% if userinstance.is_change or userinstance.is_delete %}
{% if userinstance.is_change %}{% trans "Change settings" %}{% endif %}{% if userinstance.is_change and userinstance.is_delete %} · {% endif %}{% if userinstance.is_delete %}{% trans "Delete the VM" %}{% endif %}{% if userinstance.is_change and userinstance.is_vnc %} · {% trans "Change console settings" %}{% endif %}
{% else %}
<span class="text-body-secondary">{% trans "Power and console only" %}</span>
{% endif %}
</p>
</div>
{% if request.user.is_superuser %}
<div class="col-12 col-md-auto d-flex flex-wrap gap-2">
<a class="btn btn-sm btn-secondary" href="{% url 'accounts:user_instance_update' userinstance.id %}?next={% filter urlencode:'' %}{% url 'instances:instance' instance.id %}#users{% endfilter %}">{% trans "Edit rights" %}<span class="visually-hidden"> {{ userinstance.user }}</span></a>
<a class="btn btn-sm btn-danger" href="{% url 'accounts:user_instance_delete' userinstance.id %}?next={% filter urlencode:'' %}{% url 'instances:instance' instance.id %}#users{% endfilter %}">{% trans "Remove" %}<span class="visually-hidden"> {{ userinstance.user }}</span></a>
</div>
{% endif %}
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p class="mb-0">{% trans "The VM has no owner: only administrators can use it." %}</p>
{% endif %}
</section>
</div>
{% endif %}
{% if can_manage_console %}
<div role="tabpanel" class="tab-pane" id="vncsettings">
<form method="post" action="{% url 'instances:update_console' instance.id %}" aria-label="{% trans "Console settings" %}">{% csrf_token %}
{% if instance.status != 5 %}
<p class="small text-body-secondary">{% trans "The running console keeps its current settings; changes here apply after the VM is shut down and started." %}</p>
{% endif %}
<section class="mb-4" aria-labelledby="console-heading">
<h2 class="h6" id="console-heading">{% trans "Console" %}</h2>
<label class="form-label" for="{{ console_form.console_type.id_for_label }}">{{ console_form.console_type.label }}</label>
{{ console_form.console_type }}
{% if console_form.keymap %}
<p class="small text-body-secondary mt-1 mb-0">{% trans "The settings below apply to a VNC console." %}</p>
{% else %}
<p class="small text-body-secondary mt-1 mb-0">{% trans "The VNC settings appear once the console type VNC is saved." %}</p>
{% endif %}
</section>
{% if console_form.keymap %}
<div class="row g-3 mb-3">
<div class="col-12 col-lg-6">
<section class="card h-100" aria-labelledby="console-connection">
<div class="card-body">
<h2 class="h6 mb-3" id="console-connection">{% bs_icon 'display' %} {% trans "VNC connection" %}</h2>
<div class="mb-4">
<label class="form-label" for="{{ console_form.listen_on.id_for_label }}">{{ console_form.listen_on.label }}</label>
{{ console_form.listen_on }}
<p class="small text-body-secondary mt-1 mb-0">
{% if not request.user.is_superuser %}{% trans "Only administrators can change this." %} {% endif %}{% trans "Beyond localhost the console is reachable from the network." %}
</p>
</div>
<label class="form-label" for="{{ console_form.keymap.id_for_label }}">{{ console_form.keymap.label }}</label>
{{ console_form.keymap }}
</div>
</section>
</div>
<div class="col-12 col-lg-6">
<section class="card h-100" aria-labelledby="console-password">
<div class="card-body">
<h2 class="h6 mb-3" id="console-password">{% bs_icon 'key' %} {% trans "VNC password" %}</h2>
<fieldset>
<legend class="fs-6 mb-1">{{ console_form.password_action.label }}</legend>
<p class="small text-body-secondary mb-2">{% if instance.config_console_passwd %}{% trans "A password is set." %}{% else %}{% trans "No password is set." %}{% endif %}</p>
{% for choice in console_form.password_action %}
<div class="form-check">
{{ choice.tag }}
<label class="form-check-label" for="{{ choice.id_for_label }}">{{ choice.choice_label }}</label>
</div>
{% endfor %}
</fieldset>
<label class="form-label mt-3" for="{{ console_form.password.id_for_label }}">{{ console_form.password.label }}</label>
{{ console_form.password }}
<p class="small text-body-secondary mt-1 mb-0">{% trans "Up to 8 characters (an accented letter counts as two), used with \"Set a new one\"." %}</p>
</div>
</section>
</div>
</div>
{% endif %}
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-sm btn-primary">{% trans "Save console settings" %}</button>
</div>
</form>
</div>
{% endif %}
{% if can_clone %}
<div role="tabpanel" class="tab-pane" id="clone">
<form action="{% url 'instances:clone' instance.id %}" method="post" aria-labelledby="clone-heading">{% csrf_token %}{% submission_key %}
<header class="mb-4">
<h2 class="h6 mb-1" id="clone-heading">{% trans "Create a clone" %}</h2>
<p class="small text-body-secondary mb-0">{% blocktrans with name=instance.name %}Source VM: {{ name }}{% endblocktrans %}</p>
{% if instance.config_tpm == "emulator" %}
<p class="small text-body-secondary mb-0" id="clone-tpm">{% trans "The clone gets a new, empty TPM: keys in this VM's TPM, such as BitLocker's, do not come along." %}</p>
{% endif %}
</header>
<div class="mb-4">
{% if request.user.is_superuser %}
<label class="form-label" for="clone_name">{% trans "Clone name" %}</label>
<div class="row g-2">
<div class="col-12 col-sm">
<input class="form-control" id="clone_name" name="name" type="text" value="{{ instance.name }}-clone" aria-describedby="clone-name-help">
</div>
<div class="col-12 col-sm-auto">
<button class="btn btn-secondary" type="button" onclick="guess_clone_name()">{% trans "Guess" %}</button>
</div>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="clone-name-help"></p>
{% elif app_settings.CLONE_INSTANCE_AUTO_NAME == 'True' %}
<label class="form-label" for="clone_instance_auto_name">{% trans "Clone name" %}</label>
<input class="form-control" id="clone_instance_auto_name" type="text" value="{% trans "Automatic" %}" disabled>
{% else %}
<label class="form-label" for="select_clone_name">{% trans "Clone name" %}</label>
<select class="form-select" id="select_clone_name" name="name">
{% for name in clone_free_names %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
{% endif %}
</div>
{% if request.user.is_superuser %}
<div class="row g-3 mb-4">
{% if instance.config_networks %}
<div class="col-12 col-lg-6">
<section class="card h-100" aria-labelledby="clone-network-heading">
<div class="card-body">
<h3 class="h6 mb-3" id="clone-network-heading">{% bs_icon 'ethernet' %} {% trans "Network" %}</h3>
{% for network in instance.config_networks %}
<div{% if not forloop.first %} class="border-top pt-3 mt-3"{% endif %}>
<p class="small mb-2"><strong>eth{{ forloop.counter0 }}</strong> <span class="text-body-secondary">· {{ network.nic }}</span></p>
<label class="form-label small" for="clone-net-mac-{{ forloop.counter0 }}">{% trans "New MAC address" %}</label>
<input class="form-control" id="clone-net-mac-{{ forloop.counter0 }}" name="clone-net-mac-{{ forloop.counter0 }}" type="text" value="{{ network.mac }}">
<div class="d-flex flex-wrap gap-2 mt-2">
<button class="btn btn-sm btn-secondary" type="button" onclick="random_mac('clone-net-mac-{{ forloop.counter0 }}')">{% trans "Random" %}</button>
{% if forloop.first %}
{# the DHCP host entry of the clone's name holds one address: the first NIC's #}
<button class="btn btn-sm btn-secondary" type="button" onclick="guess_mac_address('#clone_name', 0)">{% trans "Guess" %}</button>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</section>
</div>
{% endif %}
<div class="col-12{% if instance.config_networks %} col-lg-6{% endif %}">
<section class="card h-100" aria-labelledby="clone-storage-heading">
<div class="card-body">
<h3 class="h6 mb-3" id="clone-storage-heading">{% bs_icon 'device-hdd' %} {% trans "Storage" %}</h3>
{% for disk in instance.config_disks %}
<div{% if not forloop.first %} class="border-top pt-3 mt-3"{% endif %}>
<p class="small mb-2"><strong>{{ disk.dev }}</strong> <span class="text-body-secondary">· {% blocktrans with pool=disk.storage %}Pool: {{ pool }}{% endblocktrans %} · {{ disk.format }}</span></p>
<label class="form-label small" for="disk_name-{{ disk.dev }}">{% trans "New volume name" %}</label>
<input class="form-control" id="disk_name-{{ disk.dev }}" name="disk-{{ disk.dev }}" type="text" value="{{ disk.image }}">
{# a running or paused VM's disks are copied by a backup job, which does not preallocate #}
{% if disk.format == 'qcow2' and instance.status == 5 %}
<div class="form-check mt-2">
<input class="form-check-input" id="meta-{{ disk.dev }}" name="meta-{{ disk.dev }}" type="checkbox" value="true">
<label class="form-check-label small" for="meta-{{ disk.dev }}">{% trans "Preallocate qcow2 metadata" %}</label>
</div>
{% endif %}
</div>
{% empty %}
<p class="small text-body-secondary mb-0">{% trans "The VM has no disk to copy." %}</p>
{% endfor %}
</div>
</section>
</div>
</div>
{% endif %}
<fieldset class="mb-4" aria-describedby="clone-size-help">
<legend class="h6">{% trans "Size" %}</legend>
<div class="row g-3">
<div class="col-6 col-md-3">
<label class="form-label" for="clone-vcpu">{% trans "vCPUs" %}</label>
<input class="form-control" id="clone-vcpu" name="clone-vcpu" type="number" min="1" max="{{ vcpu_host }}" inputmode="numeric" value="{{ instance.config_vcpu }}">
</div>
<div class="col-6 col-md-3">
<label class="form-label" for="clone-memory">{% trans "Memory (MiB)" %}</label>
<input class="form-control" id="clone-memory" name="clone-memory" type="number" min="1" inputmode="numeric" value="{{ instance.config_memory }}">
</div>
</div>
<p class="small text-body-secondary mt-1 mb-2" id="clone-size-help">{% trans "The VM's size to start from; the quota counts the larger of the two." %}</p>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="clone-start" name="clone-start" value="true">
<label class="form-check-label" for="clone-start">{% trans "Start the clone when it is made" %}</label>
</div>
</fieldset>
<fieldset class="mb-4">
<legend class="h6">{% trans "Optional details" %}</legend>
<label class="form-label" for="clone-title">{% trans "Title" %}</label>
<input class="form-control mb-3" id="clone-title" name="clone-title" type="text">
<label class="form-label" for="clone-description">{% trans "Description" %}</label>
<textarea class="form-control" id="clone-description" name="clone-description" rows="3"></textarea>
</fieldset>
<footer class="border-top pt-3">
{% if usb_hostdevs or pci_hostdevs or other_hostdevs %}
<p class="small text-body-secondary mb-2">{% trans "The clone gets none of the VM's host devices: one VM holds a device of the host." %}</p>
{% endif %}
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
<p class="small text-body-secondary mb-0">{% trans "Cloning runs as a background job." %}</p>
{% if instance.status == 1 or instance.status == 3 or instance.status == 5 %}
<button type="submit" class="btn btn-primary ms-auto" name="clone">{% trans "Clone" %}</button>
{% else %}
<button type="button" class="btn btn-primary ms-auto" disabled name="clone">{% trans "Clone" %}</button>
{% endif %}
</div>
</footer>
</form>
<div class="clearfix"></div>
</div>
{% endif %}
{% if can_change %}
<div role="tabpanel" class="tab-pane" id="options">
<div class="list-group">
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:change_options' instance.id %}" method="post" aria-labelledby="options-details">{% csrf_token %}
<div class="row g-3">
<div class="col-12 col-lg-4">
<h2 class="h6" id="options-details">{% bs_icon 'pencil-square' %} {% trans "VM details" %}</h2>
<p class="small text-body-secondary mb-0">{% trans "A title and description to identify the VM." %}</p>
</div>
<div class="col-12 col-lg-8">
<label class="form-label" for="options-title">{% trans "Title" %}</label>
<input class="form-control mb-3" type="text" id="options-title" name="title" value="{{ instance.config_title }}">
<label class="form-label" for="options-description">{% trans "Description" %}</label>
<textarea class="form-control mb-3" id="options-description" name="description" rows="2">{{ instance.config_description }}</textarea>
<div class="text-end">
<button class="btn btn-primary" type="submit" name="change_options">{% trans "Save" %}</button>
</div>
</div>
</div>
</form>
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:set_template' instance.id %}" method="post">{% csrf_token %}
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold mb-0" for="is_template">{% trans "Template" %}</label>
<p class="small text-body-secondary mb-0" id="template-help">{% trans "A template is a VM to clone: it is not counted in quotas and cannot be started." %}</p>
</div>
<div class="col-12 col-lg-8">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="is_template" value="True" id="is_template" aria-describedby="template-help template-state"
{% if instance.is_template %}checked{% endif %}
{% if instance.status != 5 or not request.user.is_superuser and not request.user.is_staff %}disabled{% endif %} onchange="this.form.submit()">
<label class="form-check-label" for="is_template">{% trans "Use as a template" %}</label>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="template-state">
{% if not request.user.is_superuser and not request.user.is_staff %}{% trans "Only administrators and staff can change this." %}
{% elif instance.status != 5 %}{% trans "Shut the VM down to change this." %}{% endif %}
</p>
</div>
</div>
</form>
{% if request.user.is_superuser %}
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:set_video_model' instance.id %}" method="post">{% csrf_token %}
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold mb-0" for="video_model_select">{% trans "Primary video model" %}</label>
<p class="small text-body-secondary mb-0" id="video-help">{% trans "The graphics device the guest sees." %}</p>
</div>
<div class="col-12 col-lg-8">
<div class="row g-2">
<div class="col-12 col-sm">
<select id="video_model_select" class="form-select" name="video_model" aria-describedby="video-help">
{% for vmodel in instance.video_models %}
<option value="{{ vmodel }}"{% if vmodel == instance.config_video_model %} selected{% endif %}>{{ vmodel }}</option>
{% endfor %}
</select>
</div>
<div class="col-12 col-sm-auto d-grid">
<button class="btn btn-secondary" type="submit" name="set_video_model">{% trans "Save" %}</button>
</div>
</div>
</div>
</div>
</form>
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:set_rng' instance.id %}" method="post">{% csrf_token %}
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold mb-0" for="rng">{% trans "Random number generator" %}</label>
<p class="small text-body-secondary mb-0" id="rng-help">{% trans "A virtio device that feeds the guest's entropy from the host: a new VM does not wait for it at boot. From the next start." %}</p>
</div>
<div class="col-12 col-lg-8">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="rng" value="True" id="rng" aria-describedby="rng-help rng-state"
{% if instance.config_rng %}checked{% endif %}{% if instance.config_rng == "custom" %} disabled{% endif %} onchange="this.form.submit()">
<label class="form-check-label" for="rng">{% trans "Virtio RNG" %}</label>
</div>
{% if instance.config_rng == "custom" %}
<p class="small text-body-secondary mt-1 mb-0" id="rng-state">{% trans "The VM has its own RNG device: change it in the XML editor." %}</p>
{% endif %}
</div>
</div>
</form>
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:set_tpm' instance.id %}" method="post">{% csrf_token %}
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold mb-0" for="tpm">{% trans "TPM" %}</label>
<p class="small text-body-secondary mb-0" id="tpm-help">{% trans "An emulated TPM 2.0, as Windows 11 needs with UEFI Secure Boot. Its state stays on the host until the VM is destroyed: a TPM added again has it back. From the next start." %}</p>
</div>
<div class="col-12 col-lg-8">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="tpm" value="True" id="tpm" aria-describedby="tpm-help tpm-state"
{% if instance.config_tpm %}checked{% endif %}{% if instance.config_tpm == "custom" or not instance.config_tpm and not tpm_support %} disabled{% endif %} onchange="this.form.submit()">
<label class="form-check-label" for="tpm">{% trans "TPM 2.0" %}</label>
</div>
{% if instance.config_tpm == "custom" %}
<p class="small text-body-secondary mt-1 mb-0" id="tpm-state">{% trans "The VM has its own TPM: change it in the XML editor." %}</p>
{% elif not instance.config_tpm and not tpm_support %}
<p class="small text-body-secondary mt-1 mb-0" id="tpm-state">{% trans "This host offers no TPM 2.0: install swtpm on it." %}</p>
{% endif %}
</div>
</div>
</form>
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:set_on_crash' instance.id %}" method="post">{% csrf_token %}
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold mb-0" for="on_crash">{% trans "When the guest crashes" %}</label>
<p class="small text-body-secondary mb-0" id="on-crash-help">{% trans "For a crash the guest reports, not a hang. Stop keeps a VM that crashes again and again down for a look. From the next start." %}</p>
</div>
<div class="col-12 col-lg-8">
{% if instance.config_on_crash == "restart" or instance.config_on_crash == "destroy" %}
<div class="row g-2">
<div class="col-12 col-sm">
<select id="on_crash" class="form-select" name="on_crash" aria-describedby="on-crash-help">
<option value="restart"{% if instance.config_on_crash == "restart" %} selected{% endif %}>{% trans "Restart" %}</option>
<option value="destroy"{% if instance.config_on_crash == "destroy" %} selected{% endif %}>{% trans "Stop" %}</option>
</select>
</div>
<div class="col-12 col-sm-auto d-grid">
<button class="btn btn-secondary" type="submit" name="set_on_crash">{% trans "Save" %}</button>
</div>
</div>
{% else %}
<p class="small mb-0" id="on_crash">{% blocktrans with action=instance.config_on_crash %}{{ action }}: change it in the XML editor.{% endblocktrans %}</p>
{% endif %}
</div>
</div>
</form>
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:set_guest_agent' instance.id %}" method="post">{% csrf_token %}
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold mb-0" for="guest_agent">{% trans "QEMU guest agent" %}</label>
<p class="small text-body-secondary mb-0" id="agent-help">{% trans "The channel to the agent in the guest: a running VM gets it at once." %}</p>
<p class="small mt-2 mb-0">{% trans "Agent" %}:
{% if instance.status != 1 and instance.status != 3 %}<span class="badge bg-secondary">{% trans "VM not running" %}</span>
{% elif not instance.guest_agent %}<span class="badge bg-secondary">{% trans "No channel" %}</span>
{% elif instance.guest_agent_ready %}<span class="badge bg-success">{% trans "Connected" %}</span>
{% else %}<span class="badge bg-danger">{% trans "Not connected" %}</span>{% endif %}
</p>
</div>
<div class="col-12 col-lg-8">
<div class="row g-2">
<div class="col-12 col-sm">
<select id="guest_agent" class="form-select" name="guest_agent" aria-describedby="agent-help">
<option value="True"{% if instance.config_guest_agent %} selected{% endif %}>{% trans "Enabled" %}</option>
<option value="False"{% if not instance.config_guest_agent %} selected{% endif %}>{% trans "Disabled" %}</option>
</select>
</div>
<div class="col-12 col-sm-auto d-grid">
<button class="btn btn-secondary" type="submit" name="set_guest_agent">{% trans "Save" %}</button>
</div>
</div>
</div>
</div>
</form>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
</div>