Initial commit: Vultr API v2 Python wrapper with FastAPI server
- vultr_api/: Python library wrapping Vultr API v2 - 17 resource modules (instances, dns, firewall, vpc, etc.) - Pagination support, error handling - server/: FastAPI REST server - All API endpoints exposed via HTTP - X-API-Key header authentication - Swagger docs at /docs - Podman quadlet config for systemd deployment Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
291
vultr_api/resources/bare_metal.py
Normal file
291
vultr_api/resources/bare_metal.py
Normal file
@@ -0,0 +1,291 @@
|
||||
"""
|
||||
Bare Metal Resource
|
||||
|
||||
Bare metal server management
|
||||
"""
|
||||
|
||||
from typing import Dict, List
|
||||
from .base import BaseResource
|
||||
|
||||
|
||||
class BareMetalResource(BaseResource):
|
||||
"""
|
||||
Bare metal server management
|
||||
|
||||
Usage:
|
||||
# List bare metal servers
|
||||
servers = client.bare_metal.list()
|
||||
|
||||
# Create server
|
||||
server = client.bare_metal.create(
|
||||
region="ewr",
|
||||
plan="vbm-4c-32gb",
|
||||
os_id=215
|
||||
)
|
||||
"""
|
||||
|
||||
def list(
|
||||
self,
|
||||
per_page: int = 100,
|
||||
cursor: str = None,
|
||||
tag: str = None,
|
||||
label: str = None,
|
||||
main_ip: str = None,
|
||||
region: str = None,
|
||||
) -> Dict:
|
||||
"""
|
||||
List bare metal servers
|
||||
|
||||
Returns:
|
||||
Dict with 'bare_metals' list and 'meta' pagination
|
||||
"""
|
||||
params = {"per_page": per_page}
|
||||
if cursor:
|
||||
params["cursor"] = cursor
|
||||
if tag:
|
||||
params["tag"] = tag
|
||||
if label:
|
||||
params["label"] = label
|
||||
if main_ip:
|
||||
params["main_ip"] = main_ip
|
||||
if region:
|
||||
params["region"] = region
|
||||
|
||||
return self.client.get("bare-metals", params=params)
|
||||
|
||||
def list_all(self, **kwargs) -> List[Dict]:
|
||||
"""List all bare metal servers (auto-paginate)"""
|
||||
return self.client.paginate("bare-metals", "bare_metals", params=kwargs)
|
||||
|
||||
def get(self, baremetal_id: str) -> Dict:
|
||||
"""
|
||||
Get bare metal server details
|
||||
|
||||
Args:
|
||||
baremetal_id: Bare metal ID
|
||||
|
||||
Returns:
|
||||
Server details
|
||||
"""
|
||||
response = self.client.get(f"bare-metals/{baremetal_id}")
|
||||
return response.get("bare_metal", {})
|
||||
|
||||
def create(
|
||||
self,
|
||||
region: str,
|
||||
plan: str,
|
||||
os_id: int = None,
|
||||
script_id: str = None,
|
||||
snapshot_id: str = None,
|
||||
enable_ipv6: bool = False,
|
||||
label: str = None,
|
||||
sshkey_id: List[str] = None,
|
||||
app_id: int = None,
|
||||
image_id: str = None,
|
||||
user_data: str = None,
|
||||
activation_email: bool = False,
|
||||
hostname: str = None,
|
||||
tag: str = None,
|
||||
tags: List[str] = None,
|
||||
reserved_ipv4: str = None,
|
||||
persistent_pxe: bool = False,
|
||||
attach_vpc2: List[str] = None,
|
||||
) -> Dict:
|
||||
"""
|
||||
Create a bare metal server
|
||||
|
||||
Args:
|
||||
region: Region ID
|
||||
plan: Plan ID
|
||||
os_id: Operating System ID
|
||||
script_id: Startup script ID
|
||||
snapshot_id: Snapshot ID
|
||||
enable_ipv6: Enable IPv6
|
||||
label: Server label
|
||||
sshkey_id: SSH key IDs
|
||||
app_id: Application ID
|
||||
image_id: Custom image ID
|
||||
user_data: Cloud-init user data
|
||||
activation_email: Send activation email
|
||||
hostname: Server hostname
|
||||
tag: Deprecated, use tags
|
||||
tags: Tags
|
||||
reserved_ipv4: Reserved IPv4 to assign
|
||||
persistent_pxe: Enable persistent PXE
|
||||
attach_vpc2: VPC 2.0 IDs to attach
|
||||
|
||||
Returns:
|
||||
Created server details
|
||||
"""
|
||||
data = {"region": region, "plan": plan}
|
||||
|
||||
if os_id is not None:
|
||||
data["os_id"] = os_id
|
||||
if script_id:
|
||||
data["script_id"] = script_id
|
||||
if snapshot_id:
|
||||
data["snapshot_id"] = snapshot_id
|
||||
if enable_ipv6:
|
||||
data["enable_ipv6"] = enable_ipv6
|
||||
if label:
|
||||
data["label"] = label
|
||||
if sshkey_id:
|
||||
data["sshkey_id"] = sshkey_id
|
||||
if app_id is not None:
|
||||
data["app_id"] = app_id
|
||||
if image_id:
|
||||
data["image_id"] = image_id
|
||||
if user_data:
|
||||
data["user_data"] = user_data
|
||||
if activation_email:
|
||||
data["activation_email"] = activation_email
|
||||
if hostname:
|
||||
data["hostname"] = hostname
|
||||
if tag:
|
||||
data["tag"] = tag
|
||||
if tags:
|
||||
data["tags"] = tags
|
||||
if reserved_ipv4:
|
||||
data["reserved_ipv4"] = reserved_ipv4
|
||||
if persistent_pxe:
|
||||
data["persistent_pxe"] = persistent_pxe
|
||||
if attach_vpc2:
|
||||
data["attach_vpc2"] = attach_vpc2
|
||||
|
||||
response = self.client.post("bare-metals", data)
|
||||
return response.get("bare_metal", {})
|
||||
|
||||
def update(
|
||||
self,
|
||||
baremetal_id: str,
|
||||
user_data: str = None,
|
||||
label: str = None,
|
||||
tag: str = None,
|
||||
tags: List[str] = None,
|
||||
os_id: int = None,
|
||||
app_id: int = None,
|
||||
image_id: str = None,
|
||||
enable_ipv6: bool = None,
|
||||
) -> Dict:
|
||||
"""
|
||||
Update a bare metal server
|
||||
|
||||
Args:
|
||||
baremetal_id: Bare metal ID
|
||||
(other args same as create)
|
||||
|
||||
Returns:
|
||||
Updated server details
|
||||
"""
|
||||
data = {}
|
||||
|
||||
if user_data is not None:
|
||||
data["user_data"] = user_data
|
||||
if label is not None:
|
||||
data["label"] = label
|
||||
if tag is not None:
|
||||
data["tag"] = tag
|
||||
if tags is not None:
|
||||
data["tags"] = tags
|
||||
if os_id is not None:
|
||||
data["os_id"] = os_id
|
||||
if app_id is not None:
|
||||
data["app_id"] = app_id
|
||||
if image_id is not None:
|
||||
data["image_id"] = image_id
|
||||
if enable_ipv6 is not None:
|
||||
data["enable_ipv6"] = enable_ipv6
|
||||
|
||||
response = self.client.patch(f"bare-metals/{baremetal_id}", data)
|
||||
return response.get("bare_metal", {})
|
||||
|
||||
def delete(self, baremetal_id: str) -> None:
|
||||
"""
|
||||
Delete a bare metal server
|
||||
|
||||
Args:
|
||||
baremetal_id: Bare metal ID to delete
|
||||
"""
|
||||
self.client.delete(f"bare-metals/{baremetal_id}")
|
||||
|
||||
def start(self, baremetal_id: str) -> None:
|
||||
"""Start a bare metal server"""
|
||||
self.client.post(f"bare-metals/{baremetal_id}/start")
|
||||
|
||||
def halt(self, baremetal_id: str) -> None:
|
||||
"""Halt a bare metal server"""
|
||||
self.client.post(f"bare-metals/{baremetal_id}/halt")
|
||||
|
||||
def reboot(self, baremetal_id: str) -> None:
|
||||
"""Reboot a bare metal server"""
|
||||
self.client.post(f"bare-metals/{baremetal_id}/reboot")
|
||||
|
||||
def reinstall(self, baremetal_id: str, hostname: str = None) -> Dict:
|
||||
"""
|
||||
Reinstall a bare metal server
|
||||
|
||||
Args:
|
||||
baremetal_id: Bare metal ID
|
||||
hostname: New hostname (optional)
|
||||
|
||||
Returns:
|
||||
Server details
|
||||
"""
|
||||
data = {}
|
||||
if hostname:
|
||||
data["hostname"] = hostname
|
||||
|
||||
response = self.client.post(f"bare-metals/{baremetal_id}/reinstall", data)
|
||||
return response.get("bare_metal", {})
|
||||
|
||||
def get_bandwidth(self, baremetal_id: str) -> Dict:
|
||||
"""Get bandwidth usage"""
|
||||
return self.client.get(f"bare-metals/{baremetal_id}/bandwidth")
|
||||
|
||||
def get_user_data(self, baremetal_id: str) -> Dict:
|
||||
"""Get user data"""
|
||||
return self.client.get(f"bare-metals/{baremetal_id}/user-data")
|
||||
|
||||
def get_upgrades(self, baremetal_id: str, upgrade_type: str = None) -> Dict:
|
||||
"""Get available upgrades"""
|
||||
params = {}
|
||||
if upgrade_type:
|
||||
params["type"] = upgrade_type
|
||||
return self.client.get(f"bare-metals/{baremetal_id}/upgrades", params=params)
|
||||
|
||||
def get_vnc(self, baremetal_id: str) -> Dict:
|
||||
"""Get VNC URL"""
|
||||
return self.client.get(f"bare-metals/{baremetal_id}/vnc")
|
||||
|
||||
# IPv4 management
|
||||
def list_ipv4(self, baremetal_id: str) -> List[Dict]:
|
||||
"""List IPv4 addresses"""
|
||||
response = self.client.get(f"bare-metals/{baremetal_id}/ipv4")
|
||||
return response.get("ipv4s", [])
|
||||
|
||||
def list_ipv6(self, baremetal_id: str) -> List[Dict]:
|
||||
"""List IPv6 addresses"""
|
||||
response = self.client.get(f"bare-metals/{baremetal_id}/ipv6")
|
||||
return response.get("ipv6s", [])
|
||||
|
||||
# VPC 2.0
|
||||
def list_vpc2(self, baremetal_id: str) -> List[Dict]:
|
||||
"""List attached VPC 2.0 networks"""
|
||||
response = self.client.get(f"bare-metals/{baremetal_id}/vpc2")
|
||||
return response.get("vpcs", [])
|
||||
|
||||
def attach_vpc2(
|
||||
self,
|
||||
baremetal_id: str,
|
||||
vpc_id: str,
|
||||
ip_address: str = None
|
||||
) -> None:
|
||||
"""Attach VPC 2.0 to bare metal"""
|
||||
data = {"vpc_id": vpc_id}
|
||||
if ip_address:
|
||||
data["ip_address"] = ip_address
|
||||
self.client.post(f"bare-metals/{baremetal_id}/vpc2/attach", data)
|
||||
|
||||
def detach_vpc2(self, baremetal_id: str, vpc_id: str) -> None:
|
||||
"""Detach VPC 2.0 from bare metal"""
|
||||
self.client.post(f"bare-metals/{baremetal_id}/vpc2/detach", {"vpc_id": vpc_id})
|
||||
Reference in New Issue
Block a user