1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/interfaces/templates/interface.html
catborise 050d071ff9 feat(interfaces): the interface pages on Bootstrap's cards, tables and dialogs
As the storage and network pages; plan reviewed with Codex.

- The list is grouped by type (bridges, bonds, VLANs, ethernet; a type
  the host has none of is left out), three cards a row, with a search
  of their names, MACs and networks (table_filter.js, which now takes
  any element with data-search as a row); a card per interface: its link
  as the kernel reports it (up green, down grey, another state or
  unknown told as such, no red card for a link that is merely down),
  MAC, MTU, speed when known, the members it reports and the libvirt
  networks that use it, linked.
- An interface's page: an Interface card (type, libvirt's own state
  where it manages interfaces, link, start mode, MAC, MTU, speed, STP,
  networks using it); on a host whose libvirt changes interfaces, a
  card per family with how it is addressed and its addresses; the
  members of a bridge, bond or VLAN with their link and speed, or that
  none is reported; for a bridge, the running VMs' cards on it,
  directly or through a network using it, with their tap and MAC,
  linked (wvmInterface.get_vms: one domain listing). Not the bridge's
  delay: netcf tells it in seconds, the udev backend in hundredths.
  Start or Stop in its heading, Delete in its menu, disabled while it
  runs, on hosts that can change interfaces only.
- A host whose libvirt only reads interfaces says so once, with that
  it does not tell their addresses, instead of "None" on every page.
- The New interface dialog is one form, as the New pool and New
  network ones (choice_dialog.js, radio_card.html): Bridge or
  Ethernet, a bridge's member from the devices it can take, an
  ethernet interface's device from the ones the host does not define
  yet, a static address's fields with its choice; a refused interface,
  or one libvirt refuses, opens it again with what was entered; a made
  one opens its page.
- networks_by_device maps the libvirt networks to their bridges or
  interfaces on the page's own connection.
2026-10-29 10:09:52 +03:00

177 lines
9.8 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.

