Skip to content

Latest commit

 

History

History
331 lines (231 loc) · 11.8 KB

README.md

File metadata and controls

331 lines (231 loc) · 11.8 KB

vbox-api

GitHub license GitHub last commit Code style: black

Python bindings to the VirtualBox SOAP API.

Table of Contents

Description

Provides a Python SOAP client using zeep to the VirtualBox SOAP API, with Pythonic bindings, and models for object-oriented usage. Several methods have been added to models to assist with common operations, and simplify many interface methods.

Examples

Command-line interface:

Demonstration of vbox-api-cli.

Web (HTTP) interface:

Demonstration of vbox-api-http machine.view endpoint.

Components

vbox_api.interface contains all relevant classes to communicate with the VirtualBox API.

vbox_api.models defines classes to use an interface in an object-oriented approach (see below).

vbox_api.cli contains an entry point for an interactive command-line interface and functions to parse arguments.

vbox_api.http includes a Flask application to view and manage virtual machines over HTTP.

vbox_api.constants defines many enumerations, mostly generated from the VirtualBox WSDL XML, with added enumerations for those not currently specified but used internally, such as MachineFrontend. These can be used as a reference for expected values to/from the VirtualBox interface, when type hinting or passing values.

vbox_api.helpers includes a class, WebSocketProxyProcess, to wrap websockify.WebSocketProxy, allowing remote control of a virtual machine over HTTP, accessible from the web interface. vrde_ext_pack must be set to VNC and noVNC must be available.

Models

Models allow properties to be obtained and set in an object-oriented fashion, e.g. machine.name, instead of IMachine_getName(handle). To do this, BaseModel defines both a __getattr__ and a __setattr__ method, which call the relevant interface method for the requested attribute to either get or set, respectively. Additionally, the to_dict and from_dict methods allow multiple properties to be handled at once.

Any valid interface name can be used to create a model, using BaseModel.from_name. The interface is passed via a Context object, along with the handle of the model. All methods of the interface are bound to this model, using functools.partial to implictly pass its handle, then wrapped to return model instances. BaseModel also implements __str__, allowing models to be passed directly to interface methods as a handle.

Models are automatically instantiated from returned results, by obtaining the interface name from the returned handle, using ManagedObjectRef.get_interface_name. Alternatively, a passed value can be matched by string comparison to an existing interface name.

A metaclass is used to ensure that objects with the same handle and class are not recreated; the same object is returned. The instances are stored in a WeakValueDictionary, allowing them to be garbage collected when no longer referenced.

For example:

machine = api.machines[0]
assert machine is Machine(api.ctx, machine.handle)

Installation

After cloning the repository with: git clone https://github.com/Zedeldi/vbox-api.git

Build

  1. Install project: pip install .
  2. Run: vbox-api-cli (CLI) or vbox-api-http (HTTP)

Development

  1. Install dependencies: pip install -r requirements.txt
  2. Run: python -m vbox_api.cli (CLI) or python -m vbox_api.http (HTTP)

Libraries:

PyInstaller

The server application can be bundled with PyInstaller, by adding the required static files and templates for Flask to the bundle. Additionally, vbox_api.http.gui provides a simple wrapper using flaskwebgui, to serve and open the Flask application in a browser window.

pyinstaller \
    --name "vbox-api-gui" \
    --add-data "vbox_api/http/static:vbox_api/http/static" \
    --add-data "vbox_api/http/templates:vbox_api/http/templates" \
    --onefile \
    vbox_api/http/gui.py

PKGBUILD

  1. Build and install the package: makepkg -si
  2. Run: vbox-api-cli (CLI) or vbox-api-http (HTTP)
    • The HTTP interface can also be started using a systemd unit: systemctl start vbox-api-http

Note: if the optional dependency novnc is installed from the AUR, HTTP remote control will be available out of the box.

Docker

Dockerfiles are supplied in docker/, to run both vbox-api-http and vboxwebsrv in a container.

If you already have VirtualBox installed to your machine, you can build and start vbox-api-http in a Docker container easily. The VirtualBox container requires the host kernel modules to be installed for /dev/vboxdrv to be available.

Build:

Build vbox-api image, passing current directory as the build context:

docker build -t "vbox-api" -f docker/api/Dockerfile .

Build VirtualBox image, optionally passing additional build arguments:

