1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 11:46:49 +00:00
webvirtcloud/instances/templates/instances/access_tab.html
catborise 75fcc6f6c0 feat(instances): a running VM gets its root password and SSH key through its guest agent
The Access tab's Root Password and SSH Keys worked only on a shut-off
VM, through gstfsd on the compute. A running VM whose QEMU guest agent
is connected now gets them through the agent: guest-set-user-password
with the SHA-512 crypt hash, and guest-ssh-add-authorized-keys adding
the key to root's keys. A shut-off VM still goes through gstfsd; any
other VM is refused with "Shut the VM down, or start its QEMU guest
agent, and try again", and the buttons are disabled.

Each is one agent command with a 10 s timeout. libvirt's own calls for
them (setUserPassword, authorizedSSHKeysSet) wait for a hung agent
indefinitely, holding a worker and the VM's lock, and the domain's
agent timeout would change every other agent call of the VM too.

The agent's or libvirt's error is shown as is through error_text, so
users who do not see the hosts get no connection details, and the
attempt is logged as failed. The README names the SELinux boolean a
RHEL-family guest needs before its agent may add SSH keys.
2026-10-25 15:37:37 +03:00

169 lines
No EOL
9.3 KiB
HTML

{% load i18n %}
<div class="tab-pane" id="access" role="tabpanel" aria-label="Instance access options">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#vnconsole" type="button" role="tab" aria-controls="vnconsole" aria-selected="true">
{% trans "Console" %}
</button>
</li>
{% if app_settings.SHOW_ACCESS_ROOT_PASSWORD == 'True' and can_change %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#rootpasswd" type="button" role="tab" aria-controls="rootpasswd" aria-selected="false">
{% trans "Root Password" %}
</button>
</li>
{% endif %}
{% if app_settings.SHOW_ACCESS_SSH_KEYS == 'True' and can_change %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#sshkeys" type="button" role="tab" aria-controls="sshkeys" aria-selected="false">
{% trans "SSH Keys" %}
</button>
</li>
{% endif %}
{% if instance.status == 1 and can_open_console %}
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#vdiconsole" type="button" role="tab" aria-controls="vdiconsole" aria-selected="false">
{% trans "VDI" %}
</button>
</li>
{% endif %}
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="vnconsole">
<p>{% blocktrans with type=instance.console_type|upper %} This action opens a new window with a {{ type }} connection to the console of the instance.{% endblocktrans %}
</p>
{% if not can_open_console %}
<p>{% trans "Only the owners of this instance and administrators can open its console." %}</p>
{% else %}
{% if instance.console_type == 'vnc' %}
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="scale"
{% if app_settings.CONSOLE_SCALE == 'True' %} checked {% endif %}
id="scale">
<label class="form-check-label" for="scale">{% trans "Scale" %}</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="view_only"
{% if app_settings.CONSOLE_VIEW_ONLY == 'True' %} checked {% endif %}
id="view_only">
<label class="form-check-label" for="view_only">{% trans "View Only" %}</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="resize_session"
{% if app_settings.CONSOLE_RESIZE_SESSION == 'True' %} checked {% endif %}
id="resize_session">
<label class="form-check-label" for="resize_session">{% trans "Resize Session" %}</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="clip_viewport"
{% if app_settings.CONSOLE_CLIP_VIEWPORT == 'True' %} checked {% endif %}
id="clip_viewport">
<label class="form-check-label" for="clip_viewport">{% trans "View Clipboard" %}</label>
</div>
{% endif %}
{% if instance.status == 1 %}
<!-- Split button -->
<div class="btn-group float-end" role="group">
<button type="button" id="consoleBtnGroup" class="btn btn-lg btn-success"
onclick="open_console('lite')">{% trans 'Console' %}</button>
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#"
title="{% trans "Console port" %}: {{ instance.console_port }}"
onclick="open_console('lite')">{% trans "Console" %} - {% trans "Lite" %}</a>
<a class="dropdown-item" href="#"
title="{% trans "Console port" %}: {{ instance.console_port }}"
onclick="open_console('full')">{% trans "Console" %} - {% trans "Full" %}</a>
</div>
</div>
{% else %}
<button class="btn btn-lg btn-success float-end disabled">{% trans "Console" %}</button>
{% endif %}
{% endif %}
<div class="clearfix"></div>
</div>
{% if app_settings.SHOW_ACCESS_ROOT_PASSWORD == 'True' and can_change %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="rootpasswd">
<p>{% trans "Shut the VM down, or run it with its QEMU guest agent, and enter a new root password." %}</p>
<form action="{% url 'instances:rootpasswd' instance.id %}" method="post"
role="form" aria-label="Add root password to instance form">
{% csrf_token %}
<div class="row">
<div class="col-sm-12">
<input type="text" class="form-control-lg" name="passwd"
placeholder="{% trans "Enter Password" %}" maxlength="24">
</div>
</div>
{% if instance.status == 5 or instance.status == 1 and instance.guest_agent_ready %}
<input type="submit" class="btn btn-lg btn-success float-end" name="rootpasswd"
value="{% trans "Reset Root Password" %}">
{% else %}
<button
class="btn btn-lg btn-success float-end disabled">{% trans "Reset Root Password" %}</button>
{% endif %}
</form>
<div class="clearfix"></div>
</div>
{% endif %}
{% if app_settings.SHOW_ACCESS_SSH_KEYS == 'True' and can_change %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="sshkeys">
<p>{% trans "Shut the VM down, or run it with its QEMU guest agent, and choose your public key. The key is added to root's keys." %}</p>
<form action="{% url 'instances:add_public_key' instance.id %}"method="post"
role="form" aria-label="Add public key to instance form">
{% csrf_token %}
<div class="row">
<div class="col-sm-12">
<select name="sshkeyid" class="form-control-lg keyselect">
{% if publickeys %}
{% for key in publickeys %}
<option value="{{ key.id }}">{{ key.keyname }}</option>
{% endfor %}
{% else %}
<option value="None">{% trans "None" %}</option>
{% endif %}
</select>
</div>
</div>
{% if instance.status == 5 or instance.status == 1 and instance.guest_agent_ready %}
<input type="submit" class="btn btn-lg btn-success float-end" name="addpublickey"
value="{% trans "Add Public Key" %}">
{% else %}
<button class="btn btn-lg btn-success float-end disabled">{% trans "Add Public Key" %}</button>
{% endif %}
</form>
<div class="clearfix"></div>
</div>
{% endif %}
{% if instance.status == 1 and can_open_console %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="vdiconsole">
<p>{% trans "This action opens a remote viewer with a connection to the console of the instance." %}</p>
<div class="input-group">
<input type="text" class="input-lg disabled form-control" disabled id="vdi_url_input" />
<a href="#" class="btn btn-success" id="vdi_url">{% trans "VDI" %}</a>
</div>
<p>{% trans "To download console.vv file for virt-viewer." %}</p>
<a href="{% url 'instances:getvvfile' instance.id %}" class="btn btn-lg btn-success float-end">{% trans "Get console.vv" %}</a>
<div class="clearfix"></div>
</div>
{% endif %}
</div>
</div>
{% block script %}
{% if can_open_console %}
<script>
function open_console(view_style) {
const sc = $("#scale").is(':checked');
const vo = $("#view_only").is(':checked');
const rs = $("#resize_session").is(':checked');
const cv = $("#clip_viewport").is(':checked');
url = '{% url 'console' %}?token={{ compute.id }}-{{ instance.get_uuid }}&view=' + view_style + '' + '&view_only=' + vo + '' + '&scale=' + sc + '' + '&clip_viewport=' + cv + '' + '&resize_session=' + rs + '';
window.open(url, '', 'width=850,height=600')
}
</script>
{% endif %}
{% endblock %}