1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 19:56:48 +00:00

feat(logs): every VM operation writes an audit row the VM's Logs tab finds by UUID

Operations on a VM now write their rows the way the admin audit does: one
row per operation, done or failed with a safe reason, with the user, IP and
host. Each row names the VM ("VM web-1: delete snapshot snap1") and carries
its UUID in the new Logs.instance_uuid column.

- audit_vm and failed_vm wrap audit() and failed() for a VM. A failure the
  view turns into a message is caught outside the block, so its failed row
  is written; busy claims, permission and quota refusals and invalid input
  write nothing. No password, key or XML goes into a row.
- All VM page operations move from addlogmsg to audit_vm, and addlogmsg
  goes. QoS changes and defining a VM from XML are logged now; a gstfsd
  error reply (root password, SSH key) is a failed row, not a done one.
- Partial results are rows of their own: the VM delete, then each disk
  delete; the disk detach, then the volume delete; the migration, then a
  failed autostart restore, NVRAM removal or record on the target.
- Migration rows use the compute name as the host column, as every other
  row does.
- VM job rows (create, clone, snapshots) and their resolutions carry the
  VM's UUID; snapshot job intents now record it. The owner rows of the VM
  page and the accounts pages, and the ownership system rows, carry it too.
- The Logs tab loads vm_logs/<pk>/ and shows the rows with the VM's UUID,
  so a rename keeps the history, two VMs with one name are told apart and
  a VM on two computes is one VM. It gains a Result column. Rows from
  before this change have no UUID and stay on the Logs page only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
catborise 2026-10-24 14:05:11 +03:00
parent 49cf16ecbe
commit c1d36053d6
24 changed files with 639 additions and 524 deletions

View file

@ -106,9 +106,9 @@ class Kind:
the kind decides whether the job is idle and ends it if so."""
def log_entry(self, op, state):
"""(host, instance, message) of the Logs row written with each end of
the job (in the same transaction); its host and instance also go on
the row of a resolution. None: no row."""
"""(host, instance, instance UUID, message) of the Logs row written
with each end of the job (in the same transaction); its host, instance
and UUID also go on the row of a resolution. None: no row."""
return None
@ -219,8 +219,8 @@ def _entry(op, state):
return None
def _log(user, host, instance, message, success):
write(str(user), str(host), str(instance), utils.safe_text(message), success)
def _log(user, host, instance, uuid, message, success):
write(str(user), str(host), str(instance), utils.safe_text(message), success, uuid=str(uuid))
def finish(op, outcome, *, worker=None):
@ -262,10 +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 and VM 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
entry = _entry(op, outcome_state)
host, instance = entry[:2] if entry is not None else ("-", op.resource_label)
_log(user.username, host, instance, f"Job {op.pk} resolved as {outcome_state}: {note}",
host, instance, uuid = entry[:3] if entry is not None else ("-", op.resource_label, "")
_log(user.username, host, instance, uuid, f"Job {op.pk} resolved as {outcome_state}: {note}",
outcome_state == Operation.SUCCEEDED)
op.refresh_from_db()
return op

View file

@ -68,7 +68,7 @@ class NoopKind(Kind):
return Outcome(Operation.SUCCEEDED, result={"recovered": True})
def log_entry(self, op, state):
return ("c", "vm", f"No-op {state}")
return ("c", "vm", op.params["uuid"], f"No-op {state}")
@register