mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 04:06:47 +00:00
Settings > Console was one horizontal form, and on a running VM its
Update button was disabled. The owner chose this layout from three
rendered options: the console type on top, then a "VNC connection" card
(listen address, keymap) and a "VNC password" card.
- The password is changed by an action: keep it, generate a new one,
set a new one or remove it. This replaces the Generate and Clear
boxes and their precedence, and an emptied field no longer removes
the password silently. The pane says whether a password is set; the
form no longer carries the password itself.
- A VNC password takes at most 8 bytes: libvirt refuses a longer one
("VNC password is 9 characters long, only 8 permitted"). Generate and
a new VM's random password now make 8 characters; they made 12, which
libvirt 11 refuses. A set password keeps its spaces.
- Every check is in the form, so a refused save changes nothing; before,
a refused password removal still saved the other settings.
- The settings can be saved while the VM runs: they are in the
persistent definition. A line says the running console keeps its
settings until the VM is shut down and started.
- The console type shown and compared is the persistent one; it was the
running VM's, so a pending switch to Serial showed VNC and a later
save could switch again.
- While the saved type is Serial, the VNC settings are not shown or
taken; choosing Serial ignores the posted VNC settings.
900 lines
64 KiB
HTML
900 lines
64 KiB
HTML
{% 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 cards; 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 SCSI bus. Shut it down to detach other CD-ROM drives, 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>
|
||
<form action="{% url 'instances:add_cdrom' instance.id %}" method="post" aria-label="{% trans "Add CD-ROM form" %}">{% csrf_token %}
|
||
<button class="btn btn-sm btn-secondary" type="submit">{% bs_icon 'plus' %} {% trans "Add CD-ROM" %}</button>
|
||
</form>
|
||
</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 %}
|
||
<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" %} disabled{% endif %}>{% trans "Detach" %}</button>
|
||
{% endif %}
|
||
</div>
|
||
{% if 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="row g-3">
|
||
{% for disk in instance.config_disks %}
|
||
<div class="col-12{% if instance.config_disks|length > 1 %} col-md-6{% endif %}">
|
||
<article class="card h-100" aria-labelledby="disk-{{ disk.dev }}">
|
||
<div class="card-body small">
|
||
<div class="d-flex justify-content-between align-items-center gap-2 mb-2">
|
||
<h3 class="h6 mb-0" id="disk-{{ disk.dev }}">{% bs_icon 'device-hdd' %} {{ disk.dev }}</h3>
|
||
<span class="text-body-secondary">{{ disk.bus }} · {{ disk.format }}</span>
|
||
</div>
|
||
{% if disk.storage is None %}
|
||
<div class="alert alert-danger mb-0">{% trans "Error getting disk info" %}</div>
|
||
{% else %}
|
||
<div class="text-body-secondary">{% trans "Capacity" %}</div>
|
||
<p class="fs-4 fw-semibold lh-sm mb-0">{{ disk.size|filesizeformat }}</p>
|
||
<p class="text-body-secondary mb-2">{% blocktrans with used=disk.used|filesizeformat %}{{ used }} used{% endblocktrans %}</p>
|
||
<div class="border-top pt-2">
|
||
<div class="mb-1"><span class="text-body-secondary">{% trans "Storage pool" %}</span> <strong class="ms-1">{{ disk.storage }}</strong></div>
|
||
<div class="text-body-secondary">{% trans "Source" %}</div>
|
||
<p class="text-break mb-2">{{ disk.path }}</p>
|
||
</div>
|
||
{% endif %}
|
||
<details>
|
||
<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>
|
||
</div>
|
||
<div class="card-footer bg-transparent d-flex flex-wrap 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 %}" onclick="return confirm(this.dataset.confirm)">{% 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 %}" onclick="return confirm(this.dataset.confirm)">{% trans "Delete" %}</button>
|
||
</form>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</section>
|
||
</div>
|
||
<div role="tabpanel" class="tab-pane" id="network">
|
||
{# a card per NIC, the only one across the row; 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="row g-3">
|
||
{% for network in instance.config_networks %}
|
||
<div class="col-12{% if instance.config_networks|length > 1 %} col-md-6{% endif %}">
|
||
<article class="card h-100" aria-labelledby="nic-{{ forloop.counter0 }}">
|
||
<div class="card-body small">
|
||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-2">
|
||
<h3 class="h6 mb-0" id="nic-{{ forloop.counter0 }}">{% bs_icon 'ethernet' %} eth{{ forloop.counter0 }} <span class="text-body-secondary fw-normal">· {{ network.target|default:_("no target") }}</span></h3>
|
||
<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>
|
||
<p class="text-break mb-1"><span class="text-body-secondary">{% trans "Source" %}</span> <strong class="ms-1">{{ network.nic|default:"—" }}</strong></p>
|
||
<p class="mb-2"><span class="text-body-secondary">{% trans "IPv4" %}</span> <span class="ms-1">{{ network.ipv4|join:", "|default:_("unknown") }}</span></p>
|
||
<details>
|
||
<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>
|
||
<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="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 %}
|
||
</div>
|
||
<div class="card-footer bg-transparent 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-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 %}" onclick="return confirm(this.dataset.confirm)">{% trans "Delete" %}</button>
|
||
</form>
|
||
{% endif %}
|
||
</div>
|
||
</article>
|
||
{% 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">
|
||
<h5 class="modal-title" id="editInstanceNetworkLabel{{ forloop.counter0 }}">{% blocktrans with nic=forloop.counter0 %}Edit eth{{ nic }}{% endblocktrans %}</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<input type="hidden" name="net-old-mac-{{ forloop.counter0 }}" value="{{ network.mac }}">
|
||
<div class="mb-3">
|
||
<label class="form-label" for="net-mac-{{ forloop.counter0 }}">{% trans "MAC" %}</label>
|
||
<input class="form-control" type="text" id="net-mac-{{ forloop.counter0 }}" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label" for="net-source-{{ forloop.counter0 }}">{% trans "Net Source" %}</label>
|
||
<select class="form-select" id="net-source-{{ forloop.counter0 }}" name="net-source-{{ forloop.counter0 }}">
|
||
{% for c_net in networks_host %}
|
||
<option value="net:{{ c_net }}"{% if c_net == network.nic %} selected{% endif %}>{% trans 'Network' %} {{ c_net }}</option>
|
||
{% endfor %}
|
||
{% for c_iface in interfaces_host %}
|
||
<option value="iface:{{ c_iface }}"{% if c_iface == network.nic %} selected{% endif %}>{% trans 'Interface' %} {{ c_iface }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="mb-3">
|
||
<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>
|
||
<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>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">{% trans 'Close' %}</button>
|
||
<button class="btn btn-primary" name="change_network">{% trans "Apply" %}</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>
|
||
</div>
|
||
{% empty %}
|
||
<p class="small text-body-secondary mb-0">{% trans "The VM has no network device." %}</p>
|
||
{% endfor %}
|
||
</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." %}"
|
||
onclick="return confirm(this.dataset.confirm)">{% 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." %}" onclick="return confirm(this.dataset.confirm)">{% 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">
|
||
<p>{% trans "For migration both host servers must have equal settings and OS type" %}</p>
|
||
<form action="{% url 'instances:migrate' instance.id %}" class="ms-3 form" method="post" role="form" aria-label="Migrate instance form">
|
||
{% csrf_token %}{% submission_key %}
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label">{% trans "Original host" %}</label>
|
||
<div class="col-sm-6">
|
||
<label class="form-control" readonly="readonly">{{ compute.name }}</label>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label">{% trans "Host migration" %}</label>
|
||
<div class="col-sm-6">
|
||
<select name="compute_id" class="form-select" id="migrate_compute">
|
||
{% if computes_count != 1 %}
|
||
{% for comp in computes %}
|
||
{% if comp.id != compute.id %}
|
||
<option value="{{ comp.id }}">{{ comp.name }}</option>
|
||
{% endif %}
|
||
{% endfor %}
|
||
{% endif %}
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label">{% trans "Disks" %}</label>
|
||
<div class="col-sm-9 py-2" id="migrate-plan" data-url="{% url 'instances:migrate_plan' instance.id %}" aria-live="polite"></div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-sm-6 offset-sm-3">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" name="live_migrate" value="true" id="vm_live_migrate" {% if instance.status != 5 %}checked{% else %}disabled{% endif %}>
|
||
<label class="form-check-label" for="vm_live_migrate">{% trans "Live migration" %}</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-sm-6 offset-sm-3">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" name="unsafe_migrate" value="true" id="vm_unsafe_migrate">
|
||
<label class="form-check-label" for="vm_unsafe_migrate">{% trans "Unsafe migration" %}</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-sm-6 offset-sm-3">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" name="offline_migrate" value="true" id="offline_migrate" {% if instance.status == 5 %}checked{% else %}disabled{% endif %}>
|
||
<label class="form-check-label" for="offline_migrate">{% trans "Offline migration" %}</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-sm-6 offset-sm-3">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" name="autoconverge" value="true" id="autoconverge" {% if instance.status != 1 %}disabled{% else %}checked{% endif %}>
|
||
<label class="form-check-label" for="autoconverge" title="{% trans 'Forces CPU convergence during live migration' %}">{% trans "Auto converge" %}</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-sm-6 offset-sm-3">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" name="compress" value="true" id="compress" {% if instance.status != 1 %}disabled{% endif %}>
|
||
<label class="form-check-label" for="compress" title="{% trans 'Compress instance memory for fast migration' %}">{% trans "Compressed" %}</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-sm-6 offset-sm-3">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" name="delete_source" value="true" id="delete_source">
|
||
<label class="form-check-label" for="delete_source">{% trans "Delete the source files of copied disks" %}</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% if computes_count != 1 %}
|
||
<button type="submit" class="btn btn-primary float-end" name="migrate" >{% trans "Migrate" %}</button>
|
||
{% else %}
|
||
<button class="btn btn-primary float-end disabled" disabled>{% trans "Migrate" %}</button>
|
||
{% endif %}
|
||
</form>
|
||
<div class="clearfix"></div>
|
||
</div>
|
||
<div role="tabpanel" class="tab-pane" id="xmledit">
|
||
{% if instance.status != 5 %}
|
||
<p 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 "Change" %}
|
||
</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-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">
|
||
<div>
|
||
<div class="mb-3">
|
||
<span class="fw-bold">{% trans "Instance owners" %}</span>
|
||
{% include 'add_instance_owner_block.html' %}
|
||
</div>
|
||
</div>
|
||
<div class="table-responsive">
|
||
<table class="table table-striped mt-3 align-middle">
|
||
<tbody class="searchable">
|
||
{% for userinstance in userinstances %}
|
||
<tr>
|
||
<td><a href="{% url 'accounts:account' userinstance.user.id %}">{{ userinstance.user }}</a></td>
|
||
<td style="width:30px;">
|
||
<a href="{% url 'accounts:user_instance_delete' userinstance.id %}?next={% url 'instances:instance' instance.id %}#users">
|
||
{% bs_icon 'trash' %}
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="clearfix"></div>
|
||
</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">
|
||
<p class="fw-bold">{% trans "Create a clone" %}</p>
|
||
{% if usb_hostdevs or pci_hostdevs or other_hostdevs %}<p class="small text-body-secondary">{% trans "The clone gets none of the VM's host devices: one VM holds a device of the host." %}</p>{% endif %}
|
||
<form class="form" action="{% url 'instances:clone' instance.id %}" method="post" role="form" aria-label="Create clone form">{% csrf_token %}{% submission_key %}
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label fw-normal">{% trans "Clone Name" %}</label>
|
||
{% if request.user.is_superuser %}
|
||
<div class="col-sm-6">
|
||
<div class="input-group">
|
||
<input id="clone_name" type="text" class="form-control" name="name" value="{{ instance.name }}-clone">
|
||
<button type="button" class="btn btn-primary" name="guess-clone-name"
|
||
onclick="guess_clone_name()">{% trans "Guess" %}</button>
|
||
</div>
|
||
</div>
|
||
{% elif app_settings.CLONE_INSTANCE_AUTO_NAME == 'True'%}
|
||
<div class="col-sm-4">
|
||
<input id="clone_instance_auto_name" type="text" class="form-control" name="auto_name" value="Automatic" disabled/>
|
||
</div>
|
||
{% else %}
|
||
<div class="col-sm-4">
|
||
<select id="select_clone_name" class="form-control" name="name" size="1">
|
||
{% for name in clone_free_names %}
|
||
<option value="{{ name }}">{{ name }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
{% if request.user.is_superuser %}
|
||
<label>{% trans "Network devices" %}:</label>
|
||
{% for network in instance.config_networks %}
|
||
<div class="mb-3">
|
||
<div class="row">
|
||
<label class="col-sm-2 col-form-label offset-sm-1">eth{{ forloop.counter0 }} ({{ network.nic }})</label>
|
||
<div class="col-sm-6">
|
||
<div class="input-group">
|
||
<input type="text" class="form-control" name="clone-net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
||
<button type="button" class="btn btn-primary" name="random-mac-{{ forloop.counter0 }}"
|
||
onclick="random_mac('clone-net-mac-{{ forloop.counter0 }}')">{% trans "Random" %}</button>
|
||
<button type="button" class="btn btn-primary" name="guess-mac-{{ forloop.counter0 }}"
|
||
onclick="guess_mac_address('#clone_name', {{ forloop.counter0 }})">{% trans "Guess" %}</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
{% else %}
|
||
{% for network in instance.config_networks %}
|
||
<input type="hidden" class="form-control" name="clone-net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
||
{% endfor %}
|
||
{% endif %}
|
||
{% if request.user.is_superuser %}
|
||
<label>{% trans "Storage devices" %}:</label>
|
||
{% for disk in instance.config_disks %}
|
||
<div class="row">
|
||
<label class="col-sm-2 col-form-label offset-sm-1">{{ disk.dev }} ({{ disk.storage }})</label>
|
||
<div class="col-sm-6">
|
||
<div class="input-group mb-3">
|
||
<input id="disk_name-{{ disk.dev }}" type="text" class="form-control" name="disk-{{ disk.dev }}" value="{{ disk.image }}"/>
|
||
{% if disk.format == 'qcow2' %}
|
||
<span class="input-group-text" >{% trans 'Metadata' %}</span>
|
||
<div class="input-group-text">
|
||
<input type="checkbox" name="meta-{{ disk.dev }}" value="true">
|
||
</div>
|
||
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
{% else %}
|
||
{% for disk in instance.disks %}
|
||
<input id="disk_name-{{ disk.dev }}" type="hidden" class="form-control" name="disk-{{ disk.dev }}" value="{{ disk.image }}"/>
|
||
{% endfor %}
|
||
{% endif %}
|
||
<div class="row mb-3">
|
||
<label class="col-sm-3 col-form-label">{% trans "Title" %}</label>
|
||
<div class="col-sm-6">
|
||
<input type="text" name="clone-title" class="form-control">
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label">{% trans "Description" %}</label>
|
||
<div class="col-sm-6">
|
||
<textarea name="clone-description" class="form-control"></textarea>
|
||
</div>
|
||
</div>
|
||
{% if instance.status == 1 or instance.status == 3 or instance.status == 5 %}
|
||
<button type="submit" class="btn btn-primary float-end" name="clone">{% trans "Clone" %}</button>
|
||
{% else %}
|
||
<button class="btn btn-primary float-end disabled" disabled name="clone">{% trans "Clone" %}</button>
|
||
{% endif %}
|
||
</form>
|
||
<div class="clearfix"></div>
|
||
</div>
|
||
{% endif %}
|
||
{% if can_change %}
|
||
<div role="tabpanel" class="tab-pane" id="options">
|
||
<p>{% trans "To set instance template name description, shutdown the instance." %}</p>
|
||
<form action="{% url 'instances:change_options' instance.id %}" method="post" role="form" aria-label="Set instance template name description form">{% csrf_token %}
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label">{% trans "Title" %}</label>
|
||
<div class="col-sm-6">
|
||
<input type="text" name="title" class="form-control" value="{{ instance.config_title }}">
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label">{% trans "Description" %}</label>
|
||
<div class="col-sm-6">
|
||
<textarea name="description" class="form-control">{{ instance.config_description }}</textarea>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label">{% trans "Is template" %}</label>
|
||
<div class="col-sm-6">
|
||
<input type="checkbox"
|
||
name="is_template"
|
||
value="True"
|
||
id="is_template"
|
||
{% if instance.is_template %}checked{% endif %}
|
||
{% if not request.user.is_superuser and not request.user.is_staff %}disabled{% endif %}>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="d-grid offset-sm-3 col-sm-6">
|
||
{% if instance.status == 5 %}
|
||
<button type="submit" class="btn btn-primary" name="change_options">{% trans "Change" %}</button>
|
||
{% else %}
|
||
<button class="btn btn-primary disabled" disabled name="change_options">{% trans "Change" %}</button>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</form>
|
||
{% if request.user.is_superuser %}
|
||
<p class="fw-bold">{% trans "To set instance video model, shutdown the instance." %}</p>
|
||
<form action="{% url 'instances:set_video_model' instance.id %}" method="post" role="form" aria-label="Set instance video model form">{% csrf_token %}
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label" for="video_model_select">{% trans "Primary Video Model" %}</label>
|
||
<div class="col-sm-6">
|
||
<div class="input-group">
|
||
<select id="video_model_select" class="form-select" name="video_model">
|
||
<option class="fw-bold" value="">{% trans "please choose" %}</option>
|
||
{% for vmodel in instance.video_models %}
|
||
<option value="{{ vmodel }}"{% if vmodel == instance.config_video_model %} selected{% endif %}>{{ vmodel }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
{% if instance.status == 5 %}
|
||
<button type="submit" class="btn btn-primary" name="set_video_model">{% trans "Set" %}</button>
|
||
{% else %}
|
||
<button class="btn btn-primary disabled" disabled name="set_video_model">{% trans "Set" %}</button>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
<p class="fw-bold">{% trans "To set instance vCPUs hotpluggable" %}</p>
|
||
<form action="{% url 'instances:set_vcpu_hotplug' instance.id %}" method="post" role="form" aria-label="Set instance vCPUs hotpluggable form">{% csrf_token %}
|
||
<div class="row">
|
||
<label for="vcpu_hotplug" class="col-sm-3 col-form-label">{% trans "vCPU Hot Plug" %}</label>
|
||
<div class="col-sm-6">
|
||
<div class="input-group">
|
||
<select id="vcpu_hotplug" class="form-control" name="vcpu_hotplug">
|
||
<option value="True" {% if instance.vcpus %} selected {% endif %}>{% trans 'Enabled' %}</option>
|
||
<option value="False" {% if not instance.vcpus %} selected {% endif %}>{% trans 'Disabled' %}</option>
|
||
</select>
|
||
{% if instance.status == 5 %}
|
||
<button type="submit" class="btn btn-primary" name="set_vcpu_hotplug">{% trans "Set" %}</button>
|
||
{% else %}
|
||
<button class="btn btn-primary" name="set_vcpu_hotplug" disabled>{% trans "Set" %}</button>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
<p class="fw-bold">{% trans "To Enable/Disable Qemu Guest Agent. Status" %}:
|
||
{% if instance.status == 1 %}
|
||
{% if instance.guest_agent_ready %}
|
||
<label class="badge bg-success">{% trans 'Connected' %}</label>
|
||
{% else %}
|
||
<label class="badge bg-danger">{% trans 'Disconnected' %}</label>
|
||
{% endif %}</p>
|
||
{% else %}
|
||
<label class="badge bg-default">{% trans 'Unknown' %}</label>
|
||
{% endif %}
|
||
<form action="{% url 'instances:set_guest_agent' instance.id %}" method="post" role="form" aria-label="Enable/Disable Qemu Guest Agent form">{% csrf_token %}
|
||
<div class="row">
|
||
<label class="col-sm-3 col-form-label" for="guest_agent">{% trans "Qemu Guest Agent" %}</label>
|
||
<div class="col-sm-6">
|
||
<div class="input-group">
|
||
<select id="guest_agent" class="form-select" name="guest_agent">
|
||
<option value="True" {% if instance.guest_agent %} selected {% endif %}>{% trans 'Enabled' %}</option>
|
||
<option value="False" {% if not instance.guest_agent %} selected {% endif %}>{% trans 'Disabled' %}</option>
|
||
</select>
|
||
<button type="submit" class="btn btn-primary" name="set_guest_agent">{% trans "Set" %}</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
{% endif %}
|
||
<div class="clearfix"></div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|