Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add location field in DNS authorization resource. #9968

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions mmv1/products/certificatemanager/DnsAuthorization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

--- !ruby/object:Api::Resource
name: 'DnsAuthorization'
base_url: 'projects/{{project}}/locations/global/dnsAuthorizations'
create_url: 'projects/{{project}}/locations/global/dnsAuthorizations?dnsAuthorizationId={{name}}'
self_link: 'projects/{{project}}/locations/global/dnsAuthorizations/{{name}}'
base_url: 'projects/{{project}}/locations/{{location}}/dnsAuthorizations'
create_url: 'projects/{{project}}/locations/{{location}}/dnsAuthorizations?dnsAuthorizationId={{name}}'
self_link: 'projects/{{project}}/locations/{{location}}/dnsAuthorizations/{{name}}'
update_verb: :PATCH
update_mask: true
description: |
Expand All @@ -39,7 +39,9 @@ async: !ruby/object:Api::OpAsync
docs: !ruby/object:Provider::Terraform::Docs
autogen_async: true
import_format:
['projects/{{project}}/locations/global/dnsAuthorizations/{{name}}']
['projects/{{project}}/locations/{{location}}/dnsAuthorizations/{{name}}']
schema_version: 1
state_upgraders: true
examples:
- !ruby/object:Provider::Terraform::Examples
name: 'certificate_manager_dns_authorization_basic'
Expand All @@ -58,6 +60,13 @@ parameters:
Name of the resource; provided by the client when the resource is created.
The name must be 1-64 characters long, and match the regular expression [a-zA-Z][a-zA-Z0-9_-]* which means the first character must be a letter,
and all following characters must be a dash, underscore, letter or digit.
- !ruby/object:Api::Type::String
name: 'location'
description: |
The Certificate Manager location. If not specified, "global" is used.
default_value: global
immutable: true
url_param_only: true
properties:
- !ruby/object:Api::Type::String
name: 'description'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
resource "google_certificate_manager_dns_authorization" "<%= ctx[:primary_resource_id] %>" {
name = "<%= ctx[:vars]['dns_auth_name'] %>"
description = "The default dnss"
location = "global"
description = "The default dns"
domain = "<%= ctx[:vars]['subdomain'] %>.hashicorptest.com"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
func ResourceCertificateManagerDnsAuthorizationUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
log.Printf("[DEBUG] Attributes before migration: %#v", rawState)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that this log is not printed in while running the migration test, when it will be used?

Also what can I do to mimic a customer that has a configuration in an old version and then upgrades it? I didn't know how to define the resource to be in an older version.

I had an old journey with a similar change and you suggested some solutions for testing: #7661 (comment), I would appreciate if you could elaborate more on both of the mentioned solutions.

Copy link
Contributor

@SarahFrench SarahFrench Feb 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that this log is not printed in while running the migration test, when it will be used?

I ran your TestAccCertificateManagerDnsAuthorization_migration test locally with the environment variable TF_LOG set to "DEBUG" to make debug logs visible and I also didn't see the log. I believe this shows that the test isn't using the local code from mynewprovider - see other comment for suggested changes!

Also what can I do to mimic a customer that has a configuration in an old version and then upgrades it? I didn't know how to define the resource to be in an older version.

You can achieve this with the TestAccCertificateManagerDnsAuthorization_migration test (following the fix in my other comment). In that test what's happening is:

  1. the resource is being provisioned with the old version of the provider + the first config
  2. test verifies ability to import the resource using the old version of the provider
  3. the resource is being updated using the new version of the provider + the second config with updated description
  4. test verifies ability to import the resource using the new version of the provider

You could add further test steps if they were needed. For example you could insert a step between 2 and 3 of the steps above where you use the first config with the new provider and check that the plan is empty (the snippet below has ExpectNonEmptyPlan: false, implied). This would mimic a user just upgrading their provider version and not changing their config:

			{
				Config:            dnsAuthorizationResourceConfig(name),
				ProviderFactories: newVersion,
				PlanOnly:          true,
			},

// Version 0 didn't support location. Default it to global.
rawState["location"] = "global"
log.Printf("[DEBUG] Attributes after migration: %#v", rawState)
return rawState, nil
}

