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 google_dns_managed_zones data source and acceptance test #6835

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
3 changes: 3 additions & 0 deletions .changelog/9742.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note: new-datasource
`google_dns_managed_zones`
```
1 change: 1 addition & 0 deletions google-beta/fwprovider/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,7 @@ func (p *FrameworkProvider) DataSources(_ context.Context) []func() datasource.D
resourcemanager.NewGoogleClientConfigDataSource,
resourcemanager.NewGoogleClientOpenIDUserinfoDataSource,
dns.NewGoogleDnsManagedZoneDataSource,
dns.NewGoogleDnsManagedZonesDataSource,
dns.NewGoogleDnsRecordSetDataSource,
dns.NewGoogleDnsKeysDataSource,
firebase.NewGoogleFirebaseAndroidAppConfigDataSource,
Expand Down
18 changes: 17 additions & 1 deletion google-beta/services/dns/data_source_dns_managed_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"google.golang.org/api/dns/v1"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
Expand Down Expand Up @@ -167,7 +168,7 @@ func (d *GoogleDnsManagedZoneDataSource) Read(ctx context.Context, req datasourc
}
}

tflog.Trace(ctx, "read dns record set data source")
tflog.Trace(ctx, "read dns managed zone data source")

data.DnsName = types.StringValue(clientResp.DnsName)
data.Description = types.StringValue(clientResp.Description)
Expand All @@ -182,3 +183,18 @@ func (d *GoogleDnsManagedZoneDataSource) Read(ctx context.Context, req datasourc
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func getDnsManagedZoneAttrs() map[string]attr.Type {
dnsManagedZoneAttrs := map[string]attr.Type{
"name": types.StringType,
"project": types.StringType,
"dns_name": types.StringType,
"description": types.StringType,
"managed_zone_id": types.Int64Type,
"name_servers": types.ListType{}.WithElementType(types.StringType),
"visibility": types.StringType,
"id": types.StringType,
}

return dnsManagedZoneAttrs
}
244 changes: 244 additions & 0 deletions google-beta/services/dns/data_source_dns_managed_zones.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package dns

import (
"context"
"fmt"

"google.golang.org/api/dns/v1"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"

"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwmodels"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwresource"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwtransport"
)

// Ensure the implementation satisfies the expected interfaces
var (
_ datasource.DataSource = &GoogleDnsManagedZonesDataSource{}
_ datasource.DataSourceWithConfigure = &GoogleDnsManagedZonesDataSource{}
)

func NewGoogleDnsManagedZonesDataSource() datasource.DataSource {
return &GoogleDnsManagedZonesDataSource{}
}

// GoogleDnsManagedZonesDataSource defines the data source implementation
type GoogleDnsManagedZonesDataSource struct {
client *dns.Service
project types.String
}

type GoogleDnsManagedZonesModel struct {
Id types.String `tfsdk:"id"`
Project types.String `tfsdk:"project"`
ManagedZones types.List `tfsdk:"managed_zones"`
}

func (d *GoogleDnsManagedZonesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_dns_managed_zones"
}

func (d *GoogleDnsManagedZonesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {

resp.Schema = schema.Schema{
// This description is used by the documentation generator and the language server.
MarkdownDescription: "Provides access to all zones for a given project within Google Cloud DNS",

Attributes: map[string]schema.Attribute{

"project": schema.StringAttribute{
Description: "The ID of the project for the Google Cloud.",
MarkdownDescription: "The ID of the project for the Google Cloud.",
Optional: true,
},

// Id field is added to match plugin-framework migrated google_dns_managed_zone data source
// Whilst ID fields are required in the SDK, they're not needed in the plugin-framework.
"id": schema.StringAttribute{
Description: "foobar",
MarkdownDescription: "foobar",
Computed: true,
},
},

Blocks: map[string]schema.Block{
"managed_zones": schema.ListNestedBlock{
Description: "The list of managed zones in the given project.",
MarkdownDescription: "The list of managed zones in the given project.",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Description: "A unique name for the resource.",
MarkdownDescription: "A unique name for the resource.",
Computed: true,
},

// Google Cloud DNS ManagedZone resources do not have a SelfLink attribute.
"project": schema.StringAttribute{
Description: "The ID of the project for the Google Cloud.",
MarkdownDescription: "The ID of the project for the Google Cloud.",
Computed: true,
},

"dns_name": schema.StringAttribute{
Description: "The fully qualified DNS name of this zone.",
MarkdownDescription: "The fully qualified DNS name of this zone.",
Computed: true,
},

"description": schema.StringAttribute{
Description: "A textual description field.",
MarkdownDescription: "A textual description field.",
Computed: true,
},

"managed_zone_id": schema.Int64Attribute{
Description: "Unique identifier for the resource; defined by the server.",
MarkdownDescription: "Unique identifier for the resource; defined by the server.",
Computed: true,
},

"name_servers": schema.ListAttribute{
Description: "The list of nameservers that will be authoritative for this " +
"domain. Use NS records to redirect from your DNS provider to these names, " +
"thus making Google Cloud DNS authoritative for this zone.",
MarkdownDescription: "The list of nameservers that will be authoritative for this " +
"domain. Use NS records to redirect from your DNS provider to these names, " +
"thus making Google Cloud DNS authoritative for this zone.",
Computed: true,
ElementType: types.StringType,
},

"visibility": schema.StringAttribute{
Description: "The zone's visibility: public zones are exposed to the Internet, " +
"while private zones are visible only to Virtual Private Cloud resources.",
MarkdownDescription: "The zone's visibility: public zones are exposed to the Internet, " +
"while private zones are visible only to Virtual Private Cloud resources.",
Computed: true,
},

"id": schema.StringAttribute{
Description: "DNS managed zone identifier",
MarkdownDescription: "DNS managed zone identifier",
Computed: true,
},
},
},
},
},
}
}

func (d *GoogleDnsManagedZonesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

d.client = p.NewDnsClient(p.UserAgent, &resp.Diagnostics)
d.project = p.Project
}

func (d *GoogleDnsManagedZonesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data GoogleDnsManagedZonesModel
var metaData *fwmodels.ProviderMetaModel
var diags diag.Diagnostics

// Read Provider meta into the meta model
resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metaData)...)
if resp.Diagnostics.HasError() {
return
}

d.client.UserAgent = fwtransport.GenerateFrameworkUserAgentString(metaData, d.client.UserAgent)

// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

data.Project = fwresource.GetProjectFramework(data.Project, d.project, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

data.Id = types.StringValue(fmt.Sprintf("projects/%s/managedZones", data.Project.ValueString()))

tflog.Debug(ctx, fmt.Sprintf("fetching managed zones from project %s", data.Project.ValueString()))

clientResp, err := d.client.ManagedZones.List(data.Project.ValueString()).Do()
if err != nil {
fwtransport.HandleDatasourceNotFoundError(ctx, err, &resp.State, fmt.Sprintf("dataSourceDnsManagedZones %q", data.Project.ValueString()), &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
}

tflog.Trace(ctx, "read dns managed zones data source")

zones, di := flattenManagedZones(ctx, clientResp.ManagedZones, data.Project.ValueString())
diags.Append(di...)

if len(zones) > 0 {
mzObjType := types.ObjectType{}.WithAttributeTypes(getDnsManagedZoneAttrs())
data.ManagedZones, di = types.ListValueFrom(ctx, mzObjType, zones)
diags.Append(di...)
}

resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func flattenManagedZones(ctx context.Context, managedZones []*dns.ManagedZone, project string) ([]types.Object, diag.Diagnostics) {
var zones []types.Object
var diags diag.Diagnostics

for _, zone := range managedZones {

data := GoogleDnsManagedZoneModel{
// Id is not an API value but we assemble it here to match the google_dns_managed_zone data source
// and fulfil the GoogleDnsManagedZoneModel's fields.
// IDs are not required in the plugin-framework (vs the SDK)
Id: types.StringValue(fmt.Sprintf("projects/%s/managedZones/%s", project, zone.Name)),
Project: types.StringValue(project),

DnsName: types.StringValue(zone.DnsName),
Name: types.StringValue(zone.Name),
Description: types.StringValue(zone.Description),
ManagedZoneId: types.Int64Value(int64(zone.Id)),
Visibility: types.StringValue(zone.Visibility),
}

data.NameServers, diags = types.ListValueFrom(ctx, types.StringType, zone.NameServers)
diags.Append(diags...)

obj, d := types.ObjectValueFrom(ctx, getDnsManagedZoneAttrs(), data)
diags.Append(d...)

zones = append(zones, obj)
}

return zones, diags
}
69 changes: 69 additions & 0 deletions google-beta/services/dns/data_source_dns_managed_zones_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package dns_test

import (
"fmt"
"regexp"
"testing"

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

func TestAccDataSourceDnsManagedZones_basic(t *testing.T) {
t.Parallel()
// TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158
acctest.SkipIfVcr(t)

context := map[string]interface{}{
"name-1": fmt.Sprintf("tf-test-zone-%s", acctest.RandString(t, 10)),
"name-2": fmt.Sprintf("tf-test-zone-%s", acctest.RandString(t, 10)),
}

project := envvar.GetTestProjectFromEnv()
expectedId := fmt.Sprintf("projects/%s/managedZones", project)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
CheckDestroy: testAccCheckDNSManagedZoneDestroyProducerFramework(t),
Steps: []resource.TestStep{
{
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Config: testAccDataSourceDnsManagedZones_basic(context),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.google_dns_managed_zones.qa", "id", expectedId),
resource.TestMatchResourceAttr("data.google_dns_managed_zones.qa", "managed_zones.#", regexp.MustCompile("^[1-9]")), // Non-zero number length

// Checks below ensure that fields in the first element are set. We can't always make assertions about exact values.
resource.TestCheckResourceAttr("data.google_dns_managed_zones.qa", "managed_zones.0.project", project),
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.name"),
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.dns_name"),
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.managed_zone_id"),
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.visibility"),
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.id"),
),
},
},
})
}

func testAccDataSourceDnsManagedZones_basic(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_dns_managed_zone" "one" {
name = "%{name-1}"
dns_name = "%{name-1}.hashicorptest.com."
description = "tf test DNS zone"
}

resource "google_dns_managed_zone" "two" {
name = "%{name-2}"
dns_name = "%{name-2}.hashicorptest.com."
description = "tf test DNS zone"
}

data "google_dns_managed_zones" "qa" {
}
`, context)
}