mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-11 12:46:49 +00:00
feat(instances): a VM's console settings in two cards, with a password action
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.
This commit is contained in:
parent
20cfc25367
commit
301b73155d
12 changed files with 248 additions and 126 deletions
|
|
@ -21,24 +21,35 @@ class FlavorForm(forms.ModelForm):
|
|||
|
||||
|
||||
class ConsoleForm(forms.Form):
|
||||
console_type = forms.ChoiceField(label=_("Console type"), required=False)
|
||||
listen_on = forms.ChoiceField(label=_("Listen on"))
|
||||
generate_password = forms.BooleanField(label=_("Generate password"), required=False)
|
||||
clear_password = forms.BooleanField(label=_("Clear password"), required=False)
|
||||
password = forms.CharField(
|
||||
label=_("Password"),
|
||||
widget=forms.PasswordInput(render_value=True),
|
||||
required=False
|
||||
console_type = forms.ChoiceField(
|
||||
label=_("Console type"), required=False, widget=forms.Select(attrs={"class": "form-select"})
|
||||
)
|
||||
password_action = forms.ChoiceField(
|
||||
label=_("Password"),
|
||||
choices=[
|
||||
("keep", _("Keep the password")),
|
||||
("generate", _("Generate a new one")),
|
||||
("set", _("Set a new one")),
|
||||
("none", _("No password")),
|
||||
],
|
||||
widget=forms.RadioSelect(attrs={"class": "form-check-input"}),
|
||||
)
|
||||
password = forms.CharField(
|
||||
label=_("New password"),
|
||||
widget=forms.PasswordInput(attrs={"class": "form-control", "autocomplete": "new-password"}),
|
||||
required=False,
|
||||
strip=False,
|
||||
)
|
||||
keymap = forms.ChoiceField(label=_("Keymap"), required=False)
|
||||
|
||||
def __init__(self, *args, instance, can_set_listener, **kwargs):
|
||||
def __init__(self, *args, instance, is_superuser, **kwargs):
|
||||
# the VM's settings as the initial values: a save changes only the fields edited
|
||||
self.instance = instance
|
||||
self.is_superuser = is_superuser
|
||||
listener = instance.config_console_listener_address
|
||||
kwargs["initial"] = {
|
||||
"console_type": instance.console_type,
|
||||
"console_type": instance.config_console_type,
|
||||
"listen_on": listener,
|
||||
"password": instance.config_console_passwd,
|
||||
"password_action": "keep",
|
||||
"keymap": instance.config_console_keymap or "auto",
|
||||
}
|
||||
super(ConsoleForm, self).__init__(*args, **kwargs)
|
||||
|
|
@ -46,6 +57,11 @@ class ConsoleForm(forms.Form):
|
|||
if settings.SERIAL_CONSOLE_ENABLED:
|
||||
types.append(("pty", _("Serial (xterm; the guest needs a getty on ttyS0)")))
|
||||
self.fields["console_type"].choices = types
|
||||
# the VNC settings are shown and saved while the console is VNC; a
|
||||
# switch to Serial ignores them
|
||||
if "pty" in (instance.config_console_type, self.data.get("console_type")):
|
||||
del self.fields["password_action"], self.fields["password"]
|
||||
return
|
||||
keymap_choices = [("auto", _("Auto"))] + list((c, c) for c in QEMU_KEYMAPS)
|
||||
# Only administrators choose the listen address: beyond localhost the
|
||||
# console is reachable from the network. A disabled field ignores
|
||||
|
|
@ -57,10 +73,32 @@ class ConsoleForm(forms.Form):
|
|||
self.fields["listen_on"] = forms.ChoiceField(
|
||||
label=_("Listen on"),
|
||||
choices=listeners,
|
||||
disabled=not can_set_listener,
|
||||
required=can_set_listener,
|
||||
disabled=not is_superuser,
|
||||
required=is_superuser,
|
||||
widget=forms.Select(attrs={"class": "form-select"}),
|
||||
)
|
||||
self.fields["keymap"] = forms.ChoiceField(label=_("Keymap"), choices=keymap_choices)
|
||||
self.fields["keymap"] = forms.ChoiceField(
|
||||
label=_("Keymap"), choices=keymap_choices, widget=forms.Select(attrs={"class": "form-select"})
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
data = super().clean()
|
||||
action = data.get("password_action")
|
||||
if action == "set":
|
||||
password = data.get("password", "")
|
||||
if not password:
|
||||
self.add_error("password", _("Enter the new password."))
|
||||
# VNC uses 8 bytes; libvirt refuses a longer password
|
||||
elif len(password.encode()) > 8:
|
||||
self.add_error("password", _("A VNC password takes at most 8 bytes."))
|
||||
# A console that listens beyond localhost (set by an administrator)
|
||||
# keeps its password unless an administrator removes it.
|
||||
if action == "none" and not self.is_superuser and not self.instance.proxy.console_listens_locally():
|
||||
self.add_error(
|
||||
"password_action",
|
||||
_("The console listens beyond localhost; only an administrator can remove its password."),
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
class NewVMForm(forms.ModelForm):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue