FICCDocumentation
nightly prerelease / Version 0.3.0.dev1Project website
Reference library
VM providers
On this page
  1. System prerequisites
  2. Inventory and power actions
  3. Console contract
  4. Host integration interface

Libvirt VM module#

The org.ficc.libvirt runtime package provides inventory, start, graceful shutdown and a request for a host-owned VNC viewer. Install and enable the package, grant its permissions for selected enrolled systems, then add it to a workspace. The host must also configure one libvirt profile for each selected system. Inventory requires vm:read. The package declares vm:power and vm:console as optional permissions, so an inventory-only panel does not require either grant. Their actions remain unavailable until explicitly granted for the selected system.

System prerequisites#

The enrolled Linux SSH account needs the current FICC node helper, the distribution python3-libvirt package and permission to access the selected local libvirt connection. A profile chooses only system (qemu:///system) or session (qemu:///session). These are separate inventories. The helper does not run sudo, install packages, start a daemon, accept an arbitrary URI or execute a shell command from a module. Configure the account's libvirt access outside the module first.

Read/write libvirt access can confer broad administrative authority on that account. Durable receipts require account-owned, non-symlink ancestors under .local/state; group/world-writable ancestors are refused. The final receipt directory is private with mode 0700 and regular receipt files have mode 0600. FICC reports this prerequisite without changing existing directory permissions automatically. See the official connection URI, Python binding and authentication documentation.

The host checks the current caller scope, exact installed package grant, workspace instance authority, enrolled SSH destination and profile revision before dispatch. vm:read, vm:power and vm:console are separate system grants and caller scopes. Power previews also require read authority. Profile setup requires nodes:write. Modules receive inventory data and opaque confirmation/viewer references, without SSH keys, paths, libvirt XML, console addresses or credentials.

Inventory and power actions#

A VM resource ID consists of its profile ID and libvirt domain UUID. A VM name is display text, never an execution identifier. The inventory is capped at 4096 VMs per connection. A page contains at most 64 VMs. The supplied module divides its 128-row table limit across one to 64 systems.

The result includes the total, next offset, truncation flag and an inventory digest. Inventory is a live observation: if the digest changes between pages, refresh from offset zero. Each request has a finite deadline, so a large or slow batch can report a partial refusal or timeout.

Select VMs and request a start or graceful-shutdown preview. The host displays the exact VM names, system IDs, states and action before confirmation. A preview expires after 120 seconds. Confirmation freezes UUIDs, definition digests, observed states, profile revisions, package authority and the caller.

The node rechecks each VM before applying the selected fixed libvirt API. A state or definition change refuses that target. Batches are not transactions; each target has its own outcome.

The controller saves an operation before dispatch, and the node saves and syncs an intent receipt before each provider call. An idempotency key never repeats a provider call. A transport loss produces unknown; reading the durable receipt can recover a provider acknowledgement. Observing a desired VM state alone does not turn an unknown action into success.

An acknowledged action becomes observed when its requested active/off state is seen. This records observation, not proof that this action caused the state. Graceful shutdown has no forced-power fallback.

The host can close an accepted or unknown outcome as resolved after explicit operator inspection and confirmation. Accepted outcomes require a fresh state observation. This does not establish success or change the original node receipt. For example, a guest can ignore a shutdown request before its power handler starts. Closing that record permits a new confirmed action; it does not replay the request.

Unfinished operations block new power actions on the same VM and backup. Receipt history is bounded to 1024 operations on both controller and node. No automatic deletion or replay occurs after restart. There is no snapshot, force-off, reset, migration, storage, network or guest-command primitive in this initial libvirt adapter.

The host can explicitly remove an operation receipt after every target is observed, refused or resolved. Removal requires current read and power grants. It sends the original frozen intent and exact terminal outcomes to each enrolled node, without calling a VM lifecycle API. The node saves the terminal proof before removing its receipt.

The controller records each acknowledgement durably and removes its history row only after every node acknowledges. A lost acknowledgement leaves removal pending; retrying removal does not repeat a VM action. Pending removal blocks backup and restore. Receipt removal does not delete a VM.

Remove every retained receipt before changing a profile's connection or removing its profile, workspace panel or package. Security disable and grant revocation remain available. Re-enable the same profile and restore its required grants to resume receipt removal. Revision-only re-enablement can recover existing history; new lifecycle requests still require a fresh confirmation. Profile removal requires nodes:write and vm:read caller scopes. Committed previews are consumed, so removing their history does not allow the original confirmation to dispatch again.

Console contract#

The first transport is VNC. The node finds a VNC graphics device in the selected domain and calls openGraphicsFD(index, 0) on a local read/write libvirt connection. The returned descriptor is bound to that domain's graphics backend. It avoids a TCP-port lookup/rebind race and does not bypass VNC authentication. The host viewer must handle or refuse the negotiated RFB authentication without exposing secrets to the module. Password credential entry is not supplied by this package.

See the official domain graphics APIs and graphics configuration. SPICE, VMRC and RDP are different protocols and are not represented as VNC. This descriptor reports audio: false; it does not imply VM audio support.

Only a host-controlled viewer reference reaches the module. A fresh attach checks the caller, package, instance, profile and domain again. The fixed SSH stream helper opens no listening socket and emits a bounded ready header before raw RFB data. The host stream supervisor must continue checking authority, stop its SSH process group on revoke/disconnect and enforce its viewer session limits. Console acquisition has a six-second kernel deadline and the node relay has a one-hour maximum lifetime, with at most 64 KiB queued in either direction. The common host viewer owns fullscreen, focus escape, clipboard/file restrictions and reconnect behavior.

Host integration interface#

VMs(service) uses the service's store, SSH transport, authorization and module registry. The host supplies a synchronous check() closure for current caller, package revision and persisted workspace-instance authority. Keep that closure active for the entire request and console lifetime.

Method Contract
set_profile(actor, node_id, connection, enabled=True) Owner setup; returns the saved profile.
remove_profile(actor, node_id) Async host removal after all referenced receipts are removed.
profiles(actor) Returns profiles visible under nodes/read and VM/read scopes.
broker(actor, call, instance_id) List, status, preview or operation reads; no commit, resolve or console address.
preview_for_confirmation(actor, preview_id, check) Revalidates the retained preview for the host confirmation surface.
commit(actor, preview_id, key, check) Async host-confirmed lifecycle request; returns public per-VM outcomes.
operation(actor, operation_id, check) Async receipt/status reconciliation without replay.
resolve(actor, operation_id, vm_ids, check) Async explicit host resolution of accepted or unknown targets.
forget(actor, operation_id, check) Async host-confirmed terminal receipt removal; returns {removed:true}.
console(actor, digest, instance_id, node_id, vm_id, check) Async private host descriptor; exchange it for an opaque viewer reference.
console_command(descriptor, check) Async (ssh_argv, header_bytes) for the host stream supervisor.

The console helper replies with {"version":1,"ready":true} followed by a newline and the RFB byte stream. A nonzero exit or missing ready header is a failed attach. The host must never treat descriptor fields supplied by a module as trusted input.

Broker parameters are {offset?,limit?} for vm.libvirt.list, {vm_ids} for vm.libvirt.status, {action,vm_ids} for vm.libvirt.preview, and {operation_id} for vm.libvirt.operation. Invocation targets are enrolled node IDs; selected VM IDs must belong to those exact current profiles. The controller handles vm.libvirt.console with exactly one selected VM and returns only viewer_ref. Unknown fields are rejected. Destructive confirmation is not a module boolean.

Preview data is {preview_id,expires_at,action,vms}; each VM has node_id, vm_id, name and state. Only the first target carries the complete VM array; later targets carry empty arrays. Public operations have id, action, instance_id, timestamps, cleanup and targets containing node_id, vm_id, state, optional error, observed_state and observed_at. Only the first broker target carries the complete operation, with null for later targets. This keeps batch responses bounded. cleanup is null before removal, or {acknowledged,total} while removal is pending.

module_vm_store.initialize(db) creates the two tables listed in its TABLES constant. validate_records(profile_rows, operation_rows, node_ids) checks exact column identities, bounded JSON records, intent digests, retained node references and quiescence. Terminal target states are refused, observed, resolved. queued, dispatching, accepted, unknown and any pending cleanup block backup and restore.

Restore must disable every profile and increment its revision; module restore separately disables packages and removes grants. No restored operation is replayed. Records.retained(node_id) includes profiles and operation history for node-forget checks. The host owns schema migration, backup integration and route composition.

FICC / DocumentationBack to top

Search documentation

Press Escape to close

Loading search...

    Reading appearance

    Choose colours, surfaces and text independently. These settings are saved for this documentation site in this browser.

    Flat surfaces remove decorative materials. Typography is a separate choice. Increased contrast uses the Contrast palette. System forced colours always take precedence.