Hướng dẫn sử dụng VMware vSphere REST API với Python: Tự động hóa quản lý máy ảo và Inventory mà không cần cài PowerCLI

VMware tutorial - IT technology blog
VMware tutorial - IT technology blog

Quick Start: Kết nối vSphere API trong 5 phút

Nếu bạn đã từng phải cài PowerCLI trên Windows chỉ để chạy vài lệnh quản lý VMware, thì REST API của vSphere chính là thứ bạn cần. Chỉ cần Python và thư viện requests — kết nối được với toàn bộ hạ tầng VMware vSphere 7.x/8.x từ bất kỳ máy nào, không phụ thuộc gì thêm.

Cài thư viện cần thiết:

pip install requests urllib3

Code dưới đây kết nối tới vCenter, lấy session token và list tất cả VM — chạy được ngay:

import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

VCENTER_HOST = "vcenter.lab.local"
USERNAME = "[email protected]"
PASSWORD = "YourPassword123!"
BASE_URL = f"https://{VCENTER_HOST}/api"

# Tạo session
session = requests.Session()
session.verify = False  # Lab environment — production nên bật verify

# Authenticate — lấy session token
response = session.post(
    f"{BASE_URL}/session",
    auth=(USERNAME, PASSWORD)
)
token = response.json()
session.headers.update({"vmware-api-session-id": token})

# List tất cả VM
vms = session.get(f"{BASE_URL}/vcenter/vm").json()
for vm in vms:
    print(f"{vm['name']} | Power: {vm['power_state']} | ID: {vm['vm']}")

Output trông như thế này là API đã hoạt động:

ubuntu-22-web01 | Power: POWERED_ON | ID: vm-101
centos-db-prod  | Power: POWERED_OFF | ID: vm-145
win2022-dc01    | Power: POWERED_ON | ID: vm-203

Giải thích chi tiết: vSphere REST API hoạt động như thế nào?

Session-based Authentication

vSphere REST API dùng session token thay vì Basic Auth cho mỗi request. POST credentials một lần, nhận về token dạng string, rồi gắn vào header vmware-api-session-id cho các request tiếp theo. Token tự expire sau 30 phút idle. Khác với Bearer token hay OAuth, không có refresh flow hay middleware phức tạp — implement xong trong 5 dòng code.

Hai base path cần biết

Có hai base path, và đây là điểm hay nhầm lẫn nhất:

  • /api — API mới, RESTful thuần, JSON response gọn gàng. Dùng cái này nếu môi trường từ vSphere 7.0+.
  • /rest — API cũ (deprecated từ 8.0), vẫn hoạt động nhưng response bọc thêm lớp {"value": ...} khá phiền.

Swagger UI tại https://vcenter-ip/api cho phép test endpoint trực tiếp trên browser, không cần viết code. Mỗi khi không chắc endpoint nào đúng, mở cái này tra nhanh hơn đọc tài liệu nhiều.

Các endpoint hay dùng nhất

# Inventory
GET /api/vcenter/vm                    # List VM
GET /api/vcenter/vm/{vm}               # Chi tiết 1 VM
GET /api/vcenter/host                  # List ESXi hosts
GET /api/vcenter/datastore             # List datastore
GET /api/vcenter/cluster               # List cluster

# Power operations
POST /api/vcenter/vm/{vm}/power?action=start
POST /api/vcenter/vm/{vm}/power?action=stop
POST /api/vcenter/vm/{vm}/power?action=reset

# Snapshot
GET  /api/vcenter/vm/{vm}/snapshot
POST /api/vcenter/vm/{vm}/snapshot
DELETE /api/vcenter/vm/{vm}/snapshot/{snapshot}

Nâng cao: Script thực tế cho công việc hàng ngày

Export Inventory ra CSV

Script mình dùng cuối tháng để báo cáo tình trạng VM cho team infra — chạy một lần ra CSV, gửi vào group chat là xong:

import requests
import urllib3
import csv
from datetime import datetime

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class vSphereClient:
    def __init__(self, host, username, password):
        self.base_url = f"https://{host}/api"
        self.username = username
        self.password = password
        self.session = requests.Session()
        self.session.verify = False
        self._authenticate()

    def _authenticate(self):
        resp = self.session.post(
            f"{self.base_url}/session",
            auth=(self.username, self.password)
        )
        resp.raise_for_status()
        self.session.headers.update({
            "vmware-api-session-id": resp.json()
        })

    def get_vms(self, **filters):
        return self.session.get(
            f"{self.base_url}/vcenter/vm", params=filters
        ).json()

    def get_vm_details(self, vm_id):
        return self.session.get(
            f"{self.base_url}/vcenter/vm/{vm_id}"
        ).json()

    def logout(self):
        self.session.delete(f"{self.base_url}/session")


def export_inventory_csv(client, output_file):
    vms = client.get_vms()
    rows = []
    for vm in vms:
        details = client.get_vm_details(vm["vm"])
        memory_gb = details.get("memory", {}).get("size_MiB", 0) / 1024
        cpu_count = details.get("cpu", {}).get("count", 0)
        rows.append({
            "Name": vm["name"],
            "ID": vm["vm"],
            "Power State": vm["power_state"],
            "CPU": cpu_count,
            "Memory (GB)": round(memory_gb, 1),
            "Guest OS": details.get("guest_OS", "Unknown"),
        })

    with open(output_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=rows[0].keys())
        writer.writeheader()
        writer.writerows(rows)
    print(f"Exported {len(rows)} VMs to {output_file}")


