Add project CLAUDE.md and rewrite README.md for current provider
Some checks failed
CI / build (push) Failing after 34s

- CLAUDE.md: architecture guide, conventions, type mapping quirks,
  build commands, and common pitfalls for AI-assisted development
- README.md: full resource/data source tables, quick start guide,
  environment variable configuration, and usage examples

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-16 02:11:28 -04:00
parent ef8fbd530b
commit 7dba96409f
2 changed files with 269 additions and 51 deletions

90
CLAUDE.md Normal file
View File

@@ -0,0 +1,90 @@
# CLAUDE.md — Project context for AI assistants
## Project Overview
Terraform provider for VirtFusion (virtualization management platform). Written in Go using the [Terraform Plugin Framework](https://developer.hashicorp.com/terraform/plugin/framework) (not the older SDKv2).
- **Registry address**: `registry.terraform.io/EZSCALE/virtfusion`
- **Git hosting**: `https://git.ezscale.cloud/EZSCALE/terraform-provider-virtfusion` (Gitea, not GitHub)
- **VirtFusion API**: Laravel-based REST API with Bearer token auth. API docs defined in `openapi.yaml`.
## Architecture
```
main.go # Entry point, provider server
internal/
client/
client.go # HTTP client constructor, endpoint normalization
request.go # HTTP methods (Get, Post, Put, Delete, GetAllPages)
types.go # API request/response struct definitions
errors.go # APIError type with status code helpers
provider/
provider.go # Provider config, resource/datasource registration,
# shared pagination helpers (resultsSchemaAttribute, resultsQueryParam)
resource_*.go # Managed resources (20 total)
data_source_*.go # Data sources (30 total)
```
## Key Conventions
### API Client
- All HTTP methods return `(json.RawMessage, error)` — raw JSON to be unmarshalled by the caller.
- `GetAllPages(ctx, path)` handles Laravel-style pagination automatically: fetches all pages, merges `data` arrays, returns a synthetic `{"data": [...]}` response. Use this for all list endpoints.
- Query parameters must be appended to the path string (e.g., `/servers?results=300`). The client splits path from query before calling `url.JoinPath` to avoid `%3F` encoding.
- List endpoints use `?results=N` to set page size (default 300 via `defaultResultsPerPage`).
### Data Sources
- List data sources use `GetAllPages` and expose an optional `results` attribute (default 300).
- Single-item data sources use `Get` and take a required `id` attribute.
- Server list responses use a flat structure; single server GET returns nested objects (`cpu.cores`, `settings.resources.memory`, etc.).
### Resources
- Server creation uses `ServerCreateRequest` (POST `/servers`) then separate PUT/POST calls for update-only attributes (name, CPU throttle, VNC, suspend, etc.).
- User resources are keyed by `ext_relation_id` (external relation ID), not numeric ID.
- **Security**: All user-supplied strings interpolated into URL paths MUST be wrapped with `url.PathEscape()`.
- **Sensitive attributes**: `api_token`, `password`, `token`, and auth token `url` fields must be marked `Sensitive: true` in schemas.
### API Type Mappings (known quirks)
- `ServerData.Suspended` is `bool` (API returns `true`/`false`, not `0`/`1`).
- `ServerData` uses `ownerId` (not `userId`) and nests resources under `cpu.cores`, `settings.resources.*`.
- `PackageData` uses `primaryStorage`, `primaryNetworkSpeedIn`, `primaryNetworkSpeedOut` (not `storage`, `networkSpeedInbound`, etc.).
- `IPBlockData.Type` is `int64` (4=IPv4, 6=IPv6). Gateway/netmask are nested under `ipv4`.
- Hypervisor group resources returns a paginated array of per-hypervisor entries, not a single aggregate object.
- API error bodies are truncated to 500 bytes in error messages to prevent leaking sensitive data.
## Build & Test
```bash
# Build
go build ./...
# Install locally (goes to $GOPATH/bin)
go install .
# Lint
golangci-lint run
# Run against live VirtFusion (read-only test)
# Requires ~/.terraformrc with dev_overrides and test/main.tf (gitignored)
cd test && terraform apply -auto-approve
```
## Environment Variables
- `VIRTFUSION_ENDPOINT` — API base URL (e.g., `https://cp.example.com` or `https://cp.example.com/api/v1`)
- `VIRTFUSION_API_TOKEN` — API bearer token
## CI/CD
Uses Gitea Actions (`.gitea/workflows/`). GoReleaser for binary releases (`.goreleaser.yml`).
## Common Pitfalls
- `url.JoinPath` encodes `?` as `%3F` — never put query params in the path argument. The client handles this by splitting at `?` first.
- The VirtFusion `/servers` endpoint caps at 20 results per page regardless of the `results` parameter. `GetAllPages` handles this transparently by fetching all pages.
- Don't use `json:"storage"` for package storage — the API field is `json:"primaryStorage"`.
- Single server GET and list server responses have different shapes. `ServerData` type handles both via optional nested pointer fields.

230
README.md
View File

@@ -1,73 +1,201 @@
# Virtfusion Terraform Provider # Terraform Provider for VirtFusion
<p style="color: red">NOTE: This is a work in progress and is not yet ready for production use.</p> A Terraform provider for managing [VirtFusion](https://virtfusion.com) virtualization platform resources. Automate server provisioning, user management, networking, and self-service billing through infrastructure as code.
## Requirements
## Overview - [Terraform](https://developer.hashicorp.com/terraform/install) >= 1.0
- [Go](https://golang.org/doc/install) >= 1.21 (for building from source)
- A VirtFusion control panel instance with API access
This is a Terraform provider for the Virtfusion API. It allows you to manage your Virtfusion resources using Terraform. ## Installation
# What can I do with this provider? ### From Release
Currently, you're able to manage the following resources: Download the appropriate binary from the [Releases](https://git.ezscale.cloud/EZSCALE/terraform-provider-virtfusion/releases) page and place it in your Terraform plugins directory.
* Create and delete virtual machines
* Create and delete SSH keys
# How do I use this provider? ### From Source
Below is an example of how to use this provider to create a virtual machine and an SSH key. ```bash
git clone https://git.ezscale.cloud/EZSCALE/terraform-provider-virtfusion.git
cd terraform-provider-virtfusion
go install .
```
Then configure `~/.terraformrc` for local development:
```hcl
provider_installation {
dev_overrides {
"registry.terraform.io/EZSCALE/virtfusion" = "/path/to/your/gopath/bin"
}
direct {}
}
```
## Quick Start
```hcl ```hcl
terraform { terraform {
required_providers { required_providers {
virtfusion = { virtfusion = {
source = "ezscale/virtfusion" source = "registry.terraform.io/EZSCALE/virtfusion"
version = "0.0.3"
} }
} }
} }
variable "virtfusion_api_token" {
type = string
sensitive = true
}
provider "virtfusion" { provider "virtfusion" {
endpoint = "virtfusion.example.com" endpoint = "https://cp.example.com"
api_token = "" api_token = var.virtfusion_api_token
}
variable "common" {
type = map(string)
default = {
hypervisor_id = 1
package_id = 12
user_id = 1
}
}
# Create a SSH key
resource "virtfusion_ssh" "key1" {
name = "My Test Key"
public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKWyBR+dk5M5MMfmH6Ss5QDSgcAvbCYu0DkqgPKH8O5T testkey@example.com"
user_id = var.common["user_id"]
}
# Create a server
resource "virtfusion_server" "node1" {
hypervisor_id = var.common["hypervisor_id"]
package_id = var.common["package_id"]
user_id = var.common["user_id"]
}
# Initialize the server with the OS we want, the SSH key we want, and the hostname we want.
resource "virtfusion_build" "node1" {
server_id = virtfusion_server.node1.id
name = "node1-demo"
hostname = "node1.example.com"
osid = 34
vnc = true
ipv6 = true
ssh_keys = [virtfusion_ssh.key1.id]
email = true
} }
``` ```
# How can I contribute? The provider can also be configured using environment variables:
If you'd like to contribute, please feel free to open a pull request. If you're unsure of what to work on, please check the issues tab for any open issues. ```bash
export VIRTFUSION_ENDPOINT="https://cp.example.com"
export VIRTFUSION_API_TOKEN="your-api-token"
```
## Usage Examples
### Create a user, SSH key, server, and build it
```hcl
resource "virtfusion_user" "customer" {
name = "Jane Doe"
email = "jane@example.com"
ext_relation_id = "cust-001"
}
resource "virtfusion_ssh_key" "key" {
user_id = virtfusion_user.customer.id
name = "deploy-key"
public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample deploy@example.com"
}
resource "virtfusion_server" "web" {
package_id = 19
user_id = virtfusion_user.customer.id
hypervisor_id = 8
}
resource "virtfusion_server_build" "web" {
server_id = virtfusion_server.web.id
name = "web-server"
hostname = "web.example.com"
osid = 13
vnc = true
ipv6 = true
ssh_keys = [virtfusion_ssh_key.key.id]
}
```
### Read infrastructure data
```hcl
data "virtfusion_servers" "all" {}
data "virtfusion_packages" "all" {}
data "virtfusion_hypervisors" "all" {}
output "server_count" {
value = length(data.virtfusion_servers.all.servers)
}
```
List data sources support a `results` parameter (default: 300) and automatically paginate through all pages:
```hcl
data "virtfusion_servers" "all" {
results = 100 # override per-page limit
}
```
## Resources
| Resource | Description |
|----------|-------------|
| `virtfusion_server` | Create and manage servers |
| `virtfusion_server_build` | Build (install OS on) a server |
| `virtfusion_server_firewall` | Manage server firewall rules |
| `virtfusion_server_ipv4` | Add IPv4 addresses to a server |
| `virtfusion_server_network_whitelist` | Manage network whitelist entries |
| `virtfusion_server_traffic_block` | Manage traffic blocks |
| `virtfusion_server_power_action` | Control server power state |
| `virtfusion_server_password_reset` | Reset server root password |
| `virtfusion_ssh_key` | Manage SSH keys |
| `virtfusion_user` | Manage users |
| `virtfusion_user_auth_token` | Generate user authentication tokens |
| `virtfusion_user_server_auth_token` | Generate server-scoped authentication tokens |
| `virtfusion_user_password_reset` | Reset user passwords |
| `virtfusion_ip_block_range` | Add IPv4 ranges to IP blocks |
| `virtfusion_self_service_credit` | Manage self-service billing credits |
| `virtfusion_self_service_resource_pack` | Manage resource packs |
| `virtfusion_self_service_hourly_group_profile` | Manage hourly billing group profiles |
| `virtfusion_self_service_hourly_resource_pack` | Manage hourly resource packs |
| `virtfusion_self_service_resource_group_profile` | Manage resource group profiles |
| `virtfusion_self_service_pack_servers_action` | Suspend/unsuspend/delete pack servers |
## Data Sources
| Data Source | Description |
|-------------|-------------|
| `virtfusion_server` | Read a single server by ID |
| `virtfusion_servers` | List all servers |
| `virtfusion_servers_by_user` | List servers owned by a user |
| `virtfusion_server_backups` | List server backups |
| `virtfusion_server_firewall` | Read server firewall configuration |
| `virtfusion_server_templates` | List available templates for a server |
| `virtfusion_server_traffic` | Read server traffic usage |
| `virtfusion_server_traffic_blocks` | List server traffic blocks |
| `virtfusion_server_vnc` | Get VNC connection info |
| `virtfusion_hypervisor` | Read a single hypervisor |
| `virtfusion_hypervisors` | List all hypervisors |
| `virtfusion_hypervisor_group` | Read a single hypervisor group |
| `virtfusion_hypervisor_groups` | List all hypervisor groups |
| `virtfusion_hypervisor_group_resources` | Read aggregated resources for a group |
| `virtfusion_package` | Read a single package |
| `virtfusion_packages` | List all packages |
| `virtfusion_package_templates` | List templates for a package |
| `virtfusion_ip_block` | Read a single IP block |
| `virtfusion_ip_blocks` | List all IP blocks |
| `virtfusion_ssh_key` | Read a single SSH key |
| `virtfusion_ssh_keys_by_user` | List SSH keys for a user |
| `virtfusion_user` | Read a user by external relation ID |
| `virtfusion_dns_service` | Read DNS service configuration |
| `virtfusion_iso` | Read ISO media info |
| `virtfusion_queue_item` | Read a queue item status |
| `virtfusion_self_service_currencies` | List available currencies |
| `virtfusion_self_service_resource_pack` | Read a resource pack |
| `virtfusion_self_service_hourly_stats` | Read hourly billing stats |
| `virtfusion_self_service_report` | Read self-service reports |
| `virtfusion_self_service_usage` | Read self-service usage |
## Development
### Build
```bash
go build ./...
```
### Install locally
```bash
go install .
```
### Run linter
```bash
golangci-lint run
```
## License
[MPL-2.0](LICENSE)