{% extends "base.html" %}
{% load i18n %}
{% load bootstrap_icons %}
{% block title %}{% trans "Interface" %} - {{ iface }}{% endblock %}
{% block page_heading %}{{ compute.name }} - {% trans "Interface" %}: {{ iface }}{% endblock page_heading %}
{% block page_heading_extra %}
{% if changeable and info %}
{# the interface's own actions where the host's libvirt can change interfaces: start or stop, and delete a stopped one #}
<div class="btn-group" role="group" aria-label="{% blocktrans %}Actions for interface {{ iface }}{% 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=iface %}Stop interface {{ name }}? The host and its VMs lose their connections through it at once; if you reach the host through it, you lose the host.{% endblocktrans %}"
onclick="return confirm(this.dataset.confirm)">{% 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 %}
<button type="submit" class="dropdown-item text-danger" name="delete"{% if state %} disabled{% endif %}
data-confirm="{% blocktrans with name=iface %}Delete interface {{ name }}? Its definition is removed from the host; a bridge's members are defined again on their own, its addresses going to its only member.{% endblocktrans %}"
onclick="return confirm(this.dataset.confirm)">{% bs_icon 'trash' %} {% if state %}{% trans "Delete (stop it first)" %}{% else %}{% trans "Delete interface" %}{% endif %}</button>
</form></li>
</ul>
</div>
</div>
{% endif %}
{% endblock page_heading_extra %}
{% block content %}
{% include "computes/host_nav.html" with section="interfaces" detail=True %}
{% if changeable is False %}{% include 'interfaces_unchangeable.html' %}{% endif %}
{% if info %}
<div class="card mb-3">
<div class="card-header">{% trans "Interface" %}</div>
<ul class="list-group list-group-flush">
<li class="list-group-item 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">{{ info.type|capfirst }}</span>
</li>
<li class="list-group-item 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">
{# libvirt's own state where it manages the interface; the link as the kernel reports it everywhere #}
{% if changeable %}{% if state %}<span class="badge text-bg-success">{% trans "Active" %}</span>{% else %}<span class="badge text-bg-secondary">{% trans "Inactive" %}</span>{% endif %}{% endif %}
{% include "link_badge.html" with link=info.link %}
</span>
</li>
{% if info.start_mode %}
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Starts" %}</span>
<span>{% if info.start_mode == "onboot" %}{% trans "On boot" %}{% elif info.start_mode == "hotplug" %}{% trans "When plugged in" %}{% else %}{% trans "Only by hand" %}{% endif %}</span>
</li>
{% endif %}
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "MAC" %}</span><span class="font-monospace text-break text-end">{{ info.mac|default:"–" }}</span>
</li>
{% if info.mtu %}
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "MTU" %}</span><span>{{ info.mtu }}</span>
</li>
{% endif %}
{% if info.speed %}
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Speed" %}</span><span>{{ info.speed }} Mb/s</span>
</li>
{% endif %}
{% if info.stp %}
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Spanning tree" %}</span>
{# not its delay: netcf tells it in seconds, the udev backend in hundredths #}
<span>{% if info.stp == "on" %}{% trans "On" %}{% else %}{% trans "Off" %}{% endif %}</span>
</li>
{% endif %}
{% if networks %}
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Used by" %}</span>
<span class="text-end">{% for net in networks %}<a href="{% url 'network' compute.id net %}">{% blocktrans %}network {{ net }}{% endblocktrans %}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</span>
</li>
{% endif %}
</ul>
</div>
{% if changeable %}
<div class="row row-cols-1 row-cols-md-2 g-3 mb-3">
{% for family, addressing in info.addressing %}
<div class="col">
<div class="card h-100">
<div class="card-header">{{ family }}</div>
<ul class="list-group list-group-flush flex-grow-1">
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Configured" %}</span>
<span>{% if addressing.method == "dhcp" %}DHCP{% elif addressing.method == "autoconf" %}{% trans "Automatic (SLAAC)" %}{% elif addressing.method == "static" %}{% trans "Static" %}{% else %}{% trans "None" %}{% endif %}</span>
</li>
{% for address in addressing.addresses %}
<li class="list-group-item d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Address" %}</span><span class="font-monospace text-break text-end">{{ address }}</span>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% if info.type == "bridge" or info.type == "bond" or info.type == "vlan" %}
<div class="card mb-3">
<div class="card-header">{% if info.type == "vlan" %}{% trans "Device" %}{% else %}{% trans "Members" %}{% endif %}</div>
{% if info.members %}
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead>
<tr>
<th scope="col">{% trans "Name" %}</th>
<th scope="col">{% trans "Type" %}</th>
<th scope="col">{% trans "MAC" %}</th>
<th scope="col">{% trans "Link" %}</th>
<th scope="col">{% trans "Speed" %}</th>
</tr>
</thead>
<tbody>
{% for member in info.members %}
<tr>
<td class="font-monospace text-nowrap">{{ member.name }}</td>
<td>{{ member.type|default:"–" }}</td>
<td class="font-monospace text-nowrap">{{ member.mac|default:"–" }}</td>
<td>{% include "link_badge.html" with link=member.link %}</td>
<td class="text-nowrap">{% if member.speed %}{{ member.speed }} Mb/s{% else %}–{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card-body small text-body-secondary">{% trans "libvirt reports no members." %}</div>
{% endif %}
</div>
{% endif %}
{% if info.type == "bridge" %}
<div class="card mb-3">
<div class="card-header">{% trans "Connected VM interfaces" %}</div>
{% if vms %}
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead>
<tr>
<th scope="col">{% trans "VM" %}</th>
<th scope="col">{% trans "Tap" %}</th>
<th scope="col">{% trans "VM's MAC" %}</th>
</tr>
</thead>
<tbody>
{% for vm in vms %}
<tr>
<td>{% if vm.id %}<a href="{% url 'instances:instance' vm.id %}">{{ vm.vm }}</a>{% else %}{{ vm.vm }}{% endif %}</td>
<td class="font-monospace">{{ vm.tap|default:"–" }}</td>
<td class="font-monospace text-nowrap">{{ vm.mac|default:"–" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card-body small text-body-secondary">{% trans "No running VM is on this bridge." %}</div>
{% endif %}
</div>
{% endif %}
{% endif %}
{% endblock %}