Skip to content

Commit 09e574a

Browse files
committed
Add type awareness to import block generating
1 parent 33e8faf commit 09e574a

File tree

4 files changed

+237
-1
lines changed

4 files changed

+237
-1
lines changed

helper/resource/importstate/examplecloud_test.go

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,162 @@ func examplecloudZoneRecord() testprovider.Resource {
231231
},
232232
}
233233
}
234+
235+
func examplecloudResourceWithEveryIdentitySchemaType() testprovider.Resource {
236+
return testprovider.Resource{
237+
CreateResponse: &resource.CreateResponse{
238+
NewState: tftypes.NewValue(
239+
tftypes.Object{
240+
AttributeTypes: map[string]tftypes.Type{
241+
"hostname": tftypes.String,
242+
"cabinet": tftypes.String,
243+
"unit": tftypes.Number,
244+
"active": tftypes.Bool,
245+
"tags": tftypes.List{ElementType: tftypes.String},
246+
},
247+
},
248+
map[string]tftypes.Value{
249+
"hostname": tftypes.NewValue(tftypes.String, "mail.example.net"),
250+
"cabinet": tftypes.NewValue(tftypes.String, "A1"),
251+
"unit": tftypes.NewValue(tftypes.Number, 14),
252+
"active": tftypes.NewValue(tftypes.Bool, true),
253+
"tags": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "storage"), tftypes.NewValue(tftypes.String, "fast")}),
254+
},
255+
),
256+
NewIdentity: teststep.Pointer(tftypes.NewValue(
257+
tftypes.Object{
258+
AttributeTypes: map[string]tftypes.Type{
259+
"cabinet": tftypes.String,
260+
"unit": tftypes.Number,
261+
"active": tftypes.Bool,
262+
"tags": tftypes.List{ElementType: tftypes.String},
263+
},
264+
},
265+
map[string]tftypes.Value{
266+
"cabinet": tftypes.NewValue(tftypes.String, "A1"),
267+
"unit": tftypes.NewValue(tftypes.Number, 14),
268+
"active": tftypes.NewValue(tftypes.Bool, true),
269+
"tags": tftypes.NewValue(
270+
tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
271+
tftypes.NewValue(tftypes.String, "storage"),
272+
tftypes.NewValue(tftypes.String, "fast"),
273+
}),
274+
},
275+
)),
276+
},
277+
ReadResponse: &resource.ReadResponse{
278+
NewState: tftypes.NewValue(
279+
tftypes.Object{
280+
AttributeTypes: map[string]tftypes.Type{
281+
"hostname": tftypes.String,
282+
"cabinet": tftypes.String,
283+
"unit": tftypes.Number,
284+
"active": tftypes.Bool,
285+
"tags": tftypes.List{ElementType: tftypes.String},
286+
},
287+
},
288+
map[string]tftypes.Value{
289+
"hostname": tftypes.NewValue(tftypes.String, "mail.example.net"),
290+
"cabinet": tftypes.NewValue(tftypes.String, "A1"),
291+
"unit": tftypes.NewValue(tftypes.Number, 14),
292+
"active": tftypes.NewValue(tftypes.Bool, true),
293+
"tags": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "storage"), tftypes.NewValue(tftypes.String, "fast")}),
294+
},
295+
),
296+
NewIdentity: teststep.Pointer(tftypes.NewValue(
297+
tftypes.Object{
298+
AttributeTypes: map[string]tftypes.Type{
299+
"cabinet": tftypes.String,
300+
"unit": tftypes.Number,
301+
"active": tftypes.Bool,
302+
"tags": tftypes.List{ElementType: tftypes.String},
303+
},
304+
},
305+
map[string]tftypes.Value{
306+
"cabinet": tftypes.NewValue(tftypes.String, "A1"),
307+
"unit": tftypes.NewValue(tftypes.Number, 14),
308+
"active": tftypes.NewValue(tftypes.Bool, true),
309+
"tags": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "storage"), tftypes.NewValue(tftypes.String, "fast")}),
310+
},
311+
)),
312+
},
313+
ImportStateResponse: &resource.ImportStateResponse{
314+
State: tftypes.NewValue(
315+
tftypes.Object{
316+
AttributeTypes: map[string]tftypes.Type{
317+
"hostname": tftypes.String,
318+
"cabinet": tftypes.String,
319+
"unit": tftypes.Number,
320+
"active": tftypes.Bool,
321+
"tags": tftypes.List{ElementType: tftypes.String},
322+
},
323+
},
324+
map[string]tftypes.Value{
325+
"hostname": tftypes.NewValue(tftypes.String, "mail.example.net"),
326+
"cabinet": tftypes.NewValue(tftypes.String, "A1"),
327+
"unit": tftypes.NewValue(tftypes.Number, 14),
328+
"active": tftypes.NewValue(tftypes.Bool, true),
329+
"tags": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "storage"), tftypes.NewValue(tftypes.String, "fast")}),
330+
},
331+
),
332+
Identity: teststep.Pointer(tftypes.NewValue(
333+
tftypes.Object{
334+
AttributeTypes: map[string]tftypes.Type{
335+
"cabinet": tftypes.String,
336+
"unit": tftypes.Number,
337+
"active": tftypes.Bool,
338+
"tags": tftypes.List{ElementType: tftypes.String},
339+
},
340+
},
341+
map[string]tftypes.Value{
342+
"cabinet": tftypes.NewValue(tftypes.String, "A1"),
343+
"unit": tftypes.NewValue(tftypes.Number, 14),
344+
"active": tftypes.NewValue(tftypes.Bool, true),
345+
"tags": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "storage"), tftypes.NewValue(tftypes.String, "fast")}),
346+
},
347+
)),
348+
},
349+
SchemaResponse: &resource.SchemaResponse{
350+
Schema: &tfprotov6.Schema{
351+
Block: &tfprotov6.SchemaBlock{
352+
Attributes: []*tfprotov6.SchemaAttribute{
353+
ComputedStringAttribute("hostname"),
354+
RequiredStringAttribute("cabinet"),
355+
RequiredNumberAttribute("unit"),
356+
RequiredBoolAttribute("active"),
357+
RequiredListAttribute("tags", tftypes.String),
358+
},
359+
},
360+
},
361+
},
362+
IdentitySchemaResponse: &resource.IdentitySchemaResponse{
363+
Schema: &tfprotov6.ResourceIdentitySchema{
364+
Version: 1,
365+
IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{
366+
{
367+
Name: "cabinet",
368+
Type: tftypes.String,
369+
RequiredForImport: true,
370+
},
371+
{
372+
Name: "unit",
373+
Type: tftypes.Number,
374+
OptionalForImport: true,
375+
},
376+
{
377+
Name: "active",
378+
Type: tftypes.Bool,
379+
OptionalForImport: true,
380+
},
381+
{
382+
Name: "tags",
383+
Type: tftypes.List{
384+
ElementType: tftypes.String,
385+
},
386+
OptionalForImport: true,
387+
},
388+
},
389+
},
390+
},
391+
}
392+
}

helper/resource/importstate/import_block_with_resource_identity_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,39 @@ func TestImportBlock_WithResourceIdentity(t *testing.T) {
4747
})
4848
}
4949

50+
func TestImportBlock_WithResourceIdentity_WithEveryType(t *testing.T) {
51+
t.Parallel()
52+
53+
r.UnitTest(t, r.TestCase{
54+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
55+
tfversion.SkipBelow(tfversion.Version1_12_0), // ImportBlockWithResourceIdentity requires Terraform 1.12.0 or later
56+
},
57+
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
58+
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
59+
Resources: map[string]testprovider.Resource{
60+
"examplecloud_container": examplecloudResourceWithEveryIdentitySchemaType(),
61+
},
62+
}),
63+
},
64+
Steps: []r.TestStep{
65+
{
66+
Config: `
67+
resource "examplecloud_container" "test" {
68+
cabinet = "A1"
69+
unit = 14
70+
tags = ["storage", "fast"]
71+
active = true
72+
}`,
73+
},
74+
{
75+
ResourceName: "examplecloud_container.test",
76+
ImportState: true,
77+
ImportStateKind: r.ImportBlockWithResourceIdentity,
78+
},
79+
},
80+
})
81+
}
82+
5083
func TestImportBlock_WithResourceIdentity_RequiresVersion1_12_0(t *testing.T) {
5184
t.Parallel()
5285

helper/resource/importstate/types_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@ import (
88
"github.com/hashicorp/terraform-plugin-go/tftypes"
99
)
1010

11+
func RequiredBoolAttribute(name string) *tfprotov6.SchemaAttribute {
12+
return &tfprotov6.SchemaAttribute{
13+
Name: name,
14+
Type: tftypes.Bool,
15+
Required: true,
16+
}
17+
}
18+
19+
func RequiredListAttribute(name string, elementType tftypes.Type) *tfprotov6.SchemaAttribute {
20+
return &tfprotov6.SchemaAttribute{
21+
Name: name,
22+
Type: tftypes.List{ElementType: elementType},
23+
Required: true,
24+
}
25+
}
26+
27+
func RequiredNumberAttribute(name string) *tfprotov6.SchemaAttribute {
28+
return &tfprotov6.SchemaAttribute{
29+
Name: name,
30+
Type: tftypes.Number,
31+
Required: true,
32+
}
33+
}
34+
1135
func ComputedStringAttribute(name string) *tfprotov6.SchemaAttribute {
1236
return &tfprotov6.SchemaAttribute{
1337
Name: name,

helper/resource/testing_new_import_state.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package resource
55

66
import (
77
"context"
8+
"encoding/json"
89
"fmt"
910
"reflect"
1011
"strings"
@@ -443,7 +444,26 @@ func appendImportBlockWithIdentity(config string, resourceName string, identityV
443444
resourceName)
444445

445446
for k, v := range identityValues {
446-
configBuilder += fmt.Sprintf(` %q = %q`+"\n", k, v)
447+
switch v.(type) {
448+
case bool:
449+
configBuilder += fmt.Sprintf(` %q = %t`+"\n", k, v)
450+
451+
case []any:
452+
var quotedV []string
453+
for _, v := range v.([]any) {
454+
quotedV = append(quotedV, fmt.Sprintf(`%q`, v))
455+
}
456+
configBuilder += fmt.Sprintf(` %q = [%s]`+"\n", k, strings.Join(quotedV, ", "))
457+
458+
case json.Number:
459+
configBuilder += fmt.Sprintf(` %q = %s`+"\n", k, v)
460+
461+
case string:
462+
configBuilder += fmt.Sprintf(` %q = %q`+"\n", k, v)
463+
464+
default:
465+
panic(fmt.Sprintf("unexpected type %T for identity value %q", v, k))
466+
}
447467
}
448468

449469
configBuilder += `` +

0 commit comments

Comments
 (0)