Skip to main content

pyvergeos

Python SDK for the VergeOS REST API.

PyPI version Python 3.9+ License Documentation

pyvergeos gives you a Pythonic way to drive VergeOS. It wraps the REST API in a typed, discoverable SDK so you can write automation and tooling without hand rolling HTTP calls and JSON payloads.

Read the full documentation

Installation

pip install pyvergeos

# Or with uv
uv add pyvergeos

Quick start

from pyvergeos import VergeClient

client = VergeClient(
    host="192.168.1.100",
    username="admin",
    password="secret",
    verify_ssl=False,  # For self signed certificates
)

# List VMs
for vm in client.vms.list():
    print(f"{vm.name}: {vm.ram}MB RAM, {vm.cpu_cores} cores")

# Fetch one, then act on it
vm = client.vms.get(name="web-server")
vm.power_on()

# Create a VM
new_vm = client.vms.create(
    name="test-vm",
    ram=2048,
    cpu_cores=2,
    os_family="linux",
)

client.disconnect()

Connecting

Username and password

client = VergeClient(
    host="192.168.1.100",
    username="admin",
    password="secret",
)

API token

client = VergeClient(
    host="192.168.1.100",
    token="your-api-token",
)

Context manager

Preferred, since it always closes the session for you.

with VergeClient(host="192.168.1.100", token="api-token") as client:
    running = client.vms.list_running()

Environment variables

export VERGE_HOST=192.168.1.100
export VERGE_USERNAME=admin
export VERGE_PASSWORD=secret

# Or authenticate with a token instead of a username and password
export VERGE_TOKEN=your-api-token

# Optional
export VERGE_VERIFY_SSL=true
export VERGE_TIMEOUT=30
export VERGE_RETRY_TOTAL=3
export VERGE_RETRY_BACKOFF=1
client = VergeClient.from_env()

Bring your own session

Hand the client an existing requests.Session when you need to share connection pooling, proxy settings, or custom TLS material with the rest of your application. pyvergeos will not mount its own adapter or change the session's TLS verification, and it leaves the session open on disconnect.

import requests

session = requests.Session()
session.proxies = {"https": "http://proxy.internal:3128"}

with VergeClient(host="192.168.1.100", token="api-token", session=session) as client:
    vms = client.vms.list()

Do not share one session across several active clients. Pass close_session=True if you want pyvergeos to close it for you anyway.

Finding things

Every manager exposes the same three ways to narrow a query.

# Keyword shorthand, including wildcards
vms = client.vms.list(os_family="linux", name="web-*")

# A filter string
vms = client.vms.list(filter="os_family eq 'linux' and ram gt 2048")

# The filter builder, when you are assembling a query programmatically
from pyvergeos import Filter

query = Filter().eq("os_family", "linux").and_().gt("ram", 2048)
vms = client.vms.list(filter=str(query))

A few helpers cover state the API cannot filter on directly, so reach for those instead of writing the filter yourself.

client.vms.list_running()
client.vms.list_stopped()
client.networks.list_external()

Large tables page automatically with iter_all(), which yields objects instead of building one giant list.

for vm in client.vms.iter_all(page_size=100):
    print(vm.name)

A note on get(name=...)

Names are not unique in every VergeOS table. When you look something up by name and more than one row matches, get() returns the first match rather than raising. If a name might be ambiguous in your environment, use list() and decide for yourself, or look the object up by $key.

Field projections

Managers request a curated set of fields by default, which keeps responses small. Narrow that set with fields when you want less, or ask for "all" when you want everything.

names = client.vms.list(fields=["$key", "name"])
everything = client.vms.get(name="web-server", fields="all")

One behavior is worth knowing about. If you narrow the projection and then read an accessor whose backing field you left out, the SDK raises instead of making up an answer.

from pyvergeos import FieldNotProjectedError

vm = client.vms.get(name="web-server", fields=["$key", "name"])

vm.name    # "web-server"
vm.status  # raises FieldNotProjectedError

That is deliberate. Guessing here once reported a running VM as stopped, and that is exactly the check people put in front of a destructive operation. To fix it, re-fetch with the manager's default fields or add the field you need to the fields argument.

Virtual machines

vm = client.vms.get(name="web-server")

# Power
vm.power_on()
vm.power_off()
vm.reset()
vm.guest_reboot()
vm.guest_shutdown()

# Placement
vm.migrate()
vm.hibernate()

# Clone
clone = vm.clone(name="web-server-clone")

# Drives and NICs
vm.drives.create(name="data", size_gb=50)
vm.nics.create(network=network.key)

# Hot plug into a running VM, which needs allow_hotplug enabled
vm.hotplug_drive(name="scratch", size=100 * 1024**3)
vm.hotplug_nic(name="nic2", network=network.key)

Watch the units. drives.create() takes size_gb in gigabytes, while the hot plug action takes size in bytes.

You can hand a VM its cloud-init config at create time.

vm = client.vms.create(
    name="web-server",
    ram=4096,
    cpu_cores=2,
    cloud_init="#cloud-config\npackages:\n  - nginx",
)

Networks

network = client.networks.create(
    name="app-network",
    network_address="10.10.1.0/24",
    ip_address="10.10.1.1",
    dhcp_enabled=True,
)

network.power_on()

# Firewall rules. Ports are strings, so "22", "80,443" and "1024-65535" all work.
network.rules.create(
    name="Allow SSH",
    direction="incoming",
    action="accept",
    protocol="tcp",
    destination_ports="22",
)

# Rule and DNS changes need to be applied before they take effect
network.apply_rules()
network.apply_dns()

