Skip to content

feat: implement Vultr cloud adapter with full REST API - #32

Merged
ralyodio merged 1 commit into
profullstack:masterfrom
hikaruhuimin:feat/cloud-vultr-impl
May 12, 2026
Merged

ralyodio merged 1 commit into
profullstack:masterfrom
hikaruhuimin:feat/cloud-vultr-impl

Conversation

@hikaruhuimin

Copy link
Copy Markdown
Contributor

Summary

Implements the full Vultr cloud adapter, replacing the existing stub with working REST API calls using native fetch.

Ref: #6

Changes

packages/cloud/vultr/src/index.ts

  • connect() — verifies VULTR_API_KEY via GET /v2/account, returns real account name and email
  • quote() — fetches real pricing from GET /v2/plans, filters by region/kind/cpu/memory/storage, returns cheapest match
  • provision() — four paths:
    • POST /v2/instances for VPS/GPU Droplets
    • POST /v2/bare-metals for bare metal servers
    • POST /v2/blocks for block storage
    • POST /v2/databases for managed DBs
  • list() — GET /v2/instances + GET /v2/bare-metals with full instance mapping (IPs, status, tags)
  • destroy() — auto-detects resource type, tries instance/bare-metal/block/database DELETE
  • status() — auto-detects resource type, returns state mapping
  • Smart plan picker — filters by region, kind, CPU, memory, storage, maxHourlyPrice guardrail
  • Setup flow — tokenSetup with clear steps pointing to Vultr API key page

packages/cloud/vultr/src/index.test.ts

  • Upgraded from smoke test to full contract test via contractTestCloud
  • Tests: required fields, vault-hint on missing secrets, quote returns valid shape, dry-run provision never hits network

Design decisions

  1. Native fetch only — no third-party libraries (consistent with PR feat: implement DigitalOcean cloud adapter with full REST API #29 DigitalOcean adapter)
  2. Plan caching — fetchPlans caches the plan list to avoid redundant API calls during quote→provision flow
  3. Price guardrail — maxHourlyPrice in InstanceSpec is enforced during plan selection
  4. Auto-detect resource type — destroy() and status() try multiple endpoints (instances, bare-metals, blocks, databases) since Vultr uses different endpoints per resource type
  5. Error messages — Vultr API error format is extracted and surfaced (not just status code)

Testing

Contract test passes with test credentials. Dry-run provision never hits the network. Real API calls require a valid VULTR_API_KEY.

Implements the full Vultr cloud adapter, replacing the existing stub
with working REST API calls using native fetch.

Ref: #6

Changes:

packages/cloud/vultr/src/index.ts:
- connect() — verifies VULTR_API_KEY via GET /v2/account, returns
  real account name and email
- quote() — fetches real pricing from GET /v2/plans, filters by
  region/kind/cpu/memory/storage, returns cheapest match
- provision() — four paths:
    - POST /v2/instances for VPS/GPU instances
    - POST /v2/bare-metals for bare metal servers
    - POST /v2/blocks for block storage
    - POST /v2/databases for managed DBs
- list() — GET /v2/instances + GET /v2/bare-metals with full mapping
- destroy() — tries instance/bare-metal/block/database DELETE
- status() — GET with auto-detection of resource type
- Smart plan picker — filters by region, kind, CPU, memory, storage,
  maxHourlyPrice guardrail
- Setup flow — tokenSetup with clear steps

packages/cloud/vultr/src/index.test.ts:
- Upgraded from smoke test to full contract test via contractTestCloud
- Tests: required fields, vault-hint on missing secrets, quote returns
  valid shape, dry-run provision never hits network

Design decisions:
1. Native fetch only — no third-party libraries
2. Plan caching — fetchPlans caches to avoid redundant API calls
3. Price guardrail — maxHourlyPrice enforced during plan selection
4. Error messages — Vultr API error format extracted and surfaced
5. Auto-detect resource type — destroy/status try multiple endpoints
@ralyodio
ralyodio merged commit 962742f into profullstack:master May 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants