mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
The VM page's and the Settings page's views marked their messages with
gettext_noop, so every message they gave (a refused resize, a saved
setting, a QoS change, a busy VM) showed in English whatever the
language, though the catalogs translate them. They translate in the
request's language now; their module-level texts lazily. The Settings
page's group titles stay English in the view, as the page links them
by their slugs and translates them itself.
Two values went into translated messages as English codes: a job's
state ("... is running on this resource") and a QoS direction ("Remove
the inbound limit ..."). They are named as the pages name them.
454 lines
29 KiB
HTML
454 lines
29 KiB
HTML
{% extends "base.html" %}
|
||
{% load i18n %}
|
||
{% load static %}
|
||
{% load bootstrap_icons %}
|
||
|
||
{% block title %}{% trans "Network" %} - {{ pool }}{% endblock %}
|
||
|
||
{% block page_heading %}{{ compute.name }} - {% trans "Network" %}: {{ pool }}{% endblock page_heading %}
|
||
|
||
{% block page_heading_extra %}
|
||
{# the network's own actions: starting or stopping it, the others in a menu #}
|
||
<div class="btn-group" role="group" aria-label="{% blocktrans %}Actions for network {{ pool }}{% endblocktrans %}">
|
||
<form method="post" class="btn-group">{% csrf_token %}
|
||
{% if state %}
|
||
<button type="submit" class="btn btn-outline-secondary" name="stop"
|
||
data-confirm="{% blocktrans with name=pool %}Stop network {{ name }}? Running VMs on it lose their connection through it at once.{% endblocktrans %}">{% bs_icon 'stop-fill' %} {% trans "Stop" %}</button>
|
||
{% else %}
|
||
<button type="submit" class="btn btn-outline-secondary" name="start">{% bs_icon 'play-fill' %} {% trans "Start" %}</button>
|
||
{% endif %}
|
||
</form>
|
||
<div class="btn-group">
|
||
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false" aria-label="{% trans "More actions" %}">{% bs_icon 'three-dots' %}</button>
|
||
<ul class="dropdown-menu dropdown-menu-end shadow">
|
||
<li><form method="post">{% csrf_token %}
|
||
{% if autostart %}
|
||
<button type="submit" class="dropdown-item" name="unset_autostart"
|
||
data-confirm="{% blocktrans with name=pool %}Disable autostart of network {{ name }}? After the host restarts it stays stopped, and VMs that use it do not start.{% endblocktrans %}">{% bs_icon 'toggle-off' %} {% trans "Disable autostart" %}</button>
|
||
{% else %}
|
||
<button type="submit" class="dropdown-item" name="set_autostart">{% bs_icon 'toggle-on' %} {% trans "Enable autostart" %}</button>
|
||
{% endif %}
|
||
</form></li>
|
||
{% if not state %}
|
||
<li><hr class="dropdown-divider"></li>
|
||
<li><form method="post">{% csrf_token %}
|
||
<button type="submit" class="dropdown-item text-danger" name="delete"
|
||
data-confirm="{% blocktrans with name=pool %}Delete network {{ name }}? VMs that use it no longer start.{% endblocktrans %}">{% bs_icon 'trash' %} {% trans "Delete network" %}</button>
|
||
</form></li>
|
||
{% endif %}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
{% endblock page_heading_extra %}
|
||
|
||
{% block content %}
|
||
{% include "computes/host_nav.html" with section="networks" detail=True %}
|
||
|
||
<div class="card mb-3">
|
||
<div class="card-header">{% trans "Network" %}</div>
|
||
<ul class="list-group list-group-flush">
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
|
||
<span class="text-body-secondary">{% trans "State" %}</span>
|
||
<span class="d-flex flex-wrap justify-content-end gap-1">
|
||
{% if state %}<span class="badge text-bg-success">{% trans "Active" %}</span>{% else %}<span class="badge text-bg-secondary">{% trans "Stopped" %}</span>{% endif %}
|
||
{% if autostart %}<span class="badge text-bg-light border">{% trans "Autostart" %}</span>{% endif %}
|
||
</span>
|
||
</li>
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
|
||
<span class="text-body-secondary">{% trans "Type" %}</span>
|
||
<span class="badge text-bg-light border">{{ mode_label }}</span>
|
||
</li>
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
|
||
<span class="text-body-secondary">{% if mode == "macvtap" %}{% trans "Host interface" %}{% elif mode == "bridge" %}{% trans "Host bridge" %}{% else %}{% trans "Bridge" %}{% endif %}</span>
|
||
<span class="font-monospace text-break text-end">{{ device|default:"–" }}</span>
|
||
</li>
|
||
{% if net_mac %}
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
|
||
<span class="text-body-secondary">{% trans "MAC" %}</span>
|
||
<span class="font-monospace">{{ net_mac }}</span>
|
||
</li>
|
||
{% endif %}
|
||
</ul>
|
||
<div class="card-footer small text-body-secondary">{{ mode_help }}</div>
|
||
</div>
|
||
|
||
{% if external %}
|
||
<div class="alert alert-secondary">{% bs_icon 'info-circle' %} {% trans "The VMs on this network take their addresses from the outside network: libvirt gives none." %}</div>
|
||
{% else %}
|
||
<div class="row row-cols-1 row-cols-md-2 g-3 mb-3">
|
||
{% for ip in ip_networks %}
|
||
<div class="col">
|
||
<div class="card h-100">
|
||
<div class="card-header d-flex flex-wrap align-items-center gap-2">
|
||
<span class="me-auto">{% if ip.family == "ipv6" %}IPv6{% else %}IPv4{% endif %}</span>
|
||
{% if ip.range %}
|
||
{# a running network keeps its range: libvirt changes it while it is stopped #}
|
||
<span {% if state %}title="{% trans "Stop the network to change its range" %}"{% endif %}>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#DhcpRange"
|
||
data-ip-index="{{ ip.index }}" data-start="{{ ip.range.0 }}" data-end="{{ ip.range.1 }}" data-subnet="{{ ip.subnet }}"
|
||
{% if state %}disabled{% endif %}>{% bs_icon 'pencil' %} {% trans "DHCP range" %}</button>
|
||
</span>
|
||
{% endif %}
|
||
</div>
|
||
<ul class="list-group list-group-flush flex-grow-1">
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
|
||
<span class="text-body-secondary">{% trans "Subnet" %}</span><span class="font-monospace text-break text-end">{{ ip.subnet|default:"–" }}</span>
|
||
</li>
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
|
||
<span class="text-body-secondary">{% trans "Host's address" %}</span><span class="font-monospace text-break text-end">{{ ip.address }}</span>
|
||
</li>
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
|
||
<span class="text-body-secondary">{% trans "DHCP" %}</span>
|
||
<span class="text-end">
|
||
{% if ip.range %}<span class="font-monospace text-break">{{ ip.range.0 }} – {{ ip.range.1 }}</span>
|
||
{% elif ip.dhcp %}{% trans "Fixed addresses only" %}
|
||
{% else %}<span class="badge text-bg-secondary">{% trans "Off" %}</span>{% endif %}
|
||
</span>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
{% empty %}
|
||
<div class="col">
|
||
<div class="card h-100"><div class="card-body small text-body-secondary">{% trans "The network has no address of the host: its VMs reach each other only." %}</div></div>
|
||
</div>
|
||
{% endfor %}
|
||
{% if ip_networks and "ipv6" not in families %}
|
||
<div class="col">
|
||
<div class="card h-100">
|
||
<div class="card-header">IPv6</div>
|
||
<div class="card-body small text-body-secondary">{% trans "The network has no IPv6 address; the XML definition below can give it one." %}</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="card mb-3">
|
||
<div class="card-header d-flex flex-wrap align-items-center gap-2">
|
||
<span class="me-auto">{% trans "Fixed addresses" %}</span>
|
||
{% if fixed_addresses %}
|
||
<input id="filter" class="form-control form-control-sm w-auto" type="search" placeholder="{% trans "Search" %}" aria-label="{% trans "Search fixed addresses" %}">
|
||
{% endif %}
|
||
{% if dhcp_networks %}
|
||
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#FixedAddress">
|
||
{% bs_icon 'plus-lg' %} {% trans "Add" %}
|
||
</button>
|
||
{% endif %}
|
||
</div>
|
||
{% if fixed_addresses %}
|
||
<div class="table-responsive">
|
||
<table class="table table-hover align-middle mb-0" data-sortable>
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">{% trans "Address" %}</th>
|
||
<th scope="col">{% trans "MAC / DUID" %}</th>
|
||
<th scope="col">{% trans "Name" %}</th>
|
||
<th scope="col" data-sort-method="none"><span class="visually-hidden">{% trans "Actions" %}</span></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="searchable">
|
||
{% for host in fixed_addresses %}
|
||
<tr data-search="{{ host.ip }} {{ host.mac|default:"" }}{{ host.id|default:"" }} {{ host.name }}">
|
||
<td class="font-monospace text-nowrap">{{ host.ip }}</td>
|
||
<td class="font-monospace text-nowrap">{{ host.mac|default:host.id|default:"–" }}</td>
|
||
<td class="text-break">{{ host.name|default:"–" }}</td>
|
||
<td class="text-end text-nowrap">
|
||
<div class="btn-group" role="group" aria-label="{% blocktrans with address=host.ip %}Actions for {{ address }}{% endblocktrans %}">
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#FixedAddress"
|
||
data-ip-index="{{ host.ip_index }}" data-original="{{ host.ip }}" data-address="{{ host.ip }}"
|
||
data-mac="{{ host.mac|default:host.id|default:"" }}" data-name="{{ host.name }}" aria-label="{% trans "Edit" %}">{% bs_icon 'pencil' %} <span class="d-none d-sm-inline">{% trans "Edit" %}</span></button>
|
||
<div class="btn-group">
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false"
|
||
data-bs-popper-config='{"strategy": "fixed"}' aria-label="{% trans "More actions" %}">{% bs_icon 'three-dots' %}</button>
|
||
<ul class="dropdown-menu dropdown-menu-end shadow">
|
||
<li><form method="post">{% csrf_token %}
|
||
<input type="hidden" name="ip_index" value="{{ host.ip_index }}">
|
||
<input type="hidden" name="original" value="{{ host.ip }}">
|
||
<button type="submit" class="dropdown-item text-danger" name="delete_fixed_address"
|
||
data-confirm="{% blocktrans with address=host.ip %}Delete the fixed address {{ address }}? The VM may get another address when its lease ends.{% endblocktrans %}">{% bs_icon 'trash' %} {% trans "Delete" %}</button>
|
||
</form></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div role="status">
|
||
<div id="no-match" class="text-center text-body-secondary py-3" hidden>{% trans "No fixed address matches the search." %}</div>
|
||
</div>
|
||
{% elif dhcp_networks %}
|
||
<div class="card-body small text-body-secondary">{% trans "No fixed addresses: every VM gets one from the DHCP range." %}</div>
|
||
{% else %}
|
||
<div class="card-body small text-body-secondary">{% trans "The network serves no DHCP, so it has no fixed addresses." %}</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
{% if dhcp_networks %}
|
||
<div class="card mb-3">
|
||
<div class="card-header">{% trans "DHCP leases" %} {% if leases %}<span class="badge text-bg-light border">{{ leases|length }}</span>{% endif %}</div>
|
||
{% if leases_error %}
|
||
<div class="card-body small text-danger">{% blocktrans with error=leases_error %}The leases could not be read: {{ error }}{% endblocktrans %}</div>
|
||
{% elif leases %}
|
||
<div class="table-responsive position-relative">
|
||
<table class="table table-hover align-middle mb-0">
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">{% trans "Address" %}</th>
|
||
<th scope="col">{% trans "MAC / DUID" %}</th>
|
||
<th scope="col">{% trans "Host name" %}</th>
|
||
<th scope="col">{% trans "VM" %}</th>
|
||
<th scope="col">{% trans "Ends" %}</th>
|
||
<th scope="col"><span class="visually-hidden">{% trans "Actions" %}</span></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for lease in leases %}
|
||
<tr>
|
||
<td class="text-nowrap">
|
||
<span class="font-monospace">{{ lease.ip }}</span>
|
||
{% if lease.fixed %}<span class="badge text-bg-light border">{% trans "Fixed" %}</span>{% endif %}
|
||
</td>
|
||
<td class="font-monospace text-nowrap">{{ lease.key|default:"–" }}</td>
|
||
<td class="text-nowrap">{{ lease.hostname|default:"–" }}</td>
|
||
<td>
|
||
{% if lease.vm.id %}
|
||
<a href="{% url 'instances:instance' lease.vm.id %}">{{ lease.vm.name }}</a>
|
||
{% else %}
|
||
{{ lease.vm.name|default:"–" }}
|
||
{% endif %}
|
||
</td>
|
||
<td class="text-nowrap">
|
||
{% if lease.expires %}
|
||
<div>{% blocktrans with time=lease.expires|timeuntil %}in {{ time }}{% endblocktrans %}</div>
|
||
<div class="small text-body-secondary">{{ lease.expires|date:"Y-m-d H:i" }}</div>
|
||
{% else %}
|
||
{% trans "Never" %}
|
||
{% endif %}
|
||
</td>
|
||
<td class="text-end">
|
||
{# a lease kept as a fixed address: the dialog of a new one, filled in #}
|
||
{% if not lease.fixed and lease.key and lease.ip_index is not None %}
|
||
<button type="button" class="btn btn-sm btn-outline-secondary text-nowrap" data-bs-toggle="modal" data-bs-target="#FixedAddress"
|
||
data-ip-index="{{ lease.ip_index }}" data-address="{{ lease.ip }}" data-mac="{{ lease.key }}"
|
||
data-name="{{ lease.name }}">{% bs_icon 'pin-angle' %} {% trans "Make fixed" %}</button>
|
||
{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% elif state %}
|
||
<div class="card-body small text-body-secondary">{% trans "No current DHCP leases." %}</div>
|
||
{% else %}
|
||
<div class="card-body small text-body-secondary">{% trans "The network is not running, so it gives no leases." %}</div>
|
||
{% endif %}
|
||
</div>
|
||
{% endif %}
|
||
{% endif %}
|
||
|
||
<div class="card mb-3">
|
||
<div class="card-header">{% trans "VMs on this network" %}</div>
|
||
{% if vms %}
|
||
<ul class="list-group list-group-flush">
|
||
{% for vm in vms %}
|
||
<li class="list-group-item py-1 d-flex justify-content-between align-items-center gap-3">
|
||
{% if vm.id %}<a href="{% url 'instances:instance' vm.id %}">{{ vm.name }}</a>{% else %}<span>{{ vm.name }}</span>{% endif %}
|
||
{% if vm.connected %}<span class="badge text-bg-success">{% trans "Connected" %}</span>{% else %}<span class="badge text-bg-light border">{% trans "Configured" %}</span>{% endif %}
|
||
</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% else %}
|
||
<div class="card-body small text-body-secondary">{% trans "No VM is defined on this network." %}</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
{% if qos_supported %}
|
||
<div class="card mb-3">
|
||
<div class="card-header d-flex flex-wrap align-items-center gap-2">
|
||
<span class="me-auto">{% trans "Bandwidth limits" %}</span>
|
||
{% if qos.items|length < 2 %}
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#QosLimit">{% bs_icon 'plus-lg' %} {% trans "Add limit" %}</button>
|
||
{% endif %}
|
||
</div>
|
||
{% if qos %}
|
||
<div class="table-responsive">
|
||
<table class="table align-middle mb-0">
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">{% trans "Direction" %}</th>
|
||
<th scope="col">{% trans "Average" %}</th>
|
||
<th scope="col">{% trans "Peak" %}</th>
|
||
<th scope="col">{% trans "Burst" %}</th>
|
||
<th scope="col"><span class="visually-hidden">{% trans "Actions" %}</span></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for direction, limit in qos.items %}
|
||
{% if direction == "inbound" %}{% trans "inbound" as direction_name %}{% else %}{% trans "outbound" as direction_name %}{% endif %}
|
||
<tr>
|
||
<td>{% if direction == "inbound" %}{% trans "Inbound" %}{% else %}{% trans "Outbound" %}{% endif %}</td>
|
||
<td>{% if limit.average %}{{ limit.average }} KiB/s{% else %}–{% endif %}</td>
|
||
<td>{% if limit.peak %}{{ limit.peak }} KiB/s{% else %}–{% endif %}</td>
|
||
<td>{% if limit.burst %}{{ limit.burst }} KiB{% else %}–{% endif %}</td>
|
||
<td class="text-end text-nowrap">
|
||
<div class="btn-group" role="group" aria-label="{% trans "Actions for the limit" %}">
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#QosLimit"
|
||
data-direction="{{ direction }}" data-average="{{ limit.average|default:"" }}" data-peak="{{ limit.peak|default:"" }}"
|
||
data-burst="{{ limit.burst|default:"" }}" aria-label="{% trans "Edit" %}">{% bs_icon 'pencil' %} <span class="d-none d-sm-inline">{% trans "Edit" %}</span></button>
|
||
<form method="post" class="btn-group">{% csrf_token %}
|
||
<input type="hidden" name="qos_direction" value="{{ direction }}">
|
||
<button type="submit" class="btn btn-sm btn-outline-secondary" name="unset_qos" aria-label="{% trans "Remove" %}"
|
||
data-confirm="{% blocktrans with direction=direction_name name=pool %}Remove the {{ direction }} limit of network {{ name }}? It stays in force until the network is stopped and started.{% endblocktrans %}">{% bs_icon 'trash' %}</button>
|
||
</form>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% else %}
|
||
<div class="card-body small text-body-secondary">{% trans "No limits: the network's VMs share the host's bandwidth freely." %}</div>
|
||
{% endif %}
|
||
{% if state %}
|
||
<div class="card-footer small text-body-secondary">{% trans "A change takes effect when the network is stopped and started again." %}</div>
|
||
{% endif %}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<section class="accordion mb-3" aria-labelledby="xml-heading">
|
||
<div class="accordion-item">
|
||
<h2 class="accordion-header" id="xml-heading">
|
||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#network-xml" aria-expanded="false" aria-controls="network-xml">
|
||
{% trans "XML definition" %}
|
||
</button>
|
||
</h2>
|
||
<div class="accordion-collapse collapse" id="network-xml">
|
||
<form method="post" class="accordion-body" aria-label="{% trans "Change the network's XML" %}">{% csrf_token %}
|
||
<p class="small text-body-secondary">{% trans "The saved definition: a running network takes a change when it is stopped and started again." %}</p>
|
||
<input type="hidden" name="edit_xml">
|
||
<div class="xmlheight mb-3"><textarea id="edit_editor" aria-label="{% trans "Network XML" %}">{{ xml }}</textarea></div>
|
||
<div class="d-flex justify-content-end">
|
||
<button type="submit" class="btn btn-primary" name="edit_network">{% trans "Save" %}</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{# one dialog for every fixed address: Add opens it empty, a row's Edit with its entry, which stays on its subnet #}
|
||
{% if dhcp_networks %}
|
||
<div class="modal fade" id="FixedAddress" tabindex="-1" aria-labelledby="FixedAddressLabel" aria-hidden="true">
|
||
<div class="modal-dialog">
|
||
<form method="post" class="modal-content">{% csrf_token %}
|
||
<input type="hidden" name="original">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title" id="FixedAddressLabel">{% trans "Fixed address" %}</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="mb-3" id="fixed_subnet_row">
|
||
<label for="fixed_ip_index" class="form-label">{% trans "Subnet" %}</label>
|
||
<select id="fixed_ip_index" name="ip_index" class="form-select">
|
||
{% for ip in dhcp_networks %}<option value="{{ ip.index }}">{{ ip.subnet }}</option>{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label for="fixed_address" class="form-label">{% trans "Address" %}</label>
|
||
<input id="fixed_address" name="address" class="form-control font-monospace" required>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label for="fixed_mac" class="form-label">{% trans "MAC (IPv4) or DUID (IPv6)" %}</label>
|
||
<input id="fixed_mac" name="mac" class="form-control font-monospace" pattern="[0-9a-fA-F:]+" aria-describedby="fixed_mac_help">
|
||
<div class="form-text" id="fixed_mac_help">{% trans "The VM's network card; without it, the VM is known by its name." %}</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label for="fixed_name" class="form-label">{% trans "Name" %}</label>
|
||
<input id="fixed_name" name="name" class="form-control" pattern="[a-zA-Z0-9_.\-]+">
|
||
</div>
|
||
</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="modify_fixed_address">{% trans "Save" %}</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<div class="modal fade" id="DhcpRange" tabindex="-1" aria-labelledby="DhcpRangeLabel" aria-hidden="true">
|
||
<div class="modal-dialog">
|
||
<form method="post" class="modal-content">{% csrf_token %}
|
||
<input type="hidden" name="ip_index">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title" id="DhcpRangeLabel">{% trans "DHCP range" %} <span class="text-body-secondary font-monospace" id="dhcp_subnet"></span></h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
||
</div>
|
||
<div class="modal-body row g-3">
|
||
<div class="col-sm-6">
|
||
<label for="range_start" class="form-label">{% trans "From" %}</label>
|
||
<input id="range_start" name="range_start" class="form-control font-monospace" required>
|
||
</div>
|
||
<div class="col-sm-6">
|
||
<label for="range_end" class="form-label">{% trans "To" %}</label>
|
||
<input id="range_end" name="range_end" class="form-control font-monospace" required>
|
||
</div>
|
||
</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="modify_dhcp_range">{% trans "Save" %}</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
{% if qos_supported %}
|
||
<div class="modal fade" id="QosLimit" tabindex="-1" aria-labelledby="QosLimitLabel" aria-hidden="true">
|
||
<div class="modal-dialog">
|
||
<form method="post" class="modal-content">{% csrf_token %}
|
||
<div class="modal-header">
|
||
<h5 class="modal-title" id="QosLimitLabel">{% trans "Bandwidth limit" %}</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
||
</div>
|
||
<div class="modal-body row g-3">
|
||
<div class="col-12">
|
||
<label for="qos_direction" class="form-label">{% trans "Direction" %}</label>
|
||
<select id="qos_direction" name="qos_direction" class="form-select">
|
||
{# a direction with a limit is changed by its own Edit button #}
|
||
<option value="inbound"{% if "inbound" in qos %} data-taken{% endif %}>{% trans "Inbound: to the VMs" %}</option>
|
||
<option value="outbound"{% if "outbound" in qos %} data-taken{% endif %}>{% trans "Outbound: from the VMs" %}</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-sm-4">
|
||
<label for="qos_average" class="form-label">{% trans "Average (KiB/s)" %}</label>
|
||
<input id="qos_average" name="qos_average" type="number" min="1" class="form-control" required>
|
||
</div>
|
||
<div class="col-sm-4">
|
||
<label for="qos_peak" class="form-label">{% trans "Peak (KiB/s)" %}</label>
|
||
<input id="qos_peak" name="qos_peak" type="number" min="0" class="form-control" aria-describedby="qos_peak_help">
|
||
</div>
|
||
<div class="col-sm-4">
|
||
<label for="qos_burst" class="form-label">{% trans "Burst (KiB)" %}</label>
|
||
<input id="qos_burst" name="qos_burst" type="number" min="0" class="form-control">
|
||
</div>
|
||
<div class="col-12 form-text mt-1" id="qos_peak_help">{% trans "Linux applies a peak to inbound traffic only." %}</div>
|
||
</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="set_qos">{% trans "Save" %}</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
{% endblock %}
|
||
|
||
{% block script %}
|
||
{% if fixed_addresses %}<script src="{% static 'js/table_filter.js' %}"></script>{% endif %}
|
||
<script src="{% static "js/ace/ace.js" %}"></script>
|
||
<script src="{% static 'js/network_page.js' %}"></script>
|
||
{% endblock %}
|