Skip to content

Commit 52332cd

Browse files
Add google_dns_managed_zones data source and acceptance test (#9742) (#6835)
* Add `google_dns_managed_zones` data source and acceptance test * Stop skipping `TestAccDataSourceDnsManagedZones_basic` in VCR * Skip acceptance test affected by PF/VCR incompatibility * Edit schema to make sense for a plural data source * Update test to explicitly check for elements' fields being set [upstream:a2e592085964868c743b12e04cff008228baa851] Signed-off-by: Modular Magician <[email protected]>
1 parent 9c6c7d4 commit 52332cd

File tree

5 files changed

+334
-1
lines changed

5 files changed

+334
-1
lines changed

.changelog/9742.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note: new-datasource
2+
`google_dns_managed_zones`
3+
```

google-beta/fwprovider/framework_provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,7 @@ func (p *FrameworkProvider) DataSources(_ context.Context) []func() datasource.D
989989
resourcemanager.NewGoogleClientConfigDataSource,
990990
resourcemanager.NewGoogleClientOpenIDUserinfoDataSource,
991991
dns.NewGoogleDnsManagedZoneDataSource,
992+
dns.NewGoogleDnsManagedZonesDataSource,
992993
dns.NewGoogleDnsRecordSetDataSource,
993994
dns.NewGoogleDnsKeysDataSource,
994995
firebase.NewGoogleFirebaseAndroidAppConfigDataSource,

google-beta/services/dns/data_source_dns_managed_zone.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

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

11+
"github.com/hashicorp/terraform-plugin-framework/attr"
1112
"github.com/hashicorp/terraform-plugin-framework/datasource"
1213
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
1314
"github.com/hashicorp/terraform-plugin-framework/diag"
@@ -167,7 +168,7 @@ func (d *GoogleDnsManagedZoneDataSource) Read(ctx context.Context, req datasourc
167168
}
168169
}
169170

170-
tflog.Trace(ctx, "read dns record set data source")
171+
tflog.Trace(ctx, "read dns managed zone data source")
171172

172173
data.DnsName = types.StringValue(clientResp.DnsName)
173174
data.Description = types.StringValue(clientResp.Description)
@@ -182,3 +183,18 @@ func (d *GoogleDnsManagedZoneDataSource) Read(ctx context.Context, req datasourc
182183
// Save data into Terraform state
183184
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
184185
}
186+
187+
func getDnsManagedZoneAttrs() map[string]attr.Type {
188+
dnsManagedZoneAttrs := map[string]attr.Type{
189+
"name": types.StringType,
190+
"project": types.StringType,
191+
"dns_name": types.StringType,
192+
"description": types.StringType,
193+
"managed_zone_id": types.Int64Type,
194+
"name_servers": types.ListType{}.WithElementType(types.StringType),
195+
"visibility": types.StringType,
196+
"id": types.StringType,
197+
}
198+
199+
return dnsManagedZoneAttrs
200+
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package dns
4+
5+
import (
6+
"context"
7+
"fmt"
8+
9+
"google.golang.org/api/dns/v1"
10+
11+
"github.com/hashicorp/terraform-plugin-framework/datasource"
12+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
13+
"github.com/hashicorp/terraform-plugin-framework/diag"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
"github.com/hashicorp/terraform-plugin-log/tflog"
16+
17+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwmodels"
18+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwresource"
19+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwtransport"
20+
)
21+
22+
// Ensure the implementation satisfies the expected interfaces
23+
var (
24+
_ datasource.DataSource = &GoogleDnsManagedZonesDataSource{}
25+
_ datasource.DataSourceWithConfigure = &GoogleDnsManagedZonesDataSource{}
26+
)
27+
28+
func NewGoogleDnsManagedZonesDataSource() datasource.DataSource {
29+
return &GoogleDnsManagedZonesDataSource{}
30+
}
31+
32+
// GoogleDnsManagedZonesDataSource defines the data source implementation
33+
type GoogleDnsManagedZonesDataSource struct {
34+
client *dns.Service
35+
project types.String
36+
}
37+
38+
type GoogleDnsManagedZonesModel struct {
39+
Id types.String `tfsdk:"id"`
40+
Project types.String `tfsdk:"project"`
41+
ManagedZones types.List `tfsdk:"managed_zones"`
42+
}
43+
44+
func (d *GoogleDnsManagedZonesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
45+
resp.TypeName = req.ProviderTypeName + "_dns_managed_zones"
46+
}
47+
48+
func (d *GoogleDnsManagedZonesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
49+
50+
resp.Schema = schema.Schema{
51+
// This description is used by the documentation generator and the language server.
52+
MarkdownDescription: "Provides access to all zones for a given project within Google Cloud DNS",
53+
54+
Attributes: map[string]schema.Attribute{
55+
56+
"project": schema.StringAttribute{
57+
Description: "The ID of the project for the Google Cloud.",
58+
MarkdownDescription: "The ID of the project for the Google Cloud.",
59+
Optional: true,
60+
},
61+
62+
// Id field is added to match plugin-framework migrated google_dns_managed_zone data source
63+
// Whilst ID fields are required in the SDK, they're not needed in the plugin-framework.
64+
"id": schema.StringAttribute{
65+
Description: "foobar",
66+
MarkdownDescription: "foobar",
67+
Computed: true,
68+
},
69+
},
70+
71+
Blocks: map[string]schema.Block{
72+
"managed_zones": schema.ListNestedBlock{
73+
Description: "The list of managed zones in the given project.",
74+
MarkdownDescription: "The list of managed zones in the given project.",
75+
NestedObject: schema.NestedBlockObject{
76+
Attributes: map[string]schema.Attribute{
77+
"name": schema.StringAttribute{
78+
Description: "A unique name for the resource.",
79+
MarkdownDescription: "A unique name for the resource.",
80+
Computed: true,
81+
},
82+
83+
// Google Cloud DNS ManagedZone resources do not have a SelfLink attribute.
84+
"project": schema.StringAttribute{
85+
Description: "The ID of the project for the Google Cloud.",
86+
MarkdownDescription: "The ID of the project for the Google Cloud.",
87+
Computed: true,
88+
},
89+
90+
"dns_name": schema.StringAttribute{
91+
Description: "The fully qualified DNS name of this zone.",
92+
MarkdownDescription: "The fully qualified DNS name of this zone.",
93+
Computed: true,
94+
},
95+
96+
"description": schema.StringAttribute{
97+
Description: "A textual description field.",
98+
MarkdownDescription: "A textual description field.",
99+
Computed: true,
100+
},
101+
102+
"managed_zone_id": schema.Int64Attribute{
103+
Description: "Unique identifier for the resource; defined by the server.",
104+
MarkdownDescription: "Unique identifier for the resource; defined by the server.",
105+
Computed: true,
106+
},
107+
108+
"name_servers": schema.ListAttribute{
109+
Description: "The list of nameservers that will be authoritative for this " +
110+
"domain. Use NS records to redirect from your DNS provider to these names, " +
111+
"thus making Google Cloud DNS authoritative for this zone.",
112+
MarkdownDescription: "The list of nameservers that will be authoritative for this " +
113+
"domain. Use NS records to redirect from your DNS provider to these names, " +
114+
"thus making Google Cloud DNS authoritative for this zone.",
115+
Computed: true,
116+
ElementType: types.StringType,
117+
},
118+
119+
"visibility": schema.StringAttribute{
120+
Description: "The zone's visibility: public zones are exposed to the Internet, " +
121+
"while private zones are visible only to Virtual Private Cloud resources.",
122+
MarkdownDescription: "The zone's visibility: public zones are exposed to the Internet, " +
123+
"while private zones are visible only to Virtual Private Cloud resources.",
124+
Computed: true,
125+
},
126+
127+
"id": schema.StringAttribute{
128+
Description: "DNS managed zone identifier",
129+
MarkdownDescription: "DNS managed zone identifier",
130+
Computed: true,
131+
},
132+
},
133+
},
134+
},
135+
},
136+
}
137+
}
138+
139+
func (d *GoogleDnsManagedZonesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
140+
// Prevent panic if the provider has not been configured.
141+
if req.ProviderData == nil {
142+
return
143+
}
144+
145+
p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig)
146+
if !ok {
147+
resp.Diagnostics.AddError(
148+
"Unexpected Data Source Configure Type",
149+
fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData),
150+
)
151+
return
152+
}
153+
154+
d.client = p.NewDnsClient(p.UserAgent, &resp.Diagnostics)
155+
d.project = p.Project
156+
}
157+
158+
func (d *GoogleDnsManagedZonesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
159+
var data GoogleDnsManagedZonesModel
160+
var metaData *fwmodels.ProviderMetaModel
161+
var diags diag.Diagnostics
162+
163+
// Read Provider meta into the meta model
164+
resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metaData)...)
165+
if resp.Diagnostics.HasError() {
166+
return
167+
}
168+
169+
d.client.UserAgent = fwtransport.GenerateFrameworkUserAgentString(metaData, d.client.UserAgent)
170+
171+
// Read Terraform configuration data into the model
172+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
173+
if resp.Diagnostics.HasError() {
174+
return
175+
}
176+
177+
data.Project = fwresource.GetProjectFramework(data.Project, d.project, &resp.Diagnostics)
178+
if resp.Diagnostics.HasError() {
179+
return
180+
}
181+
182+
data.Id = types.StringValue(fmt.Sprintf("projects/%s/managedZones", data.Project.ValueString()))
183+
184+
tflog.Debug(ctx, fmt.Sprintf("fetching managed zones from project %s", data.Project.ValueString()))
185+
186+
clientResp, err := d.client.ManagedZones.List(data.Project.ValueString()).Do()
187+
if err != nil {
188+
fwtransport.HandleDatasourceNotFoundError(ctx, err, &resp.State, fmt.Sprintf("dataSourceDnsManagedZones %q", data.Project.ValueString()), &resp.Diagnostics)
189+
if resp.Diagnostics.HasError() {
190+
return
191+
}
192+
}
193+
194+
tflog.Trace(ctx, "read dns managed zones data source")
195+
196+
zones, di := flattenManagedZones(ctx, clientResp.ManagedZones, data.Project.ValueString())
197+
diags.Append(di...)
198+
199+
if len(zones) > 0 {
200+
mzObjType := types.ObjectType{}.WithAttributeTypes(getDnsManagedZoneAttrs())
201+
data.ManagedZones, di = types.ListValueFrom(ctx, mzObjType, zones)
202+
diags.Append(di...)
203+
}
204+
205+
resp.Diagnostics.Append(diags...)
206+
if resp.Diagnostics.HasError() {
207+
return
208+
}
209+
210+
// Save data into Terraform state
211+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
212+
}
213+
214+
func flattenManagedZones(ctx context.Context, managedZones []*dns.ManagedZone, project string) ([]types.Object, diag.Diagnostics) {
215+
var zones []types.Object
216+
var diags diag.Diagnostics
217+
218+
for _, zone := range managedZones {
219+
220+
data := GoogleDnsManagedZoneModel{
221+
// Id is not an API value but we assemble it here to match the google_dns_managed_zone data source
222+
// and fulfil the GoogleDnsManagedZoneModel's fields.
223+
// IDs are not required in the plugin-framework (vs the SDK)
224+
Id: types.StringValue(fmt.Sprintf("projects/%s/managedZones/%s", project, zone.Name)),
225+
Project: types.StringValue(project),
226+
227+
DnsName: types.StringValue(zone.DnsName),
228+
Name: types.StringValue(zone.Name),
229+
Description: types.StringValue(zone.Description),
230+
ManagedZoneId: types.Int64Value(int64(zone.Id)),
231+
Visibility: types.StringValue(zone.Visibility),
232+
}
233+
234+
data.NameServers, diags = types.ListValueFrom(ctx, types.StringType, zone.NameServers)
235+
diags.Append(diags...)
236+
237+
obj, d := types.ObjectValueFrom(ctx, getDnsManagedZoneAttrs(), data)
238+
diags.Append(d...)
239+
240+
zones = append(zones, obj)
241+
}
242+
243+
return zones, diags
244+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package dns_test
4+
5+
import (
6+
"fmt"
7+
"regexp"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
11+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest"
12+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar"
13+
)
14+
15+
func TestAccDataSourceDnsManagedZones_basic(t *testing.T) {
16+
t.Parallel()
17+
// TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158
18+
acctest.SkipIfVcr(t)
19+
20+
context := map[string]interface{}{
21+
"name-1": fmt.Sprintf("tf-test-zone-%s", acctest.RandString(t, 10)),
22+
"name-2": fmt.Sprintf("tf-test-zone-%s", acctest.RandString(t, 10)),
23+
}
24+
25+
project := envvar.GetTestProjectFromEnv()
26+
expectedId := fmt.Sprintf("projects/%s/managedZones", project)
27+
28+
acctest.VcrTest(t, resource.TestCase{
29+
PreCheck: func() { acctest.AccTestPreCheck(t) },
30+
CheckDestroy: testAccCheckDNSManagedZoneDestroyProducerFramework(t),
31+
Steps: []resource.TestStep{
32+
{
33+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
34+
Config: testAccDataSourceDnsManagedZones_basic(context),
35+
Check: resource.ComposeTestCheckFunc(
36+
resource.TestCheckResourceAttr("data.google_dns_managed_zones.qa", "id", expectedId),
37+
resource.TestMatchResourceAttr("data.google_dns_managed_zones.qa", "managed_zones.#", regexp.MustCompile("^[1-9]")), // Non-zero number length
38+
39+
// Checks below ensure that fields in the first element are set. We can't always make assertions about exact values.
40+
resource.TestCheckResourceAttr("data.google_dns_managed_zones.qa", "managed_zones.0.project", project),
41+
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.name"),
42+
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.dns_name"),
43+
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.managed_zone_id"),
44+
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.visibility"),
45+
resource.TestCheckResourceAttrSet("data.google_dns_managed_zones.qa", "managed_zones.0.id"),
46+
),
47+
},
48+
},
49+
})
50+
}
51+
52+
func testAccDataSourceDnsManagedZones_basic(context map[string]interface{}) string {
53+
return acctest.Nprintf(`
54+
resource "google_dns_managed_zone" "one" {
55+
name = "%{name-1}"
56+
dns_name = "%{name-1}.hashicorptest.com."
57+
description = "tf test DNS zone"
58+
}
59+
60+
resource "google_dns_managed_zone" "two" {
61+
name = "%{name-2}"
62+
dns_name = "%{name-2}.hashicorptest.com."
63+
description = "tf test DNS zone"
64+
}
65+
66+
data "google_dns_managed_zones" "qa" {
67+
}
68+
`, context)
69+
}

0 commit comments

Comments
 (0)