mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
fix(logs): a resolved migration and an unapplied console setting log what happened
From the Codex and agy review of the VM audit log before v3.2.0: - Resolving an uncertain migration wrote its row without the VM's UUID, because the migrate job writes no entries of its own; the resolution now takes the UUID from the job's intent, so the VM's Logs tab shows it. - A console keymap or listen address the VM could not take (no graphics device, or a console on a socket) was logged as done although nothing changed; it now writes no row, as an edit that changes nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c1d36053d6
commit
70e5c317ff
3 changed files with 34 additions and 6 deletions
|
|
@ -90,6 +90,17 @@ class VMRowTests(TestCase):
|
|||
self.assertEqual(rows, [("VM vm: set console password: The VM has no graphics device", False),
|
||||
("VM vm: set console password", True)])
|
||||
|
||||
def test_a_console_setting_that_changed_nothing_writes_no_row(self):
|
||||
self.proxy.get_console_type.return_value = "vnc"
|
||||
self.proxy.set_console_keymap.return_value = False # no graphics device
|
||||
self.proxy.set_console_listener_addr.return_value = False # a socket, no address
|
||||
self.post("update_console", {"listen_on": "0.0.0.0", "keymap": "de"})
|
||||
self.proxy.set_console_keymap.return_value = None # the define's result
|
||||
self.proxy.set_console_listener_addr.return_value = None
|
||||
self.post("update_console", {"listen_on": "0.0.0.0", "keymap": "de"})
|
||||
self.assertEqual(self.rows(), [("VM vm: set console keymap de", True),
|
||||
("VM vm: set console listen address 0.0.0.0", True)])
|
||||
|
||||
def test_a_deleted_vm_and_each_of_its_disks_have_their_own_row(self):
|
||||
self.proxy.split_disk_paths_by_use.return_value = (["/pool/a.qcow2", "/pool/b.qcow2"], [])
|
||||
volume = self.proxy.get_volume_by_path.return_value
|
||||
|
|
@ -159,3 +170,18 @@ class JobRowTests(TestCase):
|
|||
op = Operation(kind=kind, resource_label=label, params=params, intent=intent)
|
||||
state = Operation.FAILED if kind == "snapshot.delete" else Operation.SUCCEEDED
|
||||
self.assertEqual(get_kind(kind).log_entry(op, state), entry)
|
||||
|
||||
|
||||
class MigrationResolutionRowTests(TestCase):
|
||||
def test_a_resolved_migration_carries_the_vm_uuid(self):
|
||||
from operations import jobs
|
||||
from operations.models import Operation
|
||||
|
||||
admin = get_user_model().objects.create_superuser("res-admin", "res@example.com", "pw")
|
||||
op = Operation.objects.create(kind="instance.migrate", user=admin, username=admin.username,
|
||||
submission_key="key-res-00000001", resource="instance:" + UUID,
|
||||
resource_label="c1/vm", state=Operation.UNCERTAIN,
|
||||
intent={"compute": 1, "uuid": UUID})
|
||||
jobs.resolve(op.pk, admin, Operation.SUCCEEDED, "the VM runs on the target")
|
||||
row = Logs.objects.get(message__contains="resolved")
|
||||
self.assertEqual((row.instance, row.instance_uuid, row.success), ("c1/vm", UUID, True))
|
||||
|
|
|
|||
|
|
@ -1781,12 +1781,13 @@ def update_console(request, pk):
|
|||
|
||||
if "keymap" in form.changed_data or "clear_keymap" in form.changed_data:
|
||||
keymap = "" if form.cleaned_data["clear_keymap"] else form.cleaned_data["keymap"]
|
||||
with audit_vm(request, instance, f"set console keymap {keymap}" if keymap else "remove console keymap"):
|
||||
instance.proxy.set_console_keymap(keymap)
|
||||
# False: no graphics device, nothing changed
|
||||
with audit_vm(request, instance, f"set console keymap {keymap}" if keymap else "remove console keymap") as entry:
|
||||
entry.skip = instance.proxy.set_console_keymap(keymap) is False
|
||||
|
||||
if "listen_on" in form.changed_data:
|
||||
with audit_vm(request, instance, f"set console listen address {form.cleaned_data['listen_on']}"):
|
||||
instance.proxy.set_console_listener_addr(form.cleaned_data["listen_on"])
|
||||
with audit_vm(request, instance, f"set console listen address {form.cleaned_data['listen_on']}") as entry:
|
||||
entry.skip = instance.proxy.set_console_listener_addr(form.cleaned_data["listen_on"]) is False
|
||||
if not form.is_valid():
|
||||
messages.error(request, _("Console settings were not saved: %(errors)s") % {"errors": form.errors.as_text()})
|
||||
|
||||
|
|
|
|||
|
|
@ -262,9 +262,10 @@ def resolve(op_id, user, outcome_state, note):
|
|||
Operation.objects.filter(pk=op.pk).update(state=outcome_state, resolution=outcome_state,
|
||||
resolution_note=note, resolved_by=user, resolved_at=timezone.now())
|
||||
Claim.objects.filter(operation=op).delete()
|
||||
# the host, VM and UUID columns of the kind's own entries, so the VM's log shows it
|
||||
# the host, VM and UUID columns of the kind's own entries, so the VM's log shows it;
|
||||
# a kind without entries (a migration) still names its VM by the UUID in its intent
|
||||
entry = _entry(op, outcome_state)
|
||||
host, instance, uuid = entry[:3] if entry is not None else ("-", op.resource_label, "")
|
||||
host, instance, uuid = entry[:3] if entry is not None else ("-", op.resource_label, op.intent.get("uuid", ""))
|
||||
_log(user.username, host, instance, uuid, f"Job {op.pk} resolved as {outcome_state}: {note}",
|
||||
outcome_state == Operation.SUCCEEDED)
|
||||
op.refresh_from_db()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue