1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 04:36:48 +00:00
webvirtcloud/instances/templates/instances/settings_tab.html
catborise 3911e9e238 style(instances): the Console tab asks for a new password only with "Set a new one"
The New password field sits under the "Set a new one" choice and shows
only while it is chosen, so its help no longer has to say so. The Console
heading above the Console type label goes, and the save button has the
size of the other tabs' main buttons.
2026-11-04 15:15:12 +03:00

994 lines
80 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 nav-fill 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">
<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">
{# the devices the VM tries in turn when it starts, and those it does not try; each moves on its own #}
<section class="mb-4" 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 "When the VM starts it tries these devices in turn and boots from the first that works." %}</p>
<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">
<ol id="boot-chain" class="boot-chain list-unstyled mb-0">
{% for device in instance.config_boot_devices %}{% if device.checked %}{% include "instances/boot_device.html" %}{% endif %}{% endfor %}
</ol>
<p class="small text-body-secondary py-2 mb-0" id="boot-chain-empty"{% if instance.config_boot_devices.0.checked %} hidden{% endif %}>
{% if instance.config_boot_types %}{% blocktrans with types=instance.config_boot_types %}The VM boots by device type: {{ types }}. Add a device to choose the order yourself.{% endblocktrans %}
{% else %}{% trans "No device is in the boot order. Add one." %}{% endif %}
</p>
<h3 class="h6 small text-body-secondary mt-3 mb-1">{% trans "Not in the boot order" %}</h3>
<ul id="boot-spare" class="boot-spare list-unstyled mb-3">
{% for device in instance.config_boot_devices %}{% if not device.checked %}{% include "instances/boot_device.html" %}{% endif %}{% endfor %}
</ul>
<button type="submit" class="btn btn-sm btn-primary">{% trans "Save order" %}</button>
</form>
</section>
<section class="border-top pt-3" aria-labelledby="startup-heading">
<h2 class="h6" id="startup-heading">{% trans "Startup settings" %}</h2>
<div class="row g-3">
<form class="col-12 col-md-6" 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 %} data-submit-on-change>
<label class="form-check-label" for="autostart">{% trans "Autostart" %}</label>
</div>
<p class="small text-body-secondary mb-0" id="autostart-help">{% trans "Start this VM when the host starts." %}</p>
</form>
<form class="col-12 col-md-6" 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 %} data-submit-on-change>
<label class="form-check-label" for="bootmenu">{% trans "Boot menu" %}</label>
</div>
<p class="small text-body-secondary mb-0" id="bootmenu-help">{% trans "Show a device chooser when the VM starts." %}</p>
</form>
</div>
</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>
<div class="d-flex gap-2">
{# the pools are read again: an ISO image copied to one by hand is listed then #}
<form method="post" action="{% url 'instances:refresh_iso' instance.id %}">{% csrf_token %}
<button type="submit" class="btn btn-sm btn-outline-secondary" title="{% trans "Read the storage pools again: an ISO image copied to a pool by hand is listed then" %}">{% bs_icon 'arrow-clockwise' %} {% trans "Refresh ISO list" %}</button>
</form>
{% include 'add_instance_cdrom.html' %}
</div>
</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-outline-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-outline-secondary" 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-outline-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-outline-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 }}">
{# the NIC as a cable from the VM to its source: solid while its link is up, dashed while down #}
<div class="d-flex flex-wrap align-items-center column-gap-3 row-gap-2">
<div class="d-flex align-items-center gap-2 me-auto text-break">
<h3 class="h6 mb-0" id="nic-{{ forloop.counter0 }}">eth{{ forloop.counter0 }}</h3>
<span class="nic-wire{% if network.state == 'up' %} nic-up{% endif %}" aria-hidden="true"></span>
<span class="fw-semibold">{{ network.nic|default:"—" }}</span>
</div>
<div class="d-flex flex-wrap 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-outline-secondary" type="button" data-bs-toggle="modal" data-bs-target="#editInstanceNetwork{{ forloop.counter0 }}">{% trans "Edit" %}</button>
{% endif %}
<button class="btn btn-sm btn-outline-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-outline-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>
<div class="d-flex flex-wrap align-items-center column-gap-4 row-gap-1 mt-2">
<span class="text-break">{% if network.ipv4 %}{{ network.ipv4|join:", " }}{% else %}<span class="text-body-secondary">{% trans "No IPv4 address known" %}</span>{% endif %}</span>
<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 small">
<input class="form-check-input" type="checkbox" role="switch" id="link-{{ forloop.counter0 }}"{% if network.state == 'up' %} checked{% endif %} data-submit-on-change>
<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="small text-body-secondary text-break mt-1">{{ network.model|default:"—" }}, {{ network.mac }}{% if network.filterref %}, {% blocktrans with filter=network.filterref %}filter {{ filter }}{% endblocktrans %}{% endif %}{% if network.inbound or network.outbound %}, {% trans "bandwidth limited" %}{% endif %}</div>
{% if network.type == 'direct' %}
<p class="small text-body-secondary mt-1 mb-0">{% trans "In most configurations, macvtap does not work for host to guest network communication" %}</p>
{% endif %}
<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 "Host device" %}</dt><dd class="col-8 mb-1 text-break">{{ network.target|default:_("no target") }}</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>
{% if network.inbound or network.outbound %}
<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" %}{% else %}{% trans "outbound" %}{% 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>
{% 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 %}" data-failed="{% trans "The host's devices could not be read." %}">
<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"
data-checking-hosts="{% trans "Checking the hosts…" %}" data-hosts-failed="{% trans "The hosts could not be checked." %}"
data-no-host="{% trans "No host can take the VM now." %}" data-checking-disks="{% trans "Checking the disks…" %}"
data-disks-failed="{% trans "The disks could not be checked." %}"></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>
{% if instance.status == 1 or instance.status == 3 %}
<div class="row g-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>
{% 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>
{% endif %}
</div>
{% endif %}
{# the switches that can lose data, set apart from how the memory moves #}
<div{% if instance.status == 1 or instance.status == 3 %} class="border-top pt-3 mt-3"{% endif %}>
<div class="row g-3">
{% 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="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-danger 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-danger 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>
</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="xml-editor mb-3">
<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 xml-diff" id="xml-review-diff" data-line="{% blocktrans with line="__line__" %}Line {{ line }}{% endblocktrans %}"></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-outline-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-outline-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 %}
<div class="mb-4">
<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 %}
</div>
{% 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>
{% if choice.data.value == "set" %}
{# shown while "Set a new one" is chosen (webvirtcloud.css) #}
<div class="console-new-password ms-4 mt-1 mb-2">
<label class="form-label small" 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." %}</p>
</div>
{% endif %}
{% endfor %}
</fieldset>
</div>
</section>
</div>
</div>
{% endif %}
<div class="d-flex justify-content-end">
<button type="submit" class="btn 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"
data-source="{{ instance.name }}" data-guess-url="{% url 'instances:guess_clone_name' %}"
data-guess-mac-url="{% url 'instances:guess_mac_address' '__name__' %}">
</div>
<div class="col-12 col-sm-auto">
<button class="btn btn-outline-secondary" type="button" id="guess-clone-name">{% trans "Guess" %}</button>
</div>
</div>
<p class="small text-body-secondary mt-1 mb-0" id="clone-name-help" data-no-name="{% trans "The DHCP file has no free name to suggest." %}"></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>
<div class="input-group">
<input class="form-control" id="clone-net-mac-{{ forloop.counter0 }}" name="clone-net-mac-{{ forloop.counter0 }}" type="text" value="{{ network.mac }}" data-new-mac>
<button class="btn btn-outline-secondary" type="button" data-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-outline-secondary" type="button" id="guess-clone-mac">{% 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 }}" data-image="{{ 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">
{# what the VM is (its name, a template or not), then what the guest sees and what happens when it crashes #}
<div class="list-group">
<div class="list-group-item p-3 p-md-4">
<h2 class="h6 mb-3" id="options-details">{% trans "VM details" %}</h2>
<form action="{% url 'instances:change_options' instance.id %}" method="post" aria-labelledby="options-details">{% csrf_token %}
<div class="row g-2 mb-2">
<label class="col-sm-2 col-form-label" for="options-title">{% trans "Title" %}</label>
<div class="col-sm-10"><input class="form-control" type="text" id="options-title" name="title" value="{{ instance.config_title }}"></div>
</div>
<div class="row g-2 mb-2">
<label class="col-sm-2 col-form-label" for="options-description">{% trans "Description" %}</label>
<div class="col-sm-10"><textarea class="form-control" id="options-description" name="description" rows="2">{{ instance.config_description }}</textarea></div>
</div>
<div class="text-end">
<button class="btn btn-primary" type="submit" name="change_options">{% trans "Save" %}</button>
</div>
</form>
<form class="border-top mt-3 pt-3" action="{% url 'instances:set_template' instance.id %}" method="post">{% csrf_token %}
<div class="form-check form-switch mb-1">
<input class="form-check-input" type="checkbox" role="switch" name="is_template" value="True" id="is_template" aria-describedby="template-help"
{% if instance.is_template %}checked{% endif %}
{% if instance.status != 5 or not request.user.is_superuser and not request.user.is_staff %}disabled{% endif %} data-submit-on-change>
<label class="form-check-label" for="is_template">{% trans "Use as a template" %}</label>
</div>
<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." %}
{% 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>
</form>
</div>
{% if request.user.is_superuser %}
<div class="list-group-item p-3 p-md-4" role="group" aria-labelledby="options-devices">
<div class="d-flex flex-wrap justify-content-between column-gap-3 mb-2">
<h2 class="h6 mb-0" id="options-devices">{% trans "Devices the guest sees" %}</h2>
<span class="small text-body-secondary">{% trans "Changes apply from the next start; the guest agent's at once." %}</span>
</div>
<form class="option-row" action="{% url 'instances:set_video_model' instance.id %}" method="post">{% csrf_token %}
<label class="option-name" for="video_model_select">{% trans "Video" %}</label>
<select id="video_model_select" class="form-select form-select-sm w-auto" name="video_model" data-submit-on-change>
{% for vmodel in instance.video_models %}
<option value="{{ vmodel }}"{% if vmodel == instance.config_video_model %} selected{% endif %}>{{ vmodel }}</option>
{% endfor %}
</select>
<span class="small text-body-secondary">{% trans "The graphics device the guest sees." %}</span>
</form>
<form class="option-row border-top" action="{% url 'instances:set_rng' instance.id %}" method="post">{% csrf_token %}
<label class="option-name" for="rng">{% trans "Virtio RNG" %}</label>
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" role="switch" name="rng" value="True" id="rng" aria-describedby="rng-help"
{% if instance.config_rng %}checked{% endif %}{% if instance.config_rng == "custom" %} disabled{% endif %} data-submit-on-change>
</div>
<span class="small text-body-secondary" id="rng-help">{% if instance.config_rng == "custom" %}{% trans "The VM has its own RNG device: change it in the XML editor." %}{% else %}{% trans "Feeds the guest's entropy from the host, so a new VM does not wait for it at boot." %}{% endif %}</span>
</form>
<form class="option-row border-top" action="{% url 'instances:set_tpm' instance.id %}" method="post">{% csrf_token %}
<label class="option-name" for="tpm">{% trans "TPM 2.0" %}</label>
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" role="switch" name="tpm" value="True" id="tpm" aria-describedby="tpm-help"
{% if instance.config_tpm %}checked{% endif %}{% if instance.config_tpm == "custom" or not instance.config_tpm and not tpm_support %} disabled{% endif %} data-submit-on-change>
</div>
<span class="small text-body-secondary" id="tpm-help">
{% if instance.config_tpm == "custom" %}{% trans "The VM has its own TPM: change it in the XML editor." %}
{% elif not instance.config_tpm and not tpm_support %}{% trans "This host offers no TPM 2.0: install swtpm on it." %}
{% elif instance.config_tpm %}{% trans "Turned off, its state stays on the host until the VM is destroyed; turned on again, it is back." %}
{% else %}{% trans "Windows 11 needs it, with UEFI Secure Boot." %}{% endif %}</span>
</form>
<form class="option-row border-top" action="{% url 'instances:set_guest_agent' instance.id %}" method="post">{% csrf_token %}
<input type="hidden" name="guest_agent" value="{% if instance.config_guest_agent %}False{% else %}True{% endif %}">
<label class="option-name" for="guest_agent">{% trans "Guest agent" %}</label>
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" role="switch" id="guest_agent" aria-describedby="agent-help"{% if instance.config_guest_agent %} checked{% endif %} data-submit-on-change>
</div>
<span class="small d-inline-flex align-items-center gap-2" id="agent-help">
{% if not instance.config_guest_agent %}<span class="text-body-secondary">{% trans "The channel to the agent in the guest: a running VM gets it at once." %}</span>
{% elif instance.status != 1 and instance.status != 3 %}<span class="power-dot" aria-hidden="true"></span>{% trans "VM not running" %}
{% elif not instance.guest_agent %}<span class="power-dot" aria-hidden="true"></span>{% trans "No channel" %}
{% elif instance.guest_agent_ready %}<span class="power-dot bg-success" aria-hidden="true"></span>{% trans "Connected" %}
{% else %}<span class="power-dot bg-danger" aria-hidden="true"></span>{% trans "Not connected: is the agent installed and running in the guest?" %}{% endif %}
</span>
</form>
</div>
<form class="list-group-item p-3 p-md-4" action="{% url 'instances:set_on_crash' instance.id %}" method="post" aria-labelledby="options-crash">{% csrf_token %}
<h2 class="h6 mb-2" id="options-crash">{% trans "When the guest crashes" %}</h2>
<div class="d-flex flex-wrap align-items-center column-gap-3 row-gap-2">
{% if instance.config_on_crash == "restart" or instance.config_on_crash == "destroy" %}
<div class="btn-group btn-group-sm" role="radiogroup" aria-labelledby="options-crash">
<input type="radio" class="btn-check" name="on_crash" value="restart" id="on_crash_restart"{% if instance.config_on_crash == "restart" %} checked{% endif %} data-submit-on-change>
<label class="btn btn-outline-primary" for="on_crash_restart">{% trans "Restart" %}</label>
<input type="radio" class="btn-check" name="on_crash" value="destroy" id="on_crash_destroy"{% if instance.config_on_crash == "destroy" %} checked{% endif %} data-submit-on-change>
<label class="btn btn-outline-primary" for="on_crash_destroy">{% trans "Stop" %}</label>
</div>
<span class="small text-body-secondary">{% 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." %}</span>
{% 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>
</form>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
</div>