client = vSphereClient("vcenter.lab.local", "[email protected]", "Password123!")
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
export_inventory_csv(client, f"vm_inventory_{timestamp}.csv")
client.logout()

Power Management hàng loạt

Shutdown tất cả VM có tên theo pattern — dùng khi cần bảo trì host hoặc dọn sạch test environment:

def bulk_power_off(client, name_pattern):
    vms = client.get_vms()
    targets = [
        vm for vm in vms
        if name_pattern.lower() in vm["name"].lower()
        and vm["power_state"] == "POWERED_ON"
    ]
    print(f"Found {len(targets)} VMs matching '{name_pattern}'")
    for vm in targets:
        resp = client.session.post(
            f"{client.base_url}/vcenter/vm/{vm['vm']}/power",
            params={"action": "stop"}
        )
        status = "✓" if resp.status_code == 204 else "✗"
        print(f"  {status} {vm['name']}")

bulk_power_off(client, "test")

Tạo Snapshot trước khi update

Thói quen trước mỗi lần patch: snapshot nhanh, update, lỗi thì revert. Script dưới đây bỏ qua RAM dump (memory: False) — nhẹ hơn và đủ dùng cho phần lớn trường hợp:

def create_snapshot(client, vm_id, name, description=""):
    payload = {
        "description": description,
        "memory": False,    # Không snapshot RAM — nhanh hơn đáng kể
        "name": name,
        "quiesce": True     # Quiesce filesystem nếu VMware Tools đang chạy
    }
    resp = client.session.post(
        f"{client.base_url}/vcenter/vm/{vm_id}/snapshot",
        json=payload
    )
    if resp.status_code == 204:
        print(f"Snapshot '{name}' created successfully")

create_snapshot(client, "vm-101", "pre-patch-july", "Before July patch Tuesday")

Tips thực tế từ kinh nghiệm dùng hàng ngày

Tip 1: Tái sử dụng session, đừng authenticate lại mỗi request

Lỗi phổ biến nhất mình thấy là code authenticate trong vòng lặp — mỗi VM gọi 1 lần login. vSphere mặc định giới hạn 100 concurrent sessions, làm vậy rất nhanh bị lỗi 503 Service Unavailable khi chạy batch lớn. Tạo một instance vSphereClient, dùng cho toàn bộ script.

Tip 2: Dùng filter params để tăng tốc truy vấn

Môi trường 500+ VM mà lấy hết về lọc bằng Python thì response time tầm 8–10 giây. Dùng filter trên API, xuống còn dưới 1 giây:

# Chỉ lấy VM đang bật trong cluster cụ thể
params = {
    "filter.power_states": "POWERED_ON",
    "filter.clusters": "domain-c10"  # Cluster ID lấy từ GET /api/vcenter/cluster
}
vms = client.session.get(f"{client.base_url}/vcenter/vm", params=params).json()

Băng thông cũng giảm tỉ lệ tương ứng — quan trọng khi chạy script từ laptop qua VPN.

Tip 3: Xử lý session timeout cho script chạy lâu

Token expire sau 30 phút idle. Script export 500+ VM với đầy đủ details — mỗi VM là một API call riêng — dễ chạy quá 30 phút. Implement re-authenticate gọn:

def safe_get(client, endpoint):
    resp = client.session.get(f"{client.base_url}{endpoint}")
    if resp.status_code == 401:
        # Session hết hạn — login lại
        client._authenticate()
        resp = client.session.get(f"{client.base_url}{endpoint}")
    resp.raise_for_status()
    return resp.json()

Tip 4: SSL certificate trong production

Script lab tắt SSL verify cho tiện, nhưng production thì không nên. Cách đúng là dùng CA cert của vCenter:

# Download cert bundle từ vCenter (trả về file zip)
curl -o vcenter-certs.zip "https://vcenter.corp.local/certs/download"
unzip vcenter-certs.zip -d vcenter-certs
# CA cert nằm trong vcenter-certs/certs/lin/ (Linux) hoặc certs/win/ (Windows)
# Đổi extension .0 thành .pem, rồi dùng trong Python:
session.verify = "/path/to/vcenter-certs/certs/lin/root-ca.pem"

Tip 5: Tra cứu PowerCLI sang REST API

Tài liệu VMware đôi khi chỉ có ví dụ PowerCLI. Cách mapping khá nhất quán: Get-VMGET /api/vcenter/vm, Start-VMPOST /api/vcenter/vm/{id}/power?action=start, New-SnapshotPOST /api/vcenter/vm/{id}/snapshot. Quen với pattern này rồi thì chuyển đổi rất nhanh.

Một điểm thú vị khi mình migrate lab sang Proxmox: API của Proxmox cũng dùng session token tương tự (endpoint /api2/json/access/ticket), nên phần lớn code Python viết cho vSphere dùng được ngay — chỉ cần đổi endpoint và field names. Pattern này không bị lock-in vào VMware.

REST API của vSphere ổn định qua các phiên bản — script viết cho 7.0 phần lớn chạy được trên 8.0 không cần sửa. Đó là lý do mình chọn REST API thay vì PowerCLI cho automation: ít dependency hơn, chạy được trên mọi OS, và tích hợp thẳng với Ansible, Prometheus hay Slack notification bằng Python — không cần thêm middleware hay wrapper nào.

Share: