Cua Docs

Configure run.cua.ai fleets with Terraform

Create Linux and Windows run.cua.ai fleets with the temporary local Cua Fleets provider installation.

Use this guide to create a run.cua.ai fleet backed by the public Cua Fleets provider. Terraform represents each fleet as a fleets_pool resource.

Prerequisites#

  • A run.cua.ai user key or access token with permission to manage Fleet pools. Keep credentials in environment variables or a secret manager, not in source control.
  • Terraform or OpenTofu and Go on the machine where you build the provider.
  • The temporary local provider installation from the public terraform-provider-fleets README.

The provider is not published to the Terraform Registry yet. Follow the public README to clone https://github.com/trycua/terraform-provider-fleets.git, build for your current OS and architecture, and configure its filesystem mirror. That flow installs a local binary; it is not Registry resolution. Replace this temporary setup with the normal Registry installation after trycua/fleets is published.

The provider source address remains trycua/fleets; do not use a GitHub URL in required_providers.source. Set the CLI configuration file created by the public README before initializing either example:

export TF_CLI_CONFIG_FILE="$HOME/.terraformrc-fleets-local"

For OpenTofu, run the same commands with tofu in place of terraform.

Authentication#

The provider accepts either CYCLOPS_ACCESS_TOKEN, or all three OAuth user-key variables: CYCLOPS_CLIENT_ID, CYCLOPS_CLIENT_SECRET, and CYCLOPS_TOKEN_URL. Configure the run.cua.ai endpoint separately:

export CYCLOPS_ENDPOINT="https://run.cua.ai"
export CYCLOPS_ACCESS_TOKEN="<your-access-token>"

Create a Linux fleet#

Create a new directory, save this as main.tf, and choose a unique lowercase DNS-label pool name. This example creates a KubeVirt Linux pool and exposes SSH.

main.tf
terraform {
  required_providers {
    fleets = {
      source  = "trycua/fleets"
      version = "1.0.0"
    }
  }
}
 
provider "fleets" {
  endpoint = "https://run.cua.ai"
}
 
resource "fleets_pool" "linux" {
  name                 = "linux-fleet"
  replicas             = 0
  cpu_cores            = 4
  memory               = "8Gi"
  container_disk_image = "296062593712.dkr.ecr.us-west-2.amazonaws.com/desktop-workspace-duo:main-38352d34"
  runtime              = "kubevirt"
  firmware             = "bios"
 
  service {
    name        = "ssh"
    target_port = 22
    protocol    = "TCP"
  }
 
  autoscaling {
    min_pool_size     = 0
    initial_pool_size = 1
    max_pool_size     = 5
  }
}
 
output "linux_fleet" {
  value = {
    name      = fleets_pool.linux.name
    namespace = fleets_pool.linux.namespace
    phase     = fleets_pool.linux.phase
  }
}

Create a Windows fleet#

Use a distinct name for Windows. The Windows computer-server image requires UEFI, so this example sets firmware = "efi" and waits for the service on port 8000.

main.tf
terraform {
  required_providers {
    fleets = {
      source  = "trycua/fleets"
      version = "1.0.0"
    }
  }
}
 
provider "fleets" {
  endpoint = "https://run.cua.ai"
}
 
resource "fleets_pool" "windows" {
  name                 = "windows-fleet"
  replicas             = 0
  cpu_cores            = 4
  memory               = "4Gi"
  container_disk_image = "296062593712.dkr.ecr.us-west-2.amazonaws.com/cua-server-windows:latest"
  runtime              = "kubevirt"
  firmware             = "efi"
 
  readiness_probe_json = jsonencode({
    tcpSocket           = { port = 8000 }
    initialDelaySeconds = 60
    periodSeconds       = 5
    timeoutSeconds      = 3
    failureThreshold    = 120
  })
 
  service {
    name        = "computer-server"
    target_port = 8000
    protocol    = "TCP"
  }
 
  autoscaling {
    min_pool_size     = 0
    initial_pool_size = 1
    max_pool_size     = 5
  }
}
 
output "windows_fleet" {
  value = {
    name      = fleets_pool.windows.name
    namespace = fleets_pool.windows.namespace
    phase     = fleets_pool.windows.phase
  }
}

Apply, verify, and destroy#

With TF_CLI_CONFIG_FILE still set, initialize from the local mirror and run one example:

rm -rf .terraform .terraform.lock.hcl
terraform init
terraform fmt -check
terraform validate
terraform plan
terraform apply
terraform output

terraform init uses the locally built provider and must not resolve trycua/fleets from the public Registry. The provider returns namespace, phase, total_count, available_count, and claimed_count. A ready fleet has available sandboxes after its warm pool provisions.

Destroy the pool when finished. This deletes both the pool and its same-named namespace:

terraform destroy

Troubleshooting and security#

  • Use a lowercase DNS label of at most 63 characters for name. Changing it replaces the pool because it also owns its namespace.
  • Check the image reference and image-pull-secret policy if creation returns 403. image_pull_secret defaults to ecr-credentials.
  • Use bios for the Linux workspace image and efi for the Windows computer-server image. A firmware mismatch prevents the guest from booting.
  • Protect Terraform state and shell history as operational secrets.