A Terraform provider for Cycle.io, the LowOps platform for containers and infrastructure. Manage clusters, environments, containers, scoped variables, DNS, image sources, hub membership, integrations, environment services, infrastructure, pipelines, and stacks as code.
Built with the Terraform Plugin Framework (protocol version 6) on top of Cycle's official Go API client.
- Terraform >= 1.0 (plugin protocol 6)
- Go >= 1.26 (to build from source)
- A Cycle hub and an API key with appropriate permissions
terraform {
required_providers {
cycle = {
source = "grailpay/cycle"
version = "~> 0.1"
}
}
}
provider "cycle" {
# Both may be omitted and provided via the CYCLE_API_KEY and
# CYCLE_HUB_ID environment variables instead.
api_key = var.cycle_api_key
hub_id = var.cycle_hub_id
}
resource "cycle_environment" "production" {
name = "Production"
cluster = "production"
description = "Managed by Terraform"
}Provider configuration:
| Attribute | Environment variable | Description |
|---|---|---|
api_key |
CYCLE_API_KEY |
Cycle API key (sensitive) |
hub_id |
CYCLE_HUB_ID |
ID of the hub to manage |
api_url |
— | API base URL, defaults to https://api.cycle.io |
cycle_cluster— infrastructure clusterscycle_environment— environments within a clustercycle_scoped_variable— environment scoped variables (env var / internal API / file access, secret values)cycle_dns_zone— hosted or linked DNS zonescycle_dns_record— records within a DNS zone (A, AAAA, CNAME, TXT, MX, LINKED, ...)cycle_image_source— image sources (Docker Hub, registries, OCI, stack builds)cycle_hub_role— custom hub roles with capabilitiescycle_hub_invite— invite users to the hub by emailcycle_hub_member— manage an existing hub member's rolecycle_hub_webhooks— hubserver_deployed/server_deletedwebhook URLscycle_load_balancer— environment load balancer service (reconfigure singleton)cycle_vpn— environment VPN service (reconfigure singleton)cycle_vpn_user— VPN accounts for an environmentcycle_server— provision a server into a clustercycle_external_volume— external volumescycle_autoscale_group— auto-scale groupscycle_pipeline— pipelines (stagesas JSON)cycle_pipeline_trigger_key— pipeline trigger keys (secret is computed + sensitive)cycle_stack— stacks from a git repo or raw speccycle_stack_build— create a stack build and wait until it is livecycle_integration— hub integrations (vendor auth + extra, secrets preserved)cycle_api_key— hub API keys (secret is computed + sensitive)cycle_container— containers (configas JSON; optionalstart_on_create)cycle_discovery_service— environment discovery service (reconfigure singleton)cycle_gateway_service— environment gateway service (reconfigure singleton)cycle_scheduler_service— environment scheduler service (reconfigure singleton)cycle_network— SDN networkscycle_tls_certificate— user-supplied TLS certificates (destroy deprecates)
cycle_hub— the current hubcycle_cluster,cycle_clusters,cycle_environment,cycle_environments,cycle_environment_deploymentscycle_dns_zone,cycle_dns_zones,cycle_dns_recordscycle_image,cycle_images,cycle_image_source,cycle_image_sourcescycle_hub_roles,cycle_hub_memberscycle_load_balancercycle_server,cycle_serverscycle_ip_pool,cycle_ip_pools,cycle_pool_ipscycle_external_volume,cycle_autoscale_groupcycle_provider_locations,cycle_provider_server_modelscycle_pipeline,cycle_pipelinescycle_stack,cycle_stacks,cycle_stack_build,cycle_stack_buildscycle_scoped_variable,cycle_scoped_variablescycle_vpn,cycle_vpn_userscycle_integration,cycle_integrations,cycle_available_integrationscycle_api_keyscycle_container,cycle_containerscycle_network,cycle_networkscycle_tls_certificates
Full documentation for every resource and data source lives in docs/ and is rendered on the Terraform Registry once published.
make build # builds ./terraform-provider-cycle
make install # go install into $GOPATH/binTo test a local build without publishing, add a dev_overrides block to ~/.terraformrc:
provider_installation {
dev_overrides {
"grailpay/cycle" = "/path/to/your/go/bin" # output of: go env GOPATH, plus /bin
}
direct {}
}Then run go install . and use the provider in any Terraform configuration — Terraform will print a warning that the override is in effect. Skip terraform init for the overridden provider; terraform plan/apply work directly.
Unit tests (no credentials required):
make testAcceptance tests run against a real Cycle hub and create, modify, and destroy real infrastructure (clusters, environments, DNS zones, invites, etc.). Costs may apply. Use a dedicated test hub, not production:
export CYCLE_API_KEY="your-api-key"
export CYCLE_HUB_ID="your-hub-id"
make testacc # runs: TF_ACC=1 go test ./... -v -timeout 120mDocs in docs/ are generated from the provider schema and the examples in examples/ using tfplugindocs:
make docsOne-time setup, then every release is just a git tag.
-
Create the GitHub repo
grailpay/terraform-provider-cyclewithmasteras the default branch, and push this repo to it:git remote add origin git@github.com:grailpay/terraform-provider-cycle.git git push -u origin master
-
Create a GPG signing key (if you don't already have one) and export it:
gpg --full-generate-key # RSA, no expiry is fine gpg --armor --export-secret-keys KEY_ID # private key, for GitHub secret gpg --armor --export KEY_ID # public key, for the registry
-
Add repo secrets (GitHub → Settings → Secrets and variables → Actions):
GPG_PRIVATE_KEY— the ASCII-armored private keyPASSPHRASE— the key's passphrase
-
Tag a release. The release workflow runs GoReleaser, which builds multi-platform binaries, signs the checksums, and creates a GitHub release:
git tag v0.1.0 git push origin v0.1.0
-
Publish on the registry (first release only): sign in to registry.terraform.io with GitHub, go to Publish → Provider, select
grailpay/terraform-provider-cycle, and upload the GPG public key. The registry ingests the tagged release automatically; subsequent tags appear without further manual steps.
Note
The registry requires the repository to contain an open source license file (most providers use MPL-2.0). Add a LICENSE file before publishing if one is not present.