mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 19:56:48 +00:00
The host pages lose their last inline scripts: the overview's charts (host_graphs.js), the New pool, New network and New interface dialogs (pool_dialog.js, network_dialog.js, interface_dialog.js), a network's and a network filter's XML editors and dialogs (network_page.js, nwfilter_page.js, nwfilters_page.js), the secrets page's labels (secrets_page.js, its texts from the view as usage_texts) and a pool's page with the ISO upload (storage_page.js). Their URLs and messages are data attributes of the elements they belong to; the upload reads its token and address from its form. No template has an inline script or an inline event handler any more.
191 lines
16 KiB
HTML
191 lines
16 KiB
HTML
{% load i18n %}
|
|
{% load static %}
|
|
{% load bootstrap_icons %}
|
|
{% load form_fields %}
|
|
{% if request.user.is_superuser %}
|
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#AddStgPool">
|
|
<span aria-hidden="true">{% bs_icon 'plus-lg' %}</span> {% trans "New pool" %}
|
|
</button>
|
|
|
|
{# one form: a card per pool type, the fields of the chosen one (the others hidden and disabled, so not sent) #}
|
|
<div class="modal fade" id="AddStgPool" tabindex="-1" aria-labelledby="AddStgPoolLabel" aria-hidden="true"
|
|
{% if form.errors %}data-open{% endif %}>
|
|
<div class="modal-dialog modal-lg modal-dialog-scrollable modal-fullscreen-sm-down">
|
|
<form method="post" class="modal-content" id="pool-form"{% if ceph_secrets %} data-ceph-secrets{% endif %}>{% csrf_token %}
|
|
<input type="hidden" name="stg_type" value="{{ form.stg_type.value|default:"dir" }}">
|
|
<div class="modal-header">
|
|
<div>
|
|
<h5 class="modal-title" id="AddStgPoolLabel">{% trans "New storage pool" %}</h5>
|
|
<div class="small text-body-secondary">{% blocktrans with host=compute.name %}On {{ host }}{% endblocktrans %}</div>
|
|
</div>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
{% include "instances/form_errors.html" %}
|
|
|
|
<fieldset class="mb-3">
|
|
<legend class="form-label fs-6">{% trans "Storage type" %}</legend>
|
|
<div class="row row-cols-1 row-cols-sm-2 g-2">
|
|
{% trans "Directory" as title %}{% trans "Image files in a directory of the host." as help %}
|
|
{% include "radio_card.html" with name="pool_kind" value="dir" chosen=pool_kind %}
|
|
{% trans "LVM" as title %}{% trans "Logical volumes of a volume group made on a device." as help %}
|
|
{% include "radio_card.html" with name="pool_kind" value="logical" chosen=pool_kind %}
|
|
{% trans "Ceph RBD" as title %}{% trans "Images of a pool of an existing Ceph cluster." as help %}
|
|
{% include "radio_card.html" with name="pool_kind" value="rbd" chosen=pool_kind %}
|
|
{% trans "Network filesystem" as title %}{% trans "Image files on a server's share, mounted on the host." as help %}
|
|
{% include "radio_card.html" with name="pool_kind" value="netfs" chosen=pool_kind %}
|
|
{% if iso_pool %}
|
|
{# the upload button is on the page of the pool named iso only #}
|
|
<div class="col">
|
|
<div class="border rounded p-2 h-100">
|
|
<div class="d-flex flex-wrap align-items-center gap-2">
|
|
<span class="fw-semibold">{% trans "ISO images" %}</span>
|
|
<span class="badge text-bg-light border">{% trans "Already on this host" %}</span>
|
|
</div>
|
|
<div class="small text-body-secondary font-monospace text-break">{{ iso_pool.path }}</div>
|
|
<a class="small" href="{% url 'storage' compute.id 'iso' %}">{% trans "Open the ISO pool" %} →</a>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
{% trans "ISO images" as title %}{% trans "The directory pool named iso, for uploaded ISO images." as help %}
|
|
{% include "radio_card.html" with name="pool_kind" value="iso" chosen=pool_kind %}
|
|
{% endif %}
|
|
</div>
|
|
</fieldset>
|
|
|
|
<div class="mb-3">
|
|
<label for="pool_name" class="form-label">{% trans "Pool name" %}</label>
|
|
<input id="pool_name" type="text" class="form-control{{ form.name|invalid }}" name="name" value="{{ form.name.value|default:"" }}"
|
|
placeholder="vm-images" maxlength="20" required pattern="[a-zA-Z0-9._\-]+" {% error_attrs form.name "pool_name" "pool_name_help" %}>
|
|
<div class="form-text" id="pool_name_help">{% trans "Letters, digits, dots, dashes and underscores; up to 20." %}</div>
|
|
{% field_error form.name "pool_name" %}
|
|
</div>
|
|
|
|
<fieldset data-kinds="dir">
|
|
<legend class="visually-hidden">{% trans "Directory" %}</legend>
|
|
<div class="mb-3">
|
|
<label for="pool_dir_target" class="form-label">{% trans "Directory" %}</label>
|
|
<input id="pool_dir_target" type="text" class="form-control font-monospace{% if pool_kind == "dir" %}{{ form.target|invalid }}{% endif %}" name="target" value="{% if pool_kind == "dir" %}{{ form.target.value|default:"" }}{% endif %}"
|
|
data-follow-name="/var/lib/libvirt/" placeholder="/var/lib/libvirt/vm-images" maxlength="100" required {% if pool_kind == "dir" %}{% error_attrs form.target "pool_dir_target" "pool_dir_target_help" %}{% else %}aria-describedby="pool_dir_target_help"{% endif %}>
|
|
<div class="form-text" id="pool_dir_target_help">{% trans "Made on the host if it does not exist." %}</div>
|
|
{% if pool_kind == "dir" %}{% field_error form.target "pool_dir_target" %}{% endif %}
|
|
</div>
|
|
</fieldset>
|
|
|
|
<fieldset data-kinds="logical">
|
|
<legend class="visually-hidden">{% trans "LVM" %}</legend>
|
|
<div class="mb-3">
|
|
<label for="pool_lvm_source" class="form-label">{% trans "Device" %}</label>
|
|
<input id="pool_lvm_source" type="text" class="form-control font-monospace{% if pool_kind == "logical" %}{{ form.source|invalid }}{% endif %}" name="source" value="{% if pool_kind == "logical" %}{{ form.source.value|default:"" }}{% endif %}"
|
|
placeholder="/dev/sdb" maxlength="100" required {% if pool_kind == "logical" %}{% error_attrs form.source "pool_lvm_source" "pool_lvm_source_help" %}{% else %}aria-describedby="pool_lvm_source_help"{% endif %}>
|
|
<div class="form-text" id="pool_lvm_source_help">{% trans "The volume group takes the pool's name." %}</div>
|
|
{% if pool_kind == "logical" %}{% field_error form.source "pool_lvm_source" %}{% endif %}
|
|
</div>
|
|
<div class="alert alert-danger">
|
|
<div class="form-check mb-0">
|
|
<input class="form-check-input{{ form.erase_device|invalid }}" type="checkbox" name="erase_device" value="true" id="pool_lvm_erase" required {% error_attrs form.erase_device "pool_lvm_erase" %}>
|
|
<label class="form-check-label" for="pool_lvm_erase">{% trans "The device becomes a new volume group: what is on it now is erased." %}</label>
|
|
{% field_error form.erase_device "pool_lvm_erase" %}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<fieldset data-kinds="rbd">
|
|
<legend class="visually-hidden">{% trans "Ceph RBD" %}</legend>
|
|
{% if ceph_secrets %}
|
|
<div class="row g-3 mb-3">
|
|
<div class="col-sm-6">
|
|
<label for="pool_ceph_host" class="form-label">{% trans "Ceph monitor" %}</label>
|
|
<input id="pool_ceph_host" type="text" class="form-control{{ form.ceph_host|invalid }}" name="ceph_host" value="{{ form.ceph_host.value|default:"" }}"
|
|
placeholder="mon0.example.com" maxlength="253" required pattern="[a-zA-Z0-9._\-]+" {% error_attrs form.ceph_host "pool_ceph_host" %}>
|
|
{% field_error form.ceph_host "pool_ceph_host" %}
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="pool_ceph_pool" class="form-label">{% trans "Ceph pool" %}</label>
|
|
<input id="pool_ceph_pool" type="text" class="form-control{{ form.ceph_pool|invalid }}" name="ceph_pool" value="{{ form.ceph_pool.value|default:"" }}"
|
|
placeholder="libvirt-pool" required pattern="[a-zA-Z0-9._\-]+" {% error_attrs form.ceph_pool "pool_ceph_pool" %}>
|
|
{% field_error form.ceph_pool "pool_ceph_pool" %}
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="pool_ceph_user" class="form-label">{% trans "Ceph user" %}</label>
|
|
<input id="pool_ceph_user" type="text" class="form-control{{ form.ceph_user|invalid }}" name="ceph_user" value="{{ form.ceph_user.value|default:"" }}"
|
|
placeholder="libvirt" required pattern="[a-zA-Z0-9._\-]+" {% error_attrs form.ceph_user "pool_ceph_user" %}>
|
|
{% field_error form.ceph_user "pool_ceph_user" %}
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="pool_ceph_secret" class="form-label">{% trans "Ceph secret" %}</label>
|
|
<select id="pool_ceph_secret" name="secret" class="form-select{{ form.secret|invalid }}" required {% error_attrs form.secret "pool_ceph_secret" "pool_ceph_secret_help" %}>
|
|
<option value="">{% trans "Choose…" %}</option>
|
|
{% for secret in ceph_secrets %}
|
|
<option value="{{ secret.uuid }}"{% if secret.uuid == form.secret.value %} selected{% endif %}>{{ secret.usage }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<div class="form-text" id="pool_ceph_secret_help">{% trans "The libvirt secret holding that user's key." %}</div>
|
|
{% field_error form.secret "pool_ceph_secret" %}
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="alert alert-warning">
|
|
{% url 'virtsecrets' compute.id as secrets_url %}
|
|
{% blocktrans %}A Ceph pool needs a libvirt secret of the Ceph type holding the Ceph user's key, and this host has none. <a href="{{ secrets_url }}">Add one on the Secrets page</a>, then come back.{% endblocktrans %}
|
|
</div>
|
|
{% endif %}
|
|
</fieldset>
|
|
|
|
<fieldset data-kinds="netfs">
|
|
<legend class="visually-hidden">{% trans "Network filesystem" %}</legend>
|
|
<div class="row g-3 mb-3">
|
|
<div class="col-sm-6">
|
|
<label for="pool_netfs_host" class="form-label">{% trans "Server" %}</label>
|
|
<input id="pool_netfs_host" type="text" class="form-control{{ form.netfs_host|invalid }}" name="netfs_host" value="{{ form.netfs_host.value|default:"" }}"
|
|
placeholder="nfs.example.com" maxlength="253" required pattern="[a-zA-Z0-9._\-]+" {% error_attrs form.netfs_host "pool_netfs_host" %}>
|
|
{% field_error form.netfs_host "pool_netfs_host" %}
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="pool_netfs_format" class="form-label">{% trans "Protocol" %}</label>
|
|
<select id="pool_netfs_format" name="source_format" class="form-select">
|
|
{% for value, label in form.fields.source_format.choices %}
|
|
<option value="{{ value }}"{% if value == form.source_format.value %} selected{% endif %}>{{ label }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="pool_netfs_source" class="form-label">{% trans "Share on the server" %}</label>
|
|
<input id="pool_netfs_source" type="text" class="form-control font-monospace{% if pool_kind == "netfs" %}{{ form.source|invalid }}{% endif %}" name="source" value="{% if pool_kind == "netfs" %}{{ form.source.value|default:"" }}{% endif %}"
|
|
placeholder="/srv/storage" maxlength="100" required {% if pool_kind == "netfs" %}{% error_attrs form.source "pool_netfs_source" %}{% endif %}>
|
|
{% if pool_kind == "netfs" %}{% field_error form.source "pool_netfs_source" %}{% endif %}
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="pool_netfs_target" class="form-label">{% trans "Mounted on" %}</label>
|
|
<input id="pool_netfs_target" type="text" class="form-control font-monospace{% if pool_kind == "netfs" %}{{ form.target|invalid }}{% endif %}" name="target" value="{% if pool_kind == "netfs" %}{{ form.target.value|default:"" }}{% endif %}"
|
|
data-follow-name="/var/lib/libvirt/" placeholder="/var/lib/libvirt/nfs-share" maxlength="100" required {% if pool_kind == "netfs" %}{% error_attrs form.target "pool_netfs_target" "pool_netfs_target_help" %}{% else %}aria-describedby="pool_netfs_target_help"{% endif %}>
|
|
<div class="form-text" id="pool_netfs_target_help">{% trans "A directory of the host; made if it does not exist." %}</div>
|
|
{% if pool_kind == "netfs" %}{% field_error form.target "pool_netfs_target" %}{% endif %}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
|
|
{% if not iso_pool %}
|
|
<fieldset data-kinds="iso">
|
|
<legend class="visually-hidden">{% trans "ISO images" %}</legend>
|
|
<div class="mb-3">
|
|
<label for="pool_iso_target" class="form-label">{% trans "Directory" %}</label>
|
|
<input id="pool_iso_target" type="text" class="form-control font-monospace{% if pool_kind == "iso" %}{{ form.target|invalid }}{% endif %}" name="target"
|
|
value="{% if pool_kind == "iso" and form.target.value %}{{ form.target.value }}{% else %}/var/lib/libvirt/iso{% endif %}" maxlength="100" required {% if pool_kind == "iso" %}{% error_attrs form.target "pool_iso_target" %}{% endif %}>
|
|
{% if pool_kind == "iso" %}{% field_error form.target "pool_iso_target" %}{% endif %}
|
|
</div>
|
|
</fieldset>
|
|
{% endif %}
|
|
|
|
<p class="small text-body-secondary mb-0">{% bs_icon 'info-circle' %} {% trans "The pool starts at once, and with the host from then on." %}</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<button type="submit" class="btn btn-primary" name="create">{% trans "Create pool" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<script src="{% static 'js/choice_dialog.js' %}"></script>
|
|
<script src="{% static 'js/pool_dialog.js' %}"></script>
|
|
{% endif %}
|