Go SDK — VMs
Virtual machines use ComputeServiceClient and
SSHKeysServiceClient. Create returns an
operation — poll until
SUCCEEDED. Configure clients per
Go SDK → Configure.
VM manifest
CreateVirtualMachine takes a
VirtualMachineManifest — the same schema the CLI flags and
YAML manifests map to.
metadata
| Field | Required | Description |
|---|---|---|
name | No | Hostname (DNS label, ≤63 chars). |
project | Yes* | projects/{slug} |
labels / annotations | No | Metadata maps. |
spec.region
Required. e.g. datacenters/us-dal-1.
spec.compute
| Field | Description |
|---|---|
cpuClass | cascadelake, milan, etc. |
vcpus | 1–64 |
ramGib | RAM in GiB |
gpu.model / gpu.count | Whole-GPU passthrough, e.g. rtx4090 |
spec.boot
Exactly one of image, imageUrl, or diskName.
| Field | Description |
|---|---|
image | Catalog id, e.g. ubuntu-24-04 |
diskGib | Boot disk size with image/imageUrl |
diskName | Existing disk as boot volume |
spec.network
| Field | Default | Description |
|---|---|---|
publicIpv4 | false | Opt-in public IPv4 (~$2/mo). IPv6 always on. |
network | auto | Tenant network; empty → default in DC. |
spec.users[]
| Field | Description |
|---|---|
name | Login user (not root) |
sshKeys | Registered key resource names |
sshPubkey | Inline public key line |
password | Console login password |
If cloudInit is set on spec, it replaces generated user config.
spec.billing
BILLING_MODE_HOURLY (default) or
BILLING_MODE_MONTHLY_1 through
BILLING_MODE_MONTHLY_12. Prepaid terms debit wallet at create.
Create a VM
resp, err := compute.CreateVirtualMachine(ctx, connect.NewRequest(
&computev1.CreateVirtualMachineRequest{
Manifest: &computev1.VirtualMachineManifest{
ApiVersion: "compute.metalhost.io/v1",
Kind: "VirtualMachine",
Metadata: &computev1.VirtualMachineMetadata{
Name: "web-1", Project: "projects/my-app",
},
Spec: &computev1.VirtualMachineSpec{
Region: "datacenters/us-dal-1",
Compute: &computev1.VMComputeSpec{
CpuClass: "cascadelake", Vcpus: 2, RamGib: 8,
},
Boot: &computev1.VMBootSpec{Image: "ubuntu-24-04", DiskGib: 80},
Network: &computev1.VMNetworkSpec{PublicIpv4: true},
Users: []*computev1.UserSpec{{
Name: "ubuntu",
SshKeys: []string{"projects/my-app/ssh-keys/laptop"},
}},
},
},
},
))
opName := resp.Msg.GetOperation().GetName()
Poll opName with OperationsService/GetOperation.
On success, metadata.virtual_machine_name is the full VM name.
Quote before create
catalog := catalogv1connect.NewCatalogServiceClient(httpClient, base)
resp, err := catalog.QuoteVirtualMachine(ctx, connect.NewRequest(
&catalogv1.QuoteVirtualMachineRequest{
Vcpus: 2, RamGib: 8, CpuClass: "cascadelake", BootDiskGib: 80,
AssignPublicIpv4: true,
},
)) SSH keys
Separate client — register before create:
keys := computev1connect.NewSSHKeysServiceClient(httpClient, base)
_, err := keys.CreateSSHKey(ctx, connect.NewRequest(&computev1.CreateSSHKeyRequest{
ProjectName: "projects/my-app",
SshKeyId: "laptop",
DisplayName: "Laptop",
PublicKey: "ssh-ed25519 AAAA... user@host",
})) List and get
list, _ := compute.ListVirtualMachines(ctx, connect.NewRequest(
&computev1.ListVirtualMachinesRequest{ProjectName: project, PageSize: 100},
))
one, _ := compute.GetVirtualMachine(ctx, connect.NewRequest(
&computev1.GetVirtualMachineRequest{Name: vm},
)) Lifecycle
Delete, resize, and clone also return operations:
vm := "projects/my-app/virtual-machines/web-1"
compute.StopVirtualMachine(ctx, connect.NewRequest(&computev1.StopVirtualMachineRequest{Name: vm}))
compute.StartVirtualMachine(ctx, connect.NewRequest(&computev1.StartVirtualMachineRequest{Name: vm}))
compute.RestartVirtualMachine(ctx, connect.NewRequest(&computev1.RestartVirtualMachineRequest{Name: vm}))
compute.ResizeVirtualMachine(ctx, connect.NewRequest(&computev1.ResizeVirtualMachineRequest{
Name: vm, Vcpus: 4, RamGib: 16, CpuClass: "cascadelake",
}))
compute.DeleteVirtualMachine(ctx, connect.NewRequest(&computev1.DeleteVirtualMachineRequest{Name: vm})) Snapshots and clone
compute.CreateVMSnapshot(ctx, connect.NewRequest(&computev1.CreateVMSnapshotRequest{
VirtualMachineName: vm,
DisplayName: "pre-upgrade",
}))
compute.CloneVirtualMachine(ctx, connect.NewRequest(&computev1.CloneVirtualMachineRequest{
SourceName: vm,
DisplayName: "web-1-copy",
})) Console
OpenConsole returns a short-lived URL for in-browser serial/VNC
access — same RPC the dashboard console uses.