docker build -t "virtualbox" -f docker/virtualbox/Dockerfile .
docker build -t "virtualbox" --build-arg USER="user" --build-arg PASS="password" -f docker/virtualbox/Dockerfile .
docker build -t "virtualbox" --build-arg PACMAN_ARGS="--disable-download-timeout" -f docker/virtualbox/Dockerfile .

Run:

Run vbox-api-http in a container interactively, with host network:

docker run -it --rm --network=host "vbox-api"

Run vboxwebsrv in a container interactively, with host network (note: VirtualBox host kernel modules must be installed):

docker run -it --rm --network=host --device /dev/vboxdrv:/dev/vboxdrv -e DISPLAY=unix:0 "virtualbox"

Usage

Ensure that vboxwebsrv is running as the intended user. The virtualbox package also provides a systemd unit for this: systemctl start vboxweb.

In the following examples, api refers to a VBoxAPI (or VirtualBox model) instance.

Machine

Get machine information:

for machine in api.machines:
    print(machine.to_dict())

Wait for machine to start in headless mode:

progress = machine.start(front_end="headless")  # or MachineFrontend.HEADLESS
progress.wait_for_completion(-1)

Write-lock machine and set machine name:

with machine.with_lock(save_settings=True) as locked_machine:
    locked_machine.name = "Machine Name"
    # or
    locked_machine.set_name("Machine Name")
assert machine.name == "Machine Name"

Create machine with default settings for Windows 11:

machine = api.create_machine_with_defaults(
    name="Windows 11",
    os_type_id="Windows11_64",
)

Create machine from Windows 11 ISO and start unattended installation:

machine = api.create_machine_from_iso(
    iso_path="Win11_23H2_EnglishInternational_x64.iso",
    name="Windows 11",
    unattended_options={
        "user": "username",
        "password": "password",
        "install_guest_additions": True,
    },
)
machine.attach_medium(hard_disk)  # See Medium examples
machine.start()

Clone machine:

cloned_machine = machine.clone(f"{machine.name} - Clone")

Interact with guest OS of machine:

with machine.with_lock() as locked_machine:
    guest = locked_machine.session.console.guest
    session = guest.create_session("username", "password", "domain", "session_name")
    # Wait for session.status to be GuestSessionStatus.STARTED
    progress = session.copy_from_guest(r"C:\path\to\copy", [], FileCopyFlag.NONE, "/path/to/destination/")
    process = session.process_create(r"C:\path\to\file.exe", ["argument"], ["var=1"], ProcessCreateFlag.NONE, 0)

Teleport machine to another on the same host, with a password:

# Configure then start target machine
target_machine.teleport_listen(port=6000, password="password")
target_machine.start()

# Start then teleport source machine to target machine
source_machine.start()
source_machine.teleport_to(host="localhost", port=6000, password="password")

Medium

Get medium information:

for medium in api.mediums:  # or specify dvd_images, floppy_images, hard_disks
    print(medium.to_dict())

Create hard-disk medium:

medium = api.create_medium_with_defaults(
    location="/path/to/medium.vdi",
    logical_size=1024 ** 4,  # 1 TiB
    format_="VDI",
)

Testing

vbox-api has been tested successfully on Arch Linux and Windows 10.

Unit tests can be run using pytest, though tests require authentication for the VirtualBox interface: python -m pytest

Contributing

Please contribute by raising an issue or submitting a pull request, whether for code or documentation.

Source code is formatted using black, and type hints should be added where possible.

If there are any questions, please do not hesitate to ask. All contributions are welcome!

Changelog

For VirtualBox v7.1.0 onwards (released 09/09/2024), use v2.0.0 or above of vbox-api. v7.1.0 was a major update, causing some breaking changes with their API, specifically with the introduction of PlatformProperties.

For previous versions of VirtualBox, use v1.5.3 or below.

For more information, see the VirtualBox Changelog.

Credits

Contributors

Resources

Other Projects

  • vboxwebber - VirtualBox SOAP API client for Python
  • phpVirtualBox - web interface to manage and access Virtualbox machines
  • RemoteBox - VirtualBox GUI (GTK3) client

License

vbox-api is licensed under the MIT Licence for everyone to use, modify and share freely.

This project is distributed in the hope that it will be useful, but without any warranty.

The VirtualBox logo is licensed under the GPL-2.0.

Donate

If you found this project useful, please consider donating. Any amount is greatly appreciated! Thank you 😃

PayPal