PyInfra OrbStack Connector
A PyInfra connector for managing OrbStack VMs and containers with native integration.
Overview
The PyInfra OrbStack Connector provides seamless integration between PyInfra and OrbStack, allowing you to manage VMs and containers using PyInfra's declarative infrastructure automation framework.
Features
- Native PyInfra Integration: Use the
@orbstackconnector for seamless VM management - VM Lifecycle Management: Create, start, stop, restart, clone, rename, and delete VMs
- VM Export/Import: Backup and restore VMs with export/import operations
- Command Execution: Run commands inside VMs with proper user and working directory support
- File Transfer: Upload and download files to/from VMs
- Information Retrieval: Get VM status, IP addresses, and network information
- SSH Configuration: Get SSH connection details and connection strings
- Cross-VM Communication: Test connectivity between VMs
Installation
Prerequisites
- Python 3.9 or higher
- PyInfra 2.0.0 or higher
- OrbStack installed and configured
- uv (recommended) or pip for package management
Install the Connector
# Using uv (recommended)
uv add pyinfra-orbstack
# Using pip
pip install pyinfra-orbstack
Development Installation
git clone https://github.com/elazar/pyinfra-orbstack.git
cd pyinfra-orbstack
# Using uv (recommended)
uv sync --dev
# Using pip
pip install -e ".[dev]"
Quick Start
Basic Usage
# inventory.py
from pyinfra import inventory
# Use @orbstack connector to automatically discover VMs
inventory.add_group("@orbstack", {
"orbstack_vm": True,
})
# deploy.py
from pyinfra import host
from pyinfra.operations import server
from pyinfra_orbstack.operations.vm import vm_info, vm_status
# Operations will automatically use the connector
if host.data.orbstack_vm:
# Get VM information
vm_data = vm_info()
status = vm_status()
print(f"VM Status: {status}")
print(f"VM IP: {vm_data.get('ip4', 'unknown')}")
# Install packages
server.packages(
name="Install nginx",
packages=["nginx"],
)
# Start services
server.service(
name="Start nginx",
service="nginx",
running=True,
)
Manual VM Configuration
# inventory.py
inventory.add_host("@orbstack/my-vm", {
"vm_name": "my-vm",
"vm_image": "ubuntu:22.04",
"vm_arch": "arm64",
})
Operations
VM Lifecycle Operations
from pyinfra_orbstack.operations.vm import (
vm_create, vm_delete, vm_start, vm_stop, vm_restart,
vm_clone, vm_export, vm_import, vm_rename
)
# Create a new VM
vm_create(
name="test-vm",
image="ubuntu:22.04",
arch="arm64",
user="ubuntu",
)
# Start a VM
vm_start("test-vm")
# Clone a VM
vm_clone(
source_name="test-vm",
new_name="test-vm-clone",
)
# Export a VM
vm_export(
name="test-vm",
output_path="/tmp/test-vm-backup.tar.zst",
)
# Import a VM
vm_import(
input_path="/tmp/test-vm-backup.tar.zst",
name="test-vm-restored",
)
# Rename a VM
vm_rename(
old_name="test-vm",
new_name="production-vm",
)
# Stop a VM
vm_stop("test-vm", force=True)
# Restart a VM
vm_restart("test-vm")
# Delete a VM
vm_delete("test-vm", force=True)
VM Information Operations
from pyinfra_orbstack.operations.vm import (
vm_info, vm_list, vm_status, vm_ip, vm_network_info
)
# Get detailed VM information
vm_data = vm_info()
print(f"VM Status: {vm_data.get('record', {}).get('state')}")
# List all VMs
all_vms = vm_list()
for vm in all_vms:
print(f"VM: {vm['name']}, Status: {vm['state']}")
# Get VM status
status = vm_status()
print(f"Current VM Status: {status}")
# Get VM IP address
ip = vm_ip()
print(f"VM IP: {ip}")
# Get network information
network_info = vm_network_info()
print(f"IPv4: {network_info['ip4']}")
print(f"IPv6: {network_info['ip6']}")
SSH Configuration Operations
from pyinfra_orbstack.operations.vm import (
ssh_info, ssh_connect_string
)
# Get SSH connection information
ssh_details = ssh_info("my-vm")
print(f"SSH Details: {ssh_details}")
# Get SSH connection string
conn_str = ssh_connect_string("my-vm")
print(f"Connect with: {conn_str}")
VM Backup and Export
For backing up VMs, use the built-in export/import operations:
from pyinfra_orbstack.operations.vm import vm_export, vm_import, vm_clone
# Quick snapshot (instant)
vm_clone("my-vm", "my-vm-backup")
# Export to file (for sharing or archival)
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
vm_export("my-vm", f"/backups/my-vm-{timestamp}.tar.zst")
# Restore from export
vm_import("/backups/my-vm-20251028.tar.zst", "my-vm-restored")
For automated backup workflows: Users can easily script around vm_export() if needed.
Configuration Management Operations
from pyinfra_orbstack.operations.vm import (
orbstack_config_get, orbstack_config_set,
orbstack_config_show, vm_username_set
)
# Get global OrbStack configuration
cpu_count = orbstack_config_get("cpu")
print(f"CPU cores allocated to OrbStack: {cpu_count}")
memory_mib = orbstack_config_get("memory_mib")
print(f"Memory allocated to OrbStack: {memory_mib} MiB")
# Show all configuration
all_config = orbstack_config_show()
print(all_config)
# Set global configuration (affects all VMs)
orbstack_config_set("memory_mib", "24576") # Set to 24GB
# Set per-VM username (only per-VM setting available)
vm_username_set("web-server", "nginx")
vm_username_set("db-server", "postgres")
Important Notes about Configuration:
-
Global vs. Per-VM Settings: Most OrbStack settings are global (affect all VMs):
cpu: Total CPU cores allocated to OrbStackmemory_mib: Total memory allocated to OrbStacknetwork.subnet4: Network subnet for all VMs- These are shared resources, not per-VM limits
-
Per-VM Settings: Only
machine.<vm-name>.usernameis per-VM:# This is the ONLY per-VM configuration available vm_username_set("my-vm", "ubuntu")
-
Common Configuration Keys:
cpu- Number of CPU cores (global)memory_mib- Memory in MiB (global)network.subnet4- IPv4 subnetrosetta- Rosetta translation (true/false)docker.expose_ports_to_lan- Expose Docker ports to LANmachines.forward_ports- Enable port forwardingnetwork.https- Enable HTTPS support
-
Effect of Changes: Some configuration changes may require restarting OrbStack to take effect
Logging and Diagnostics Operations
from pyinfra_orbstack.operations.vm import (
vm_logs, vm_status_detailed
)
# Get VM system logs
logs = vm_logs()
print(logs)
# Get detailed logs including debug information
detailed_logs = vm_logs(all_logs=True)
print(detailed_logs)
# Get comprehensive VM status information
status = vm_status_detailed()
print(f"VM State: {status.get('state')}")
print(f"VM IP: {status.get('ip4')}")
print(f"VM Image: {status.get('image')}")
Important Notes about Logging and Diagnostics:
-
VM System Logs:
vm_logs()retrieves OrbStack's unified logs for the VM- These are OrbStack-level logs (VM startup, system errors, OrbStack events)
- NOT logs from services running inside the VM
- Use
all_logs=Truefor detailed debugging information
-
In-VM Logs: To get logs from services inside the VM, use standard PyInfra operations:
from pyinfra.operations import server # Get logs from a service inside the VM server.shell( name="Get nginx logs", commands=["journalctl -u nginx -n 50"], )
-
Status Monitoring:
vm_status_detailed()provides comprehensive information:- Running state (running, stopped, etc.)
- Network configuration (IP addresses)
- Resource information
- Image details
VM Networking Information Operations
from pyinfra_orbstack.operations.vm import (
vm_network_details, vm_test_connectivity, vm_dns_lookup
)
# Get comprehensive network information for current VM
network_info = vm_network_details()
print(f"IPv4: {network_info.get('ip4')}")
print(f"IPv6: {network_info.get('ip6')}")
print(f"Hostname: {network_info.get('hostname')}")
# Test connectivity to another VM using .orb.local domain
# Ping test (default)
connectivity_result = vm_test_connectivity("backend-vm.orb.local")
print(connectivity_result)
# Test with custom ping count
connectivity_result = vm_test_connectivity(
"backend-vm.orb.local", method="ping", count=5
)
# Test HTTP endpoint availability
http_status = vm_test_connectivity(
"http://backend-vm.orb.local:8080", method="curl"
)
print(f"HTTP Status: {http_status}")
# Test specific port connectivity with netcat
port_check = vm_test_connectivity(
"database-vm.orb.local:5432", method="nc"
)
# Perform DNS lookups
# A record (IPv4) - default
ip_address = vm_dns_lookup("backend-vm.orb.local")
print(f"Resolved IP: {ip_address}")
# AAAA record (IPv6)
ipv6_address = vm_dns_lookup("backend-vm.orb.local", lookup_type="AAAA")
# MX record
mx_records = vm_dns_lookup("example.com", lookup_type="MX")
# External DNS lookup
external_ip = vm_dns_lookup("google.com")
Important Notes about Networking Operations:
-
OrbStack .orb.local Domains: VMs automatically get
.orb.localdomain names- Format:
vm-name.orb.local - Enables easy cross-VM communication without IP addresses
- Works for all connectivity tests (ping, curl, nc)
- Format:
-
Connectivity Test Methods:
ping: Basic ICMP connectivity (default, requires ICMP enabled)curl: HTTP/HTTPS endpoint testing (returns HTTP status code)nc(netcat): Port-specific connectivity checks
-
DNS Lookup Types:
A: IPv4 address (default)AAAA: IPv6 addressCNAME: Canonical nameMX: Mail exchange records- Other standard DNS record types supported
-
Cross-VM Communication:
# Example: Test if backend VM is accessible from pyinfra.operations import server from pyinfra_orbstack.operations.vm import vm_test_connectivity # Test basic connectivity vm_test_connectivity("backend.orb.local", method="ping") # Test service availability vm_test_connectivity("http://backend.orb.local:8080", method="curl") # Then configure services using standard PyInfra operations server.shell( name="Configure app to use backend", commands=["echo 'BACKEND_URL=http://backend.orb.local:8080' >> /etc/app.conf"], )
Connector Features
Automatic VM Discovery
The connector automatically discovers all OrbStack VMs and makes them available as PyInfra hosts:
# inventory.py
from pyinfra import inventory
# Automatically discover and add all running OrbStack VMs
inventory.add_group("@orbstack")
# Now you can use them in your deployment
# deploy.py
from pyinfra import host
from pyinfra.operations import server
# This will run on all discovered OrbStack VMs
server.shell(
name="Check hostname",
commands=["hostname"],
)
# Access VM properties
print(f"Deploying to: {host.name}")
print(f"VM IP: {host.data.get('vm_ip', 'unknown')}")
VM Groups
VMs are automatically grouped based on their characteristics:
orbstack: All OrbStack VMsorbstack_running: Running VMs onlyorbstack_arm64: ARM64 architecture VMsorbstack_amd64: AMD64 architecture VMs
Command Execution
Execute commands inside VMs with full PyInfra integration:
from pyinfra.operations import server
# Commands run inside the VM automatically
server.shell(
name="Check system info",
commands=["uname -a", "cat /etc/os-release"],
)
File Transfer
Upload and download files to/from VMs:
from pyinfra.operations import files
# Upload a file to the VM
files.put(
name="Upload config file",
src="local_config.conf",
dest="/etc/myapp/config.conf",
)
# Download a file from the VM
files.get(
name="Download log file",
src="/var/log/myapp.log",
dest="local_log.log",
)
Configuration
VM Configuration
Configure VM properties in your inventory:
# inventory.py
inventory.add_host("@orbstack/my-vm", {
"vm_name": "my-vm",
"vm_image": "ubuntu:22.04",
"vm_arch": "arm64",
"vm_username": "ubuntu",
"ssh_user": "ubuntu",
"ssh_key": "/path/to/ssh/key",
})
SSH Configuration
The connector uses OrbStack's built-in SSH configuration:
- SSH keys are automatically managed by OrbStack
- Default location:
~/.orbstack/ssh/id_ed25519 - SSH connection strings are automatically generated
Examples
Complete VM Setup
# deploy.py
from pyinfra import host
from pyinfra.operations import server, files
from pyinfra_orbstack.operations.vm import vm_create, vm_start
# Create and start a VM
vm_create(
name="web-server",
image="ubuntu:22.04",
arch="arm64",
user="ubuntu",
)
vm_start("web-server")
# Install and configure nginx
server.packages(
name="Install nginx",
packages=["nginx"],
)
files.put(
name="Upload nginx config",
src="nginx.conf",
dest="/etc/nginx/sites-available/default",
)
server.service(
name="Start nginx",
service="nginx",
running=True,
enabled=True,
)
Multi-VM Deployment
# inventory.py
from pyinfra import inventory
# Define multiple VMs
inventory.add_host("@orbstack/web-server", {
"vm_name": "web-server",
"vm_image": "ubuntu:22.04",
})
inventory.add_host("@orbstack/db-server", {
"vm_name": "db-server",
"vm_image": "ubuntu:22.04",
})
# Group them
inventory.add_group("web_servers", ["@orbstack/web-server"])
inventory.add_group("db_servers", ["@orbstack/db-server"])
# deploy.py
from pyinfra import host
from pyinfra.operations import server
# Deploy to web servers
if host in inventory.get_group("web_servers"):
server.packages(
name="Install nginx",
packages=["nginx"],
)
# Deploy to database servers
if host in inventory.get_group("db_servers"):
server.packages(
name="Install PostgreSQL",
packages=["postgresql"],
)
Operation Timing (Optional)
For debugging and performance analysis, enable operation timing:
import logging
from pyinfra_orbstack.timing import timed_operation
# Enable timing logs
logging.basicConfig(level=logging.INFO)
with timed_operation("vm_deployment"):
vm_create(name="web-server", image="ubuntu:22.04")
# ... other operations
See Timing Guide for details.
Development
For detailed development information, standards, and guidelines, see the Documentation Index.
Quick Development Setup
# Install development dependencies
uv sync --dev
# Run tests
uv run pytest
# Format and lint code
uv run black src/ tests/
uv run flake8 src/ tests/
Contributing
We welcome contributions! Please see CONTRIBUTING.md for detailed guidelines on:
- Setting up your development environment
- Code style and conventions
- Testing requirements
- Submitting pull requests
- Documentation standards
For architectural decisions and development history, see the Documentation Index.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- Issues: GitHub Issues
- Documentation: GitHub README
- PyInfra Documentation: pyinfra.com
Changelog
See CHANGELOG.md for a list of changes and version history.
Metadata
Release files for pyinfra-orbstack 0.11.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyinfra_orbstack-0.11.0.tar.gz | 349.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyinfra_orbstack-0.11.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 370.3 kB
Release files / pyinfra_orbstack-0.11.0.tar.gz
| Download URL | pyinfra_orbstack-0.11.0.tar.gz |
|---|---|
| Size | 349.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2beb4c8c8075cf3029b3d0e7452ac96997ca8d4edf3fa1f9a4371f117896b6ff
|
|
BLAKE2b-256 checksum How to use checksums |
c2c9cb4afbb6b3de00791f4b7287a2920985367ae62e452101d2f5051d1ae34e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Nov 2, 2025.
Transparency logRelease files / pyinfra_orbstack-0.11.0-py3-none-any.whl
| Download URL | pyinfra_orbstack-0.11.0-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fca40ec0da514cc95f7b8f296dbbc23e985bfe79ea8a62516aac9bba13bb9bd5
|
|
BLAKE2b-256 checksum How to use checksums |
4997c18e282b0de5d39f6f46ae2066a822d71b29676d2bc51c5ca6b66b48bdc4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Nov 2, 2025.
Transparency log