Networks also carry DNS zones, static hosts, aliases, routing, IPSec, WireGuard, and a proxy, each on its own manager under the network object.

Heads up: the Core and DMZ networks are reserved for VergeOS. Create your own network for workloads.

Storage and NAS

# vSAN tiers, which are numbered rather than named
for tier in client.storage_tiers.list():
    print(f"Tier {tier.tier}: {tier.used_percent:.1f}% of {tier.capacity_gb:.0f}GB used")

# NAS volumes and shares
volume = client.nas_volumes.create(name="share-data", service="nas1", size_gb=500)

client.cifs_shares.create(name="data", volume=volume.key, browseable=True)
client.nfs_shares.create(name="data", volume=volume.key)

Snapshots

VM snapshots are scoped to the VM.

vm.snapshots.create(name="before-upgrade", retention=86400, quiesce=True)

for snap in vm.snapshots.list():
    print(snap.name, snap.expires_at)

System wide cloud snapshots live on the client. Snapshot creation is not backed by a task, so pass wait=True when you need the call to block until the snapshot settles.

snapshot = client.cloud_snapshots.create(
    name="nightly",
    wait=True,
    wait_timeout=600,
)
print(snapshot.status)

You can also scope a cloud snapshot to a set of tags, which captures only the VMs carrying them.

client.cloud_snapshots.create(name="db-only", include_tags="database", wait=True)

Tenants

tenant = client.tenants.create(name="customer-a", password="initial-password")
tenant.power_on()

# Give the tenant a UI address on the external network
tenant.set_ui_ip("192.168.1.150")

# Resources
tenant.nodes.list()
tenant.network_blocks.list()
tenant.snapshots.list()

Scheduled tasks

client.tasks is the VergeOS task scheduler. Use it to run and wait on scheduled work.

task = client.tasks.get(name="Nightly backup")

task.execute()
task.wait(timeout=300)

Most VergeOS operations complete on the API call itself and do not create a task row, so reach for a manager's own wait argument, such as cloud_snapshots.create(wait=True), rather than expecting a task to poll.

What else is in here

The client exposes more than eighty managers. The ones above are the common starting points. Beyond them you will find:

  • Compute and infrastructure: nodes, clusters, cluster_status, physical_drives, machine_drive_stats, vgpu_profiles
  • Sites and replication: sites, site_syncs, site_syncs_incoming, site_sync_schedules, volume_syncs
  • Provisioning: catalogs, catalog_repositories, vm_recipes, tenant_recipes, vm_imports, volume_vm_exports, cloudinit_files, files
  • Identity and access: users, groups, permissions, api_keys, auth_sources, oidc_applications
  • Operations: update_settings, update_sources, update_packages, task_schedules, alarms, logs, billing, system_diagnostics, vsan_queries, certificates, tags, snapshot_profiles

Full reference for all of them is in the API documentation.

Error handling

from pyvergeos import (
    AuthenticationError,
    FieldNotProjectedError,
    NotFoundError,
    TaskTimeoutError,
    ValidationError,
    VergeTimeoutError,
)

try:
    vm = client.vms.get(name="nonexistent")
except NotFoundError:
    print("VM not found")

try:
    task.wait(timeout=60)
except TaskTimeoutError as e:
    print(f"Task {e.task_id} timed out")

Everything the SDK raises inherits from VergeError, so catch that if you just want one handler. APIError covers the HTTP failures underneath AuthenticationError, NotFoundError, ValidationError, and ConflictError.

Retries and timeouts

The client retries transient failures automatically, which by default means 429, 500, 502, 503, and 504, three times, with exponential backoff.

from http import HTTPStatus

client = VergeClient(
    host="192.168.1.100",
    username="admin",
    password="secret",
    timeout=30,                 # Per request timeout in seconds (default: 30)
    retry_total=5,              # Retry attempts (default: 3)
    retry_backoff_factor=2.0,   # Backoff factor (default: 1)
    retry_status_codes=frozenset({
        HTTPStatus.TOO_MANY_REQUESTS,
        HTTPStatus.SERVICE_UNAVAILABLE,
    }),
)

Set retry_total=0 to turn retries off entirely.

Requirements

  • Python 3.9 or newer
  • VergeOS 26.0 or newer

Contributing

Contributions are welcome. Start with the contributing guide for the development setup, test commands, and coding standards.

All contributors must agree to the Contributor License Agreement. Submitting a pull request counts as accepting it.

License

Apache License 2.0. See LICENSE for details.

Resources

Metadata

Release files for pyvergeos 1.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyvergeos 1.6.1
File Size Uploaded
pyvergeos-1.6.1.tar.gz 958.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyvergeos 1.6.1
File Interpreter ABI Platform
pyvergeos-1.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 1.4 MB

Release files / pyvergeos-1.6.1.tar.gz

Download URL pyvergeos-1.6.1.tar.gz
Size 958.0 kB
Tags Source
SHA-256 checksum
How to use checksums
da31a8f3fcd7b33e7b93dc41b7e1f8345aa568279bba69e4e6d2e338b1cc5df2
BLAKE2b-256 checksum
How to use checksums
da7349489afba60f0ea08883d18f9285b6b5a01a830bdc1317b4afc059e460c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release files / pyvergeos-1.6.1-py3-none-any.whl

Download URL pyvergeos-1.6.1-py3-none-any.whl
Size 474.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
95f7d93889293ac143fb0b56bb9924cffea2701239da3e5953cda7ecea63b001
BLAKE2b-256 checksum
How to use checksums
0409bc8346dab39b1b1c6d2030635465c29374d5ca78ee2b358f200a63896082
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release history Release notifications | RSS feed

1.7.1

2 release files

This release

1.6.1 This release

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page