func resourceCertificateManagerDnsAuthorizationResourceV0() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"domain": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `A domain which is being authorized. A DnsAuthorization resource covers a
single domain and its wildcard, e.g. authorization for "example.com" can
be used to issue certificates for "example.com" and "*.example.com".`,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `Name of the resource; provided by the client when the resource is created.
The name must be 1-64 characters long, and match the regular expression [a-zA-Z][a-zA-Z0-9_-]* which means the first character must be a letter,
and all following characters must be a dash, underscore, letter or digit.`,
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: `A human-readable description of the resource.`,
},
"labels": {
Type: schema.TypeMap,
Optional: true,
Description: `Set of label tags associated with the DNS Authorization resource.

**Note**: This field is non-authoritative, and will only manage the labels present in your configuration.
Please refer to the field 'effective_labels' for all of the labels present on the resource.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
"dns_resource_record": {
Type: schema.TypeList,
Computed: true,
Description: `The structure describing the DNS Resource Record that needs to be added
to DNS configuration for the authorization to be usable by
certificate.`,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"data": {
Type: schema.TypeString,
Computed: true,
Description: `Data of the DNS Resource Record.`,
},
"name": {
Type: schema.TypeString,
Computed: true,
Description: `Fully qualified name of the DNS Resource Record.
E.g. '_acme-challenge.example.com'.`,
},
"type": {
Type: schema.TypeString,
Computed: true,
Description: `Type of the DNS Resource Record.`,
},
},
},
},
"effective_labels": {
Type: schema.TypeMap,
Computed: true,
Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
"terraform_labels": {
Type: schema.TypeMap,
Computed: true,
Description: `The combination of labels configured directly on the resource
and default labels configured on the provider.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package certificatemanager_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-google/google/acctest"
)

// Tests schema version migration by creating a dns authorization with an old version of the provider (5.15.0)
// and then updating it with the current version the provider.
func TestAccCertificateManagerDnsAuthorization_migration(t *testing.T) {
acctest.SkipIfVcr(t)
t.Parallel()
name := fmt.Sprintf("tf-test-%d", acctest.RandInt(t))

oldVersion := map[string]resource.ExternalProvider{
"google": {
VersionConstraint: "5.15.0", // a version that doesn't support location yet.
Source: "registry.terraform.io/hashicorp/google",
},
}
newVersion := map[string]func() (*schema.Provider, error){
"mynewprovider": func() (*schema.Provider, error) { return acctest.TestAccProviders["google"], nil },
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
CheckDestroy: testAccCheckCertificateManagerDnsAuthorizationDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: dnsAuthorizationResourceConfig(name),
ExternalProviders: oldVersion,
},
{
ResourceName: "google_certificate_manager_dns_authorization.default",
ImportState: true,
ImportStateVerifyIgnore: []string{"location"},
SarahFrench marked this conversation as resolved.
Show resolved Hide resolved
ExternalProviders: oldVersion,
},
{
Config: dnsAuthorizationResourceConfigUpdated(name),
ProviderFactories: newVersion,
},
{
ResourceName: "google_certificate_manager_dns_authorization.default",
ImportState: true,
ImportStateVerifyIgnore: []string{"location"},
ProviderFactories: newVersion,
},
},
})
}

func dnsAuthorizationResourceConfig(name string) string {
return fmt.Sprintf(`
resource "google_certificate_manager_dns_authorization" "default" {
name = "%s"
description = "The default dns"
domain = "domain.hashicorptest.com"
}
`, name)
}

func dnsAuthorizationResourceConfigUpdated(name string) string {
return fmt.Sprintf(`
provider "mynewprovider" {}

resource "google_certificate_manager_dns_authorization" "default" {
provider = mynewprovider
name = "%s"
description = "The migrated default dns"
domain = "domain.hashicorptest.com"
}
`, name)
}
Loading