Migrate from CDB Terraform provider v0 to v2
The CDB Terraform provider v2 is a complete rewrite generated from the CDB OpenAPI specification, covering more resources and using more consistent attribute names. Migrating from v0 to v2 requires manual configuration updates because the two versions use incompatible resource names, attribute names, and authentication configuration.
Before migrating
v2 uses api_key instead of permanent_api_token for authentication, adds a cloud_ prefix to all Cloud resource types, and changes the import ID separator from : to /. The reference tables for resource type renames and attribute changes are in the steps below where they are needed.
Resources without a v2 equivalent
The following v0 resources do not yet have a v2 equivalent. Keep them on v0, or manage them through the CDB Technical Web Portal and API until v2 support is added:
gcore_snapshotgcore_lifecyclepolicygcore_storage_s3/gcore_storage_s3_bucketgcore_storage_sftpgcore_faas_function/gcore_faas_key/gcore_faas_namespacegcore_laas_topicgcore_postgres_clustergcore_ddos_protectiongcore_port_security/gcore_port_allowed_address_pairsgcore_registry_credential
Projects using any of these resources cannot fully migrate to v2 today because running two provider versions in the same configuration is complex. Wait until v2 covers all required resources before migrating.
Migration approach
There is no automated migration tool, so the process is manual:
- Back up the current state file.
- Remove each resource from Terraform state (without deleting it from CDB).
- Update all
.tffiles to use v2 resource types and provider configuration. - Run
terraform init -upgradeto install the v2 provider. - Re-import each resource under its new v2 resource type.
- Run
terraform planand resolve any attribute drift.
The infrastructure itself is never recreated — only the Terraform resource type that tracks each existing CDB resource changes.
Migrate each resource
The steps below use an SSH key pair as a concrete case. Apply the same steps to every other resource in the project — only the resource type and import ID format differ.
Starting point: v0 configuration
The project has two files: providers.tf with the provider block and main.tf with a single SSH key resource.
providers.tf:
terraform {
required_version = ">= 0.13.0"
required_providers {
gcore = {
source = "G-Core/gcore"
version = "~> 0.34"
}
}
}
provider "gcore" {
permanent_api_token = var.api_token
}
main.tf:
resource "gcore_keypair" "demo" {
project_id = var.project_id
public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMzSiHhVTBaHerNPgRLHm+tQhvTtnOsZQEfgHMPmCxFZ demo"
sshkey_name = "terraform-migration-demo"
}
Before starting, verify what Terraform currently tracks. The id value from terraform state show is the import ID needed in Step 6:
$ terraform state list
gcore_keypair.demo
$ terraform state show gcore_keypair.demo
# gcore_keypair.demo:
resource "gcore_keypair" "demo" {
fingerprint = "11:b6:c5:77:48:14:82:9c:85:6b:80:46:b0:c8:7f:10"
id = "e82f4f48-9534-490e-bcf1-c164aae5255f"
project_id = 1186668
public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMzSiHhVTBaHerNPgRLHm+tQhvTtnOsZQEfgHMPmCxFZ demo"
sshkey_id = "e82f4f48-9534-490e-bcf1-c164aae5255f"
sshkey_name = "terraform-migration-demo"
}
- 1
Back up the state
Back up the state before making any changes. If something goes wrong during migration, restoring this backup returns Terraform to its v0 state without touching the actual infrastructure.
Copy the state file:
Copy-Item terraform.tfstate terraform.tfstate.v0backupTo restore, copy the backup back over the active state file:
Copy-Item terraform.tfstate.v0backup terraform.tfstate - 2
Remove resources from state
Run
terraform state listto see all tracked resources, then remove each one withterraform state rm. This removes resources from Terraform tracking only — the actual infrastructure in CDB is not affected.terraform state listgcore_keypair.demo gcore_network.main gcore_subnet.mainterraform state rm gcore_keypair.demo terraform state rm gcore_network.main terraform state rm gcore_subnet.main # repeat for every resource in the listEach removal confirms success:
Removed gcore_keypair.demo Successfully removed 1 resource instance(s).No CDB API calls are made and no infrastructure is affected.
terraform state rmmodifies only the Terraform state — local file or remote backend — not the actual resources. - 3
Update providers.tf
Replace the v0 provider block with v2:
v0:
terraform { required_version = ">= 0.13.0" required_providers { gcore = { source = "G-Core/gcore" version = "~> 0.34" } } } provider "gcore" { permanent_api_token = var.api_token }v2:
terraform { required_version = ">= 1.11" required_providers { gcore = { source = "G-Core/gcore" version = "~> 2.0" } } } provider "gcore" { api_key = var.api_key }The latest v2 release is listed on the Terraform Registry.
Also update the variable that holds the token. If
var.api_tokenwas used in v0, rename it tovar.api_key(or keep the existing name — the variable name is flexible; only the provider attribute must change toapi_key).To use an environment variable instead, update the name:
# v0: $env:GCORE_PERMANENT_TOKEN = "YOUR_TOKEN" # v2: $env:GCORE_API_KEY = "YOUR_TOKEN" - 4
Update resource blocks in .tf files
Rename each resource type and update attributes that changed. Use the reference tables to find the v2 name for every v0 resource type and attribute.
SSH key — resource type and
sshkey_namerenamed toname:# v0 resource "gcore_keypair" "demo" { project_id = var.project_id public_key = "ssh-ed25519 AAAA... demo" sshkey_name = "terraform-migration-demo" } # v2 — resource type and sshkey_name → name resource "gcore_cloud_ssh_key" "demo" { project_id = var.project_id public_key = "ssh-ed25519 AAAA... demo" name = "terraform-migration-demo" }Network — only the resource type changes, all attributes remain the same:
# v0 resource "gcore_network" "main" { name = "production" type = "vxlan" region_id = var.region_id project_id = var.project_id } # v2 — only the resource type changes; all attributes remain the same resource "gcore_cloud_network" "main" { name = "production" type = "vxlan" region_id = var.region_id project_id = var.project_id }All cross-resource references must reflect the rename — a subnet that referenced
gcore_network.main.idnow referencesgcore_cloud_network.main.id. - 5
Run terraform init -upgrade
Install the v2 provider:
terraform init -upgradeInitializing provider plugins found in the configuration... - Finding g-core/gcore versions matching "~> 2.0"... - Installing g-core/gcore v2.0.0... - Installed g-core/gcore v2.0.0 (signed by a HashiCorp partner, key ID 7DC84F37C1A1C035) ... Terraform has been successfully initialized! - 6
Import each resource under v2
The resource ID is the same UUID the resource had in v0 — find it in the state backup created in Step 1 by looking for the
"id"field, or in the Customer Portal URL. Useterraform importwith the v2 format (/separator instead of:for Cloud resources):terraform import gcore_cloud_ssh_key.demo '1186668/e82f4f48-9534-490e-bcf1-c164aae5255f'gcore_cloud_ssh_key.demo: Importing from ID "1186668/e82f4f48-9534-490e-bcf1-c164aae5255f"... gcore_cloud_ssh_key.demo: Import prepared! Prepared gcore_cloud_ssh_key for import gcore_cloud_ssh_key.demo: Refreshing state... [id=e82f4f48-9534-490e-bcf1-c164aae5255f] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.Repeat for every resource in the project.
Import ID formats for common Cloud resources
v2 resource Import ID format gcore_cloud_ssh_key<project_id>/<ssh_key_id>gcore_cloud_network<project_id>/<region_id>/<network_id>gcore_cloud_network_subnet<project_id>/<region_id>/<subnet_id>gcore_cloud_instance<project_id>/<region_id>/<instance_id>gcore_cloud_volume<project_id>/<region_id>/<volume_id>gcore_cloud_load_balancer<project_id>/<region_id>/<lb_id>gcore_cloud_k8s_cluster<project_id>/<region_id>/<cluster_id>gcore_cloud_security_group<project_id>/<region_id>/<sg_id>gcore_cloud_floating_ip<project_id>/<region_id>/<fip_id>gcore_cloud_reserved_fixed_ip<project_id>/<region_id>/<rfip_id>Verify the exact format in the Import section of each resource's page on Terraform Registry.
- 7
Run terraform plan
After importing all resources, run
terraform planto check for attribute drift — differences between the imported state and the local configuration:terraform planIf migration is complete and all attributes match:
gcore_cloud_ssh_key.demo: Refreshing state... [id=e82f4f48-9534-490e-bcf1-c164aae5255f] No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.If
terraform planshows changes, the resource block in the.tffile has attributes whose values do not match what the CDB API returned after import. Update those attributes untilterraform planreports no changes. Common causes:- An attribute set in v0 has a different name in v2 (see the attribute rename table above).
- A v2 computed attribute is now read-only and must be removed from the resource block.
- A v0 attribute was silently ignored but v2 enforces it strictly.
Do not run
terraform applyuntilterraform planshows no unintended changes. Applying a plan with unexpected changes may modify or destroy live infrastructure.
Migrating data sources
Data source types also changed. Update all data blocks alongside the resource blocks:
Data sources do not have state entries, so they do not need to be removed from state or re-imported. Rename them in the .tf files and update any references.