Features
Single Login
Authenticate once in __init__. Session reused for all calls — no per-request delays.
Auto Pagination
list_all() lazily iterates every page. No manual page tracking needed.
Async Task Polling
tasks.wait() polls until completion, raises on failure or timeout.
Dual Auth
EC2 (AWS4-HMAC-SHA256) signature or Token-based (RSA encrypted) authentication.
Idempotency
Automatic X-Client-Token headers on POST/PUT requests.
Token Refresh
24-hour tokens renewed transparently. Your long-running scripts stay connected.
Quick Start
EC2 Authentication (Recommended)
Python
from sangfor_scp import SCPClient
client = SCPClient(
host="10.10.10.10",
access_key="AK5F3B2A1D9E7C4082F1",
secret_key="sK9mXpL2rN8vQwZdTfUcOb4jYhAeIgBk",
region="cn-south-1",
verify_ssl=False, # SCP uses self-signed certs by default
)
Token Authentication
Python
from sangfor_scp import SCPClient
client = SCPClient(
host="10.10.10.10",
username="admin",
password="your_password",
verify_ssl=False,
)
Virtual Machines
List all VMs (auto-paginated)
Code
for vm in client.servers.list_all():
print(vm["id"], vm["name"], vm["status"])
# Filter by resource pool
for vm in client.servers.list_all(az_id="878b7070-6d87-409a-a141-7224fc7bcedd"):
print(vm["name"])
# Count without fetching all
total = client.servers.count()
print(f"Total VMs: {total}")
Response
// vm object example
{
"id": "f14b3195-653e-41b0-a2a9-235e38770c1a",
"name": "web-server-01",
"status": "running",
"cores": 4,
"memory_mb": 8192,
"az_id": "878b7070-6d87-409a-a141-7224fc7bcedd",
"host_id": "host-90e2bad3dfa4",
"disks": [{ "id": "ide0", "size_mb": 51200 }],
"networks": [{ "ip": "192.168.1.101", "mac": "fa:16:3e:ab:cd:ef" }]
}
Get VM detail
Code
vm = client.servers.get("f14b3195-653e-41b0-a2a9-235e38770c1a")
print(vm["name"], vm["status"])
print(f"CPU: {vm['cores']} RAM: {vm['memory_mb']}MB")
Response
{
"id": "f14b3195-653e-41b0-a2a9-235e38770c1a",
"name": "web-server-01",
"status": "running",
"cores": 4,
"memory_mb": 8192
}
Create a VM and wait for completion
Code
result = client.servers.create(
az_id="878b7070-6d87-409a-a141-7224fc7bcedd",
image_id="98a5f5a0-665a-4d66-ba9e-985fc860b7eb",
storage_tag_id="00000000-0000-0000-0000-000000000000",
cores=4,
memory_mb=8192,
name="web-server-01",
networks=[{
"vif_id": "net0",
"vpc_id": "vpc-3a1f9c2d",
"subnet_id": "sub-7b4e1a09",
"connect": 1,
"model": "virtio",
}],
power_on=True,
)
# Wait up to 5 minutes
task = client.tasks.wait(result["task_id"], timeout=300)
vm_id = result["uuids"][0]
print(f"VM created: {vm_id}")
Response
{
"task_id": "task-a3f91bc2-4d8e-11ef-b123-0050568a1234",
"uuids": [
"f14b3195-653e-41b0-a2a9-235e38770c1a"
]
}
// After tasks.wait():
{
"id": "task-a3f91bc2-4d8e-11ef-b123",
"status": "finish",
"progress": 100,
"description": "Create VM success"
}
Power operations
Code
vm_id = "f14b3195-653e-41b0-a2a9-235e38770c1a"
client.servers.power_on(vm_id)
client.servers.power_off(vm_id)
client.servers.power_off(vm_id, force=True) # hard power off
client.servers.reboot(vm_id)
client.servers.reboot(vm_id, force=True) # force reboot
client.servers.suspend(vm_id)
client.servers.resume(vm_id)
Resource Pools (AZ)
Code
for az in client.resource_pools.list_all():
print(az["id"], az["name"])
# Platform-wide overview
ov = client.resource_pools.overview()
print(f"Total VMs : {ov['server']['total']}")
print(f"Running : {ov['server']['running_count']}")
print(f"Total hosts: {ov['host']['total']}")
# Storage tags in a pool
tags = client.resource_pools.storage_tags(az_id="878b7070-...")
for t in tags:
print(t["id"], t["name"])
Response
// list_all() item
{ "id": "878b7070-6d87-409a-a141-7224fc7bcedd", "name": "DATACENTER-A" }
// overview()
{
"server": { "total": 1422, "running_count": 1098 },
"host": { "total": 32, "running_count": 32 }
}
// storage_tags()
[
{ "id": "00000000-0000-0000-0000-000000000000", "name": "High Performance" },
{ "id": "22222222-2222-2222-2222-222222222222", "name": "Capacity Storage" }
]
Images
Code
# All images
for img in client.images.list_all():
print(img["id"], img["name"])
# Filter by type
for img in client.images.list_iso():
print(img["name"])
for img in client.images.list_acloud():
print(img["name"])
# Find by name
img = client.images.find_by_name("Rocky-9.7-x86_64-minimal")
if img:
print(img["id"])
Response
// image object
{
"id": "98a5f5a0-665a-4d66-ba9e-985fc860b7eb",
"name": "Rocky-9.7-x86_64-minimal",
"disk_format": "ISO",
"os_type": "linux",
"size_mb": 1024,
"status": "active",
"az_id": "878b7070-6d87-409a-a141-7224fc7bcedd"
}
Volumes (Disks)
Code
# Create a standalone disk
result = client.volumes.create(
az_id="878b7070-6d87-409a-a141-7224fc7bcedd",
storage_tag_id="00000000-0000-0000-0000-000000000000",
size_mb=102400, # 100 GB
name="data-disk-01",
)
client.tasks.wait(result["task_id"])
volume_id = result["volume_id"]
# Attach to a VM
task_id = client.servers.attach_volume("vm-uuid", volume_id)
client.tasks.wait(task_id)
# Detach
task_id = client.servers.detach_volume("vm-uuid", volume_id)
client.tasks.wait(task_id)
# List disks attached to a VM
disks = client.volumes.list_attached("vm-uuid")
for d in disks:
print(d)
Response
// create()
{
"volume_id": "vol-d4a19f3c-72b1-4e8a",
"task_id": "task-b7e2ca10-5f91-11ef"
}
// list_all() item
{
"id": "vol-d4a19f3c-72b1-4e8a",
"name": "data-disk-01",
"status": "available",
"size_mb": 102400,
"az_id": "878b7070-6d87-409a-a141-7224fc7bcedd"
}
Networks
Code
# List VPCs
for vpc in client.networks.list_vpcs():
print(vpc["id"], vpc["name"])
# Create VPC
vpc = client.networks.create_vpc(
az_id="878b7070-...",
name="prod-vpc",
cidr="10.0.0.0/16",
)
# Create Subnet
subnet = client.networks.create_subnet(
vpc_id=vpc["id"],
az_id="878b7070-...",
cidr="10.0.1.0/24",
name="prod-subnet-a",
gateway_ip="10.0.1.1",
)
# List subnets in a VPC
for s in client.networks.list_subnets(vpc_id=vpc["id"]):
print(s["cidr"], s["name"])
Response
// VPC object
{
"id": "vpc-3a1f9c2d-8e74-4b12-a091",
"name": "prod-vpc",
"cidr": "10.0.0.0/16",
"status": "active",
"az_id": "878b7070-6d87-409a-a141"
}
// Subnet object
{
"id": "sub-7b4e1a09-3c82-4f51-b207",
"name": "prod-subnet-a",
"cidr": "10.0.1.0/24",
"gateway_ip": "10.0.1.1",
"vpc_id": "vpc-3a1f9c2d-8e74-4b12"
}
Elastic IPs
Code
# Allocate
eip = client.eips.allocate(
az_id="878b7070-...",
bandwidth_mb=100,
name="web-eip-01",
)
eip_id = eip["id"]
# Bind to a VM
task_id = client.eips.bind(eip_id, server_id="vm-uuid")
client.tasks.wait(task_id)
# Update bandwidth
client.eips.update_bandwidth(eip_id, bandwidth_mb=500)
# Unbind and release
client.eips.unbind(eip_id)
client.eips.release(eip_id)
Response
// allocate()
{
"id": "eip-c9f3a217-4b8d-11ef-9021",
"ip": "203.0.113.45",
"status": "inactive",
"bandwidth_mb": 100,
"az_id": "878b7070-6d87-409a-a141"
}
// bind() — returns task_id
"task-f2b9e341-5c1d-11ef-b872-0050568a1234"
Async Tasks
Code
# Simple wait
task = client.tasks.wait("task-uuid", timeout=300)
# With progress callback
def on_progress(task_data):
pct = task_data.get("progress", 0)
desc = task_data.get("description", "")
print(f" {pct}% {desc}")
task = client.tasks.wait(
task_id="task-uuid",
timeout=600,
poll_interval=5,
progress_callback=on_progress,
)
# Non-blocking check
if client.tasks.is_done("task-uuid"):
print("done!")
Response
// task object
{
"id": "task-a3f91bc2-4d8e-11ef-b123",
"status": "finish",
"progress": 100,
"description": "Create VM success",
"created_at": "2025-11-27T10:32:14Z",
"finished_at": "2025-11-27T10:33:02Z"
}
// Possible statuses:
// waiting → doing → finish
// → failure
// → canceled
Physical Hosts
Code
# List all hosts
for host in client.system.list_all_hosts():
print(host["id"], host["name"], host["status"])
# Filter by AZ or status
running = list(client.system.list_all_hosts(
az_id="878b7070-...",
status="running",
))
print(f"{len(running)} running hosts")
# Get specific host
host = client.system.get_host("host-90e2bad3dfa4")
print(host["name"], host["status"])
# Host network interfaces
ifaces = client.system.list_host_interfaces("host-90e2bad3dfa4")
for i in ifaces:
print(i["name"], i["ip"])
Response
// host object
{
"id": "host-90e2bad3dfa4",
"name": "10.10.10.101",
"status": "running",
"az_id": "878b7070-6d87-409a-a141-7224fc7bcedd",
"cpu_total": 64,
"cpu_used": 28,
"memory_total_mb": 196608,
"memory_used_mb": 87040
}
// interface object
{
"name": "bond0",
"ip": "10.10.10.101",
"function": "mgmt",
"speed_mbps": 10000
}
Error Handling
Code
from sangfor_scp import (
SCPError, # base exception
SCPAuthError, # 401 Unauthorized
SCPForbiddenError, # 403 Forbidden
SCPNotFoundError, # 404 Not Found
SCPConflictError, # 409 Conflict
SCPRateLimitError, # 429 Too Many Requests
SCPTaskError, # task ended in failure/canceled
SCPTimeoutError, # tasks.wait() timed out
)
try:
vm = client.servers.get("nonexistent-uuid")
except SCPNotFoundError:
print("VM not found")
try:
task = client.tasks.wait("task-uuid", timeout=60)
except SCPTaskError as e:
print(f"Task failed: {e}")
except SCPTimeoutError as e:
print(f"Timed out after {e.timeout}s")
API Coverage
| Resource | Operations |
|---|---|
client.servers | list_all, get, create, delete, power on/off/reboot, attach/detach volume |
client.tasks | get, wait (with timeout & progress callback), is_done |
client.resource_pools | list_all, get, overview, storage_tags |
client.tenants | list_all, get, find_by_name, list_by_resource_pool |
client.images | list_all, get, find_by_name, list_iso, list_acloud |
client.volumes | list_all, get, create, delete, resize, list_available, list_attached |
client.networks | VPC: list, create, get, delete · Subnet: list, create, get, delete |
client.eips | allocate, bind, unbind, release, update_bandwidth |
client.system | version, platform_info, list_all_hosts, get_host, list_host_interfaces |