pysnap.core package¶
Core business logic package for PySnap.
Submodules¶
pysnap.core.access module¶
How PySnap reaches the guest of a VM: serial console or ssh.
Base VMs registered with pysnap protosettings and their clones are known
to have their console on COM1, so they are reached through the serial TCP
server of COM1. Every other VM is reached through ssh: its NAT adapter
forwards a host port on 127.0.0.1 to port 22 of the guest. The automatic
choice can be overridden per VM with pysnap set VM access=com|ssh.
The override and the ssh user are kept in VirtualBox extra data of the VM;
the forwarded port is read from the NAT port-forwarding rule named
SSH_RULE_NAME.
- class pysnap.core.access.AccessInfo(mode, source, serial_port, ssh_port, ssh_user)[source]¶
Bases:
objectDescribe how PySnap reaches the guest of one VM.
- Parameters:
mode (str) –
"com"for the COM1 serial console,"ssh"for ssh.source (str) – Why this mode applies:
"override"(pysnap set),"protosettings"(the VM or its parent is registered) or"default".serial_port (int | None) – TCP port of COM1, if any.
ssh_port (int | None) – Host port forwarded to the guest ssh server, if any.
ssh_user (str) – User for ssh connections.
- mode: str¶
- source: str¶
- serial_port: int | None¶
- ssh_port: int | None¶
- ssh_user: str¶
- pysnap.core.access.resolve_access(info, proto_settings_vms)[source]¶
Return the access mode and connection details of a VM.
- Parameters:
info (VMInfo) – VM information including PySnap metadata.
proto_settings_vms (Collection[str]) – Base VM names registered with protosettings.
- Returns:
Access description.
- Return type:
- pysnap.core.access.validate_access_mode(value)[source]¶
Validate an
access=value.- Parameters:
value (str) –
com,sshorauto.- Returns:
The lower-case value.
- Raises:
PySnapError – For other values.
- Return type:
str
- pysnap.core.access.validate_ssh_user(value)[source]¶
Validate an
ssh-user=value.- Parameters:
value (str) – User name in the guest.
- Returns:
The user name.
- Raises:
PySnapError – For names that are not plain user names.
- Return type:
str
- pysnap.core.access.ssh_forwarding_rule(port)[source]¶
Return the VirtualBox NAT rule that forwards a host port to ssh.
- Parameters:
port (int) – Host port on
SSH_HOST_ADDRESS.- Returns:
Rule in
VBoxManage --natpfNsyntax.- Return type:
str
- pysnap.core.access.parse_ssh_forwarding(rule)[source]¶
Return the host port of a PySnap ssh forwarding rule.
- Parameters:
rule (str) – Rule as printed by
showvminfo --machinereadable,name,protocol,host address,host port,guest address,guest port.- Returns:
Host port, or
Nonefor other rules.- Return type:
int | None
pysnap.core.appliance module¶
Helpers for reading appliance metadata from OVF and OVA files.
- pysnap.core.appliance.read_appliance_vm_names(image_path)[source]¶
Read original VM names declared inside an OVF or OVA appliance.
- Parameters:
image_path (str | Path) – Appliance path.
- Returns:
Declared appliance VM names in descriptor order.
- Raises:
PySnapError – If the descriptor cannot be read or parsed.
- Return type:
tuple[str, …]
pysnap.core.models module¶
Domain models used by PySnap.
- class pysnap.core.models.VMReference(name, uuid)[source]¶
Bases:
objectRepresent a lightweight VirtualBox VM reference.
- Parameters:
name (str)
uuid (str)
- name: str¶
- uuid: str¶
- class pysnap.core.models.SerialPortConfiguration(enabled, mode=None, port=None)[source]¶
Bases:
objectRepresent the raw
UART1configuration of one VM.- Parameters:
enabled (bool)
mode (str | None)
port (int | None)
- enabled: bool¶
- mode: str | None = None¶
- port: int | None = None¶
- class pysnap.core.models.ImportCandidate(vsys_index, vm_name, group, requires_eula_accept=False)[source]¶
Bases:
objectRepresent a VM discovered in an appliance import dry run.
- Parameters:
vsys_index (int)
vm_name (str)
group (str)
requires_eula_accept (bool)
- vsys_index: int¶
- vm_name: str¶
- group: str¶
- requires_eula_accept: bool = False¶
- class pysnap.core.models.VMInfo(name, uuid, groups, serial_port=None, vm_state=None, parent_name=None, managed=False, metadata=<factory>, serial_tcp_ports=(), ssh_port=None)[source]¶
Bases:
objectRepresent the VM information required by the CLI.
- Parameters:
name (str)
uuid (str)
groups (tuple[str, ...])
serial_port (int | None)
vm_state (str | None)
parent_name (str | None)
managed (bool)
metadata (dict[str, str])
serial_tcp_ports (tuple[int, ...])
ssh_port (int | None)
- name: str¶
- uuid: str¶
- groups: tuple[str, ...]¶
- serial_port: int | None = None¶
- vm_state: str | None = None¶
- parent_name: str | None = None¶
- managed: bool = False¶
- metadata: dict[str, str]¶
- serial_tcp_ports: tuple[int, ...] = ()¶
- ssh_port: int | None = None¶
- class pysnap.core.models.VMGroup(name, vm_names)[source]¶
Bases:
objectRepresent a VM group and its members.
- Parameters:
name (str)
vm_names (tuple[str, ...])
- name: str¶
- vm_names: tuple[str, ...]¶
- class pysnap.core.models.IntegrationTestResult(machines, deleted_vm_names, monitor_records=())[source]¶
Bases:
objectRepresent the outcome of an integration test run.
- Parameters:
machines (tuple[VMInfo, ...])
deleted_vm_names (tuple[str, ...])
monitor_records (tuple[VMMonitorRecord, ...])
- deleted_vm_names: tuple[str, ...]¶
- monitor_records: tuple[VMMonitorRecord, ...] = ()¶
- class pysnap.core.models.VMMonitorRecord(name, display_state, serial_port, group, raw_state, access_mode='com', ssh_port=None)[source]¶
Bases:
objectRepresent a compact monitor record for a VM.
- Parameters:
name (str)
display_state (str)
serial_port (int | None)
group (str)
raw_state (str)
access_mode (str)
ssh_port (int | None)
- name: str¶
- display_state: str¶
- serial_port: int | None¶
- group: str¶
- raw_state: str¶
- access_mode: str = 'com'¶
- ssh_port: int | None = None¶
- class pysnap.core.models.ComPortSetting(mode, port=None, path=None, detail=None)[source]¶
Bases:
objectRepresent the configuration of one serial (COM) port.
- Parameters:
mode (str) –
"off","tcpserver","server"or"client"(host pipe), or another raw VirtualBox mode such as"file".port (int | None) – TCP port of a
tcpserverport.path (str | None) – Host pipe path of a
serverorclientport.detail (str | None) – Raw VirtualBox value of other modes.
- mode: str¶
- port: int | None = None¶
- path: str | None = None¶
- detail: str | None = None¶
- class pysnap.core.models.NicSetting(attachment, network=None)[source]¶
Bases:
objectRepresent the attachment of one network adapter.
- Parameters:
attachment (str) –
"none","nat"or"intnet", or another raw VirtualBox attachment such as"bridged".network (str | None) – Internal network name of an
intnetadapter.
- attachment: str¶
- network: str | None = None¶
- class pysnap.core.models.VMHardware(com_ports, nics)[source]¶
Bases:
objectRepresent the serial ports and network adapters of one VM.
- Parameters:
com_ports (tuple[ComPortSetting, ...]) – Settings of every serial port the VM can have (COM1-COM4).
nics (tuple[NicSetting, ...]) – Settings of every network adapter the VM can have; their number depends on the chipset (8 for PIIX3, 36 for ICH9).
- com_ports: tuple[ComPortSetting, ...]¶
- nics: tuple[NicSetting, ...]¶
- class pysnap.core.models.SshKeyResult(vm_name, users, ssh_user, changed_user=False, already_installed=False)[source]¶
Bases:
objectRepresent the outcome of
pysnap ssh-key.- Parameters:
vm_name (str) – VM name.
users (tuple[str, ...]) – Guest users whose login with the PySnap key works.
ssh_user (str) – User that PySnap uses for ssh after the setup.
changed_user (bool) – Whether
ssh_userwas switched to make ssh work.already_installed (bool) – Whether the key worked before anything was done.
- vm_name: str¶
- users: tuple[str, ...]¶
- ssh_user: str¶
- changed_user: bool = False¶
- already_installed: bool = False¶
- class pysnap.core.models.VMSettingsResult(vm_name, vm_state, hardware, warnings=(), access=None)[source]¶
Bases:
objectRepresent the outcome of
pysnap set.- Parameters:
vm_name (str) – VM name.
vm_state (str | None) – Raw VirtualBox state.
hardware (VMHardware) – Serial ports and network adapters after the change.
warnings (tuple[str, ...]) – Notes about removed TCP servers and similar effects.
access (AccessInfo | None) – How PySnap reaches the guest after the change.
- vm_name: str¶
- vm_state: str | None¶
- hardware: VMHardware¶
- warnings: tuple[str, ...] = ()¶
- access: AccessInfo | None = None¶
pysnap.core.service module¶
Application service layer for PySnap.
- pysnap.core.service.normalize_group_name(group)[source]¶
Normalize a VirtualBox group name.
- Parameters:
group (str | None) – Raw group name.
- Returns:
Group name that always starts with
/.- Return type:
str
- class pysnap.core.service.PySnapService(client=None, session_registry=None, serial_probe_factory=None, proto_settings_store=None, ssh_key_store=None)[source]¶
Bases:
objectProvide the main PySnap business operations.
- Parameters:
client (VBoxManageClient | None)
session_registry (SessionRegistry | None)
serial_probe_factory (SerialProbeFactory | None)
proto_settings_store (ProtoSettingsStore | None)
ssh_key_store (SshKeyStore | None)
- SNAPSHOT_NAME = 'pysnap-base'¶
- DEFAULT_SERIAL_TCP_PORT = 1024¶
- DEFAULT_START_TIMEOUT = 30.0¶
- DEFAULT_STOP_TIMEOUT = 60.0¶
- DEFAULT_PAUSE_TIMEOUT = 30.0¶
- DEFAULT_SSH_WAIT_TIMEOUT = 180.0¶
- DEFAULT_INTEGRATION_STOP_TIMEOUT = 180.0¶
- STOPPED_STATES = {'aborted', 'poweroff', 'saved'}¶
- STOPPING_STATES = {'stopping'}¶
- PAUSED_STATES = {'paused'}¶
- ERROR_STATES = {'gurumeditation', 'stuck'}¶
- import_image(image_path, vm_name=None, progress_callback=None)[source]¶
Import an OVA or OVF image into VirtualBox.
- Parameters:
image_path (str) – Path to the OVA or OVF appliance.
vm_name (str | None) – Optional custom name for a single imported VM.
progress_callback (Callable[[int], None] | None) – Optional import progress callback.
- Returns:
Imported VM information objects.
- Raises:
PySnapError – If the file is invalid or import does not create VMs.
- Return type:
list[VMInfo]
- run_integration_test(image_path, name_token=None)[source]¶
Run an end-to-end integration scenario on an appliance.
The scenario imports one appliance VM, creates three linked clones connected in a triangle of internal networks, captures machine details, validates runtime monitoring by attaching to one clone and starting a second clone headlessly, and removes all created VMs one by one.
- Parameters:
image_path (str) – Path to the appliance used for the test.
name_token (str | None) – Optional deterministic suffix for generated VM names.
- Returns:
Integration test result with machine info and deletion order.
- Raises:
PySnapError – If the appliance is invalid or the test fails.
- Return type:
- list_groups()[source]¶
List all VM groups and their members.
- Returns:
Group information sorted by group name.
- Return type:
list[VMGroup]
- list_monitored_vms()[source]¶
List VMs that are running or changing state in a compact form.
- Returns:
Monitor records sorted by VM name.
- Return type:
list[VMMonitorRecord]
- get_session_state_label(vm_name)[source]¶
Return the runtime label of the VM of a
connectsession cheaply.A session asks for the state every second, so this runs one
VBoxManage showvminfoand skips the existence check and the extra data ofget_monitor_state_label().- Parameters:
vm_name (str) – VM name.
- Returns:
User-facing monitor label.
- Return type:
str
- get_monitor_state_label(vm_name)[source]¶
Return the user-facing runtime label for one VM.
- Parameters:
vm_name (str) – VM name.
- Returns:
User-facing monitor label.
- Return type:
str
- prepare_vm_connection(vm_name, timeout=None)[source]¶
Ensure that a VM is ready for an interactive connection (COM1 or ssh).
- Parameters:
vm_name (str) – VM name.
timeout (float | None) – Optional startup timeout in seconds.
- Returns:
Updated VM information.
- Raises:
PySnapError – If the VM cannot be connected.
- Return type:
- stop_runtime_vm(vm_name, timeout=None)[source]¶
Request a graceful stop for one running VM.
- Parameters:
vm_name (str) – VM name.
timeout (float | None) – Optional timeout in seconds.
- Raises:
PySnapError – If the VM is not in a stoppable state.
- Return type:
None
- stop_all_runtime_vms(timeout=None)[source]¶
Stop all currently running VMs that are in a normal running state.
- Parameters:
timeout (float | None) – Optional per-VM timeout in seconds.
- Returns:
Names of VMs that received a stop request and stopped.
- Return type:
list[str]
- pause_runtime_vm(vm_name, timeout=None)[source]¶
Pause one running VM; it stays in memory until it is resumed.
- Parameters:
vm_name (str) – VM name.
timeout (float | None) – Optional timeout in seconds.
- Raises:
PySnapError – If the VM is not running.
- Return type:
None
- resume_runtime_vm(vm_name, timeout=None)[source]¶
Resume one paused VM.
- Parameters:
vm_name (str) – VM name.
timeout (float | None) – Optional timeout in seconds.
- Raises:
PySnapError – If the VM is not paused.
- Return type:
None
- pause_all_runtime_vms(timeout=None)[source]¶
Pause all running VMs.
- Parameters:
timeout (float | None) – Optional per-VM timeout in seconds.
- Returns:
Names of the paused VMs.
- Raises:
PySnapError – If one or more VMs cannot be paused.
- Return type:
list[str]
- resume_all_runtime_vms(timeout=None)[source]¶
Resume all paused VMs.
- Parameters:
timeout (float | None) – Optional per-VM timeout in seconds.
- Returns:
Names of the resumed VMs.
- Raises:
PySnapError – If one or more VMs cannot be resumed.
- Return type:
list[str]
- show_vm(vm_name)[source]¶
Return details for a single VM.
- Parameters:
vm_name (str) – Name of the VM to inspect.
- Returns:
Detailed VM information.
- Raises:
VMNotFoundError – If the VM is absent.
- Return type:
- plug_vm(vm_name)[source]¶
Configure one VM for PySnap connections.
A VM reached through COM1 gets
UART1as a TCP server: if it already is one, the VM is returned unchanged; otherwise PySnap assigns a free TCP port and enables the sameUART1tcpserver mode used by the imported protocol images. A VM reached through ssh gets a NAT rule that forwards a free host port to port 22 of the guest.- Parameters:
vm_name (str) – VM name to configure.
- Returns:
Updated VM information.
- Raises:
PySnapError – If the VM cannot be configured safely.
- Return type:
- set_vm_settings(vm_name, options)[source]¶
Change the serial ports and network adapters of a stopped VM.
Without options the current settings are returned unchanged. All options are validated before one
modifyvmcall applies them. For proto-settings clones the DMI system SKU is rebuilt from the new COM1 port and the internal networks of NIC2-NIC4.- Parameters:
vm_name (str) – VM name.
options (Sequence[str]) –
comN=VALUEandnicN=VALUEoptions.
- Returns:
Settings after the change and warnings.
- Raises:
PySnapError – For invalid options, a VM that is not stopped or TCP ports in use.
- Return type:
- ssh_target(vm_name, user=None)[source]¶
Return where and as whom to reach a running VM through ssh.
- Parameters:
vm_name (str) – VM name.
user (str | None) – Guest user; the ssh user of the VM by default.
- Returns:
Connection target.
- Raises:
PySnapError – Without a forwarded ssh port or a running VM.
- Return type:
- prepare_ssh_terminal(vm_name, *, timeout=None, notify=None, installer=None, poll_interval=2.0)[source]¶
Wait for the guest ssh server and make sure the PySnap key works.
A freshly started guest needs time to boot, so a missing ssh server is retried until
timeout. A refused key starts the interactive key setup ofsetup_ssh_key()in the current terminal.- Parameters:
vm_name (str) – Name of a running VM reached through ssh.
timeout (float | None) – Seconds to wait for the ssh server.
notify (Callable[[str], None] | None) – Callback for progress messages.
installer – Interactive installer, for tests.
poll_interval (float) – Seconds between attempts.
- Returns:
Connection target for the ssh user of the VM.
- Raises:
PySnapError – When no ssh server answers in time or the key cannot be installed.
- Return type:
- setup_ssh_key(vm_name, user=None, *, console=False, installer=None, console_wait=10.0)[source]¶
Install the PySnap key in the guest so that ssh needs no password.
By default ssh logs in with the password of
user(the ssh user of the VM) in the current terminal, adds the key for that user and, when the root password is given in the guest, for root as well. Withconsolethe key line is typed on the VM screen instead, for a shell that is logged in there. When the ssh user of the VM cannot use the key butusercan, the ssh user is switched touser.- Parameters:
vm_name (str) – VM name.
user (str | None) – Guest user for the password login.
console (bool) – Type the command on the VM screen.
installer – Interactive installer, for tests.
console_wait (float) – Seconds to wait for a typed command to work.
- Returns:
Users that can log in with the key afterwards.
- Raises:
PySnapError – When no ssh server answers or nothing worked.
- Return type:
- get_vm_access(vm_name)[source]¶
Return how PySnap reaches the guest of a VM.
- Parameters:
vm_name (str) – VM name.
- Returns:
Access mode, its source and the connection details.
- Return type:
- clone_vm(base_vm, clone_vm, serial_port=None, networks=())[source]¶
Create a linked clone and configure it.
- Parameters:
base_vm (str) – Name of the source VM.
clone_vm (str) – Name of the linked clone to create.
serial_port (int | None) – Optional TCP port assigned to
UART1.networks (tuple[str, ...]) – Up to three internal network names.
- Returns:
Detailed information about the created clone.
- Raises:
PySnapError – If invalid parameters are supplied.
- Return type:
- register_proto_settings_vm(vm_name)[source]¶
Persist one base VM name in the proto-settings store.
- Parameters:
vm_name (str) – Base VM name to register.
- Returns:
Updated configured VM names.
- Raises:
VMNotFoundError – If the VM does not exist.
- Return type:
tuple[str, …]
- erase_vm(vm_name)[source]¶
Erase one VM when no dependent clones exist.
- Parameters:
vm_name (str) – Name of the VM to remove.
- Raises:
VMDependencyError – If dependent clones still exist.
- Return type:
None
- erase_group(group_name)[source]¶
Erase all VMs from a single group.
- Parameters:
group_name (str) – Group to erase.
- Returns:
Names of removed VMs.
- Raises:
PySnapError – If the group is empty or contains blocked base VMs.
- Return type:
list[str]
- erase_all()[source]¶
Erase all registered VirtualBox VMs.
- Returns:
Names of removed VMs.
- Return type:
list[str]
- erase_clones(group_name=None)[source]¶
Erase all managed clone VMs, optionally limited to one group.
Clones are recognized through the
pysnap/kindandpysnap/parentmetadata written byclone_vm(), so no separate clone registry has to be kept in sync with VirtualBox.- Parameters:
group_name (str | None) – Optional group that limits the deleted clones.
- Returns:
Names of removed clone VMs.
- Raises:
PySnapError – If the group is empty or clones outside the selection still depend on the selected clones.
- Return type:
list[str]
- is_clone_vm(vm_name)[source]¶
Return whether one VM was created as a managed linked clone.
- Parameters:
vm_name (str) – VM name to check.
- Returns:
Truewhen the VM is a managed clone.- Raises:
VMNotFoundError – If the VM does not exist.
- Return type:
bool
- full_clean(paths)[source]¶
Delete VirtualBox data directories from the host file system.
- Parameters:
paths (Sequence[Path]) – Directories to remove recursively.
- Returns:
Paths of directories that were removed.
- Raises:
PySnapError – If one or more directories cannot be removed.
- Return type:
list[str]
pysnap.core.settings module¶
Parse pysnap set options for serial ports and network adapters.
Each option is KEY=VALUE:
comN:autoor a TCP port number for a TCP server,server:NAMEorclient:NAMEfor a host pipe between VMs, oroff;nicN: an internal network name,natoroff;access:com,sshorauto(the choice by protosettings);ssh-user: the guest user for ssh connections.
N is any port or adapter number; whether the VM has it (VirtualBox
offers COM1-COM4 and, depending on the chipset, NIC1-NIC8 or NIC1-NIC36) is
checked against the VM.
A host pipe is given by a short name; host_pipe_path() turns it into
the path format of the host system, so two VMs that use the same name are
connected on any platform.
- class pysnap.core.settings.ComPortRequest(mode, port=None, pipe_name=None)[source]¶
Bases:
objectRepresent a requested serial port change.
- Parameters:
mode (str) –
"off","tcpserver","server"or"client".port (int | None) – Requested TCP port;
Nonewithtcpservermeansauto.pipe_name (str | None) – Short host pipe name of
serverandclient.
- mode: str¶
- port: int | None = None¶
- pipe_name: str | None = None¶
- class pysnap.core.settings.SetRequest(com_ports, nics, access=None, ssh_user=None)[source]¶
Bases:
objectRepresent the changes requested by
pysnap set.- Parameters:
com_ports (dict[int, ComPortRequest]) – Port numbers mapped to the requested change.
nics (dict[int, NicSetting]) – Adapter numbers mapped to the requested setting.
access (str | None) –
"com","ssh"or"auto", if requested.ssh_user (str | None) – Guest user for ssh, if requested.
- com_ports: dict[int, ComPortRequest]¶
- nics: dict[int, NicSetting]¶
- access: str | None = None¶
- ssh_user: str | None = None¶
- pysnap.core.settings.parse_set_options(options)[source]¶
Parse
KEY=VALUEoptions.- Parameters:
options (Sequence[str]) – Command line options.
- Returns:
Requested changes.
- Raises:
PySnapError – For unknown keys, repeated keys and invalid values.
- Return type:
- pysnap.core.settings.host_pipe_path(name, *, windows=None)[source]¶
Return the host pipe path for a short pipe name.
- Parameters:
name (str) – Short pipe name.
windows (bool | None) – Override the host system check, for tests.
- Returns:
\\.\pipe\pysnap-NAMEon Windows, otherwise a socket pathpysnap-NAMEin the temporary directory.- Return type:
str
- pysnap.core.settings.host_pipe_name(path)[source]¶
Return the short name of a pipe path created by PySnap.
- Parameters:
path (str) – Host pipe path.
- Returns:
Short name, or
Nonefor other paths.- Return type:
str | None
- pysnap.core.settings.com_setting_from_request(request, port)[source]¶
Return the resulting port setting of a request.
- Parameters:
request (ComPortRequest) – Requested change.
port (int | None) – Resolved TCP port of a
tcpserverrequest.
- Returns:
Port setting.
- Return type: