dnsimple / terraform-provider-dnsimple

Terraform DNSimple provider.
https://www.terraform.io/docs/providers/dnsimple/
Mozilla Public License 2.0
21 stars 20 forks source link

`dnsimple_record` to `dnsimple_zone_record` migration unhandled #162

Closed spkane closed 9 months ago

spkane commented 1 year ago

Hi there,

Thank you for opening an issue. Please note that we try to keep the Terraform issue tracker reserved for bug reports and feature requests. For general usage questions, please see: https://www.terraform.io/community.html.

Terraform Version

v1.5.7

Affected Resource(s)

It appears to affect all resources

Terraform Configuration Files

terraform {
  required_version = "~> 1.5"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.3"
    dnsimple = {
      source  = "dnsimple/dnsimple"
      version = "~> 1.3"
    }
  }
}

resource "dnsimple_zone_record" "archive" {
  zone_name = "foo.io"
  name      = "archive"
  value     = "c.storage.googleapis.com"
  type      = "CNAME"
  ttl       = 60
}

resource "dnsimple_zone_record" "domain-verification" {
  zone_name = data.googlesiteverification_dns_token.domain.domain
  name      = ""
  value     = data.googlesiteverification_dns_token.domain.record_value
  type      = data.googlesiteverification_dns_token.domain.record_type
  ttl       = 3600
}

Expected Behavior

The provider should have managed the state file alteration automatically or provided very clear directions about the issue and resolution.

Actual Behavior

 # dnsimple_zone_record.archive will be created
  + resource "dnsimple_zone_record" "archive" {
      + id             = (known after apply)
      + name           = "archive"
      + priority       = (known after apply)
      + qualified_name = (known after apply)
      + ttl            = 60
      + type           = "CNAME"
      + value          = "c.storage.googleapis.com"
      + zone_id        = (known after apply)
      + zone_name      = "foo.io"
    }

  # dnsimple_zone_record.domain-verification will be created
  + resource "dnsimple_zone_record" "domain-verification" {
      + id             = (known after apply)
      + priority       = (known after apply)
      + qualified_name = (known after apply)
      + ttl            = 3600
      + type           = "TXT"
      + value          = "google-site-verification=dfdsfdsfsdf"
      + zone_id        = (known after apply)
      + zone_name      = "foo.io"
    }

Plan: 2 to add, 1 to change, 0 to destroy.

│ Warning: Missing resource schema from provider
│
│ No resource schema found for dnsimple_record when decoding prior state
╵
╷
│ Warning: Missing resource schema from provider
│
│ No resource schema found for dnsimple_record when decoding prior state
╵
╷
│ Error: no schema available for dnsimple_record.domain-verification while reading state; this is a bug in Terraform and should be reported
│
│
╵
╷
│ Error: no schema available for dnsimple_record.archive while reading state; this is a bug in Terraform and should be reported
│
│

Steps to Reproduce

Please list the steps required to reproduce the issue:

  1. terraform apply
spkane commented 1 year ago

Ok, so a bit of added context here and then a workaround.

At some point in the past the dnsimple_record resource was renamed to dnssimple_zone_record and Terraform sees this as a completely new resource type and the provider does not handle this migration situation at all.

Using something like terraform state mv does not work:

terraform state mv dnsimple_record.archive dnsimple_zone_record.archive
╷
│ Error: Invalid state move request
│
│ Cannot move dnsimple_record.archive to dnsimple_zone_record.archive: resource types don't match.
╵

However, you can use a combination of terraform import and terraform state rm to workaround this, but this is not very maintainable for more than a few records requiring migration.

It would be very useful if the provider handled this in a more graceful manner.

spkane commented 1 year ago

In a second codebase that has a lot of records, I am trying to update to the dnsimple provider v0.16 before going to v1.3 to see if that can handle the migration in a clean fashion.

weppos commented 1 year ago

/cc @DXTimer

weppos commented 9 months ago

@DXTimer please provide an update as planned.

DXTimer commented 9 months ago

Thank you for your feedback, we could have indeed provided some suggestions on how to migrate when the resource was deprecated. Belatedly here is a suggestion on how one could go about it:

Overview

  1. Extract existing resource data
  2. Generate new resource configuration
  3. Import new resource into state and verify
  4. Remove old resources from state and from the configuration

Extract existing resource data

Create a script that reads the state of each dnsimple_record resource and extracts the necessary fields, storing them in a file for later use.

#!/bin/bash

# Extracting existing resource data
terraform show -json | jq -c '.values.root_module.resources[] | select(.type == "dnsimple_record")' > old_resources.json

Generate new resource configuration

Create a script to read the old resource data and generate new TF configuration for the dnsimple_zone_record resources.

#!/bin/bash

# Parsing the old resources file
cat old_resources.json | jq -c | while read -r resource; do
  # Extracting necessary fields
  id=$(echo "$resource" | jq -r '.values.id')
  name=$(echo "$resource" | jq -r '.values.name')
  type=$(echo "$resource" | jq -r '.values.type')
  value=$(echo "$resource" | jq -r '.values.value')
  ttl=$(echo "$resource" | jq -r '.values.ttl')
  zone_name=$(echo "$resource" | jq -r '.values.domain')  # 'domain' is the old field name
  resource_name=$(echo "$resource" | jq -r '.name')

  # Generating new resource configuration
  cat << EOF >> new_resources.tf
resource "dnsimple_zone_record" "${resource_name}" {
  zone_name = "${zone_name}"
  name      = "${name}"
  type      = "${type}"
  value     = "${value}"
  ttl       = ${ttl}
  # ... any other necessary fields ...
}
EOF
done

Import new resources into state and verify

Create a script that imports the old resources under the new resource.

#!/bin/bash

# Parsing the old resources file
cat old_resources.json | jq -c | while read -r resource; do
  # Extracting necessary fields
  id=$(echo "$resource" | jq -r '.values.id')
  zone_name=$(echo "$resource" | jq -r '.values.domain')  # 'domain' is the old field
  resource_name=$(echo "$resource" | jq -r '.name')

  terraform import dnsimple_zone_record.$resource_name ${zone_name}_$id
done

Remove old resources from state and from the configuration

Given the previous examples create a script to remove the resources from the state and then remove the configuration, and this would conclude the migration.

[!WARNING] I have not run the provided scripts in production, so please verify the outputs of each script should you choose to use them.