Skip to content

Commit 861ac53

Browse files
apparentlymartjen20
authored andcommitted
provider/template: convert resources to data sources
The template resources don't actually need to retain any state, so they are good candidates to be data sources. This includes a few tweaks to the acceptance tests -- now configured to run as unit tests -- since it seems that they have been slightly broken for a while now. In particular, the "update" cases are no longer tested because updating is not a meaningful operation for a data source.
1 parent 46e3cac commit 861ac53

11 files changed

Lines changed: 122 additions & 262 deletions

builtin/providers/template/resource_cloudinit_config.go renamed to builtin/providers/template/datasource_cloudinit_config.go

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,9 @@ import (
1515
"github.com/sthulb/mime/multipart"
1616
)
1717

18-
func resourceCloudinitConfig() *schema.Resource {
18+
func dataSourceCloudinitConfig() *schema.Resource {
1919
return &schema.Resource{
20-
Create: resourceCloudinitConfigCreate,
21-
Delete: resourceCloudinitConfigDelete,
22-
Update: resourceCloudinitConfigCreate,
23-
Exists: resourceCloudinitConfigExists,
24-
Read: resourceCloudinitConfigRead,
20+
Read: dataSourceCloudinitConfigRead,
2521

2622
Schema: map[string]*schema.Schema{
2723
"part": &schema.Schema{
@@ -52,13 +48,11 @@ func resourceCloudinitConfig() *schema.Resource {
5248
Type: schema.TypeBool,
5349
Optional: true,
5450
Default: true,
55-
ForceNew: true,
5651
},
5752
"base64_encode": &schema.Schema{
5853
Type: schema.TypeBool,
5954
Optional: true,
6055
Default: true,
61-
ForceNew: true,
6256
},
6357
"rendered": &schema.Schema{
6458
Type: schema.TypeString,
@@ -69,7 +63,7 @@ func resourceCloudinitConfig() *schema.Resource {
6963
}
7064
}
7165

72-
func resourceCloudinitConfigCreate(d *schema.ResourceData, meta interface{}) error {
66+
func dataSourceCloudinitConfigRead(d *schema.ResourceData, meta interface{}) error {
7367
rendered, err := renderCloudinitConfig(d)
7468
if err != nil {
7569
return err
@@ -80,24 +74,6 @@ func resourceCloudinitConfigCreate(d *schema.ResourceData, meta interface{}) err
8074
return nil
8175
}
8276

83-
func resourceCloudinitConfigDelete(d *schema.ResourceData, meta interface{}) error {
84-
d.SetId("")
85-
return nil
86-
}
87-
88-
func resourceCloudinitConfigExists(d *schema.ResourceData, meta interface{}) (bool, error) {
89-
rendered, err := renderCloudinitConfig(d)
90-
if err != nil {
91-
return false, err
92-
}
93-
94-
return strconv.Itoa(hashcode.String(rendered)) == d.Id(), nil
95-
}
96-
97-
func resourceCloudinitConfigRead(d *schema.ResourceData, meta interface{}) error {
98-
return nil
99-
}
100-
10177
func renderCloudinitConfig(d *schema.ResourceData) (string, error) {
10278
gzipOutput := d.Get("gzip").(bool)
10379
base64Output := d.Get("base64_encode").(bool)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package template
2+
3+
import (
4+
"testing"
5+
6+
r "github.com/hashicorp/terraform/helper/resource"
7+
)
8+
9+
func TestRender(t *testing.T) {
10+
testCases := []struct {
11+
ResourceBlock string
12+
Expected string
13+
}{
14+
{
15+
`data "template_cloudinit_config" "foo" {
16+
gzip = false
17+
base64_encode = false
18+
19+
part {
20+
content_type = "text/x-shellscript"
21+
content = "baz"
22+
}
23+
}`,
24+
"Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
25+
},
26+
{
27+
`data "template_cloudinit_config" "foo" {
28+
gzip = false
29+
base64_encode = false
30+
31+
part {
32+
content_type = "text/x-shellscript"
33+
content = "baz"
34+
filename = "foobar.sh"
35+
}
36+
}`,
37+
"Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n--MIMEBOUNDARY\r\nContent-Disposition: attachment; filename=\"foobar.sh\"\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n",
38+
},
39+
{
40+
`data "template_cloudinit_config" "foo" {
41+
gzip = false
42+
base64_encode = false
43+
44+
part {
45+
content_type = "text/x-shellscript"
46+
content = "baz"
47+
}
48+
part {
49+
content_type = "text/x-shellscript"
50+
content = "ffbaz"
51+
}
52+
}`,
53+
"Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nffbaz\r\n--MIMEBOUNDARY--\r\n",
54+
},
55+
}
56+
57+
for _, tt := range testCases {
58+
r.UnitTest(t, r.TestCase{
59+
Providers: testProviders,
60+
Steps: []r.TestStep{
61+
r.TestStep{
62+
Config: tt.ResourceBlock,
63+
Check: r.ComposeTestCheckFunc(
64+
r.TestCheckResourceAttr("data.template_cloudinit_config.foo", "rendered", tt.Expected),
65+
),
66+
},
67+
},
68+
})
69+
}
70+
}
71+
72+
var testCloudInitConfig_basic = `
73+
data "template_cloudinit_config" "config" {
74+
part {
75+
content_type = "text/x-shellscript"
76+
content = "baz"
77+
}
78+
}`
79+
80+
var testCloudInitConfig_basic_expected = `Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n`

builtin/providers/template/resource_template_file.go renamed to builtin/providers/template/datasource_template_file.go

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"crypto/sha256"
55
"encoding/hex"
66
"fmt"
7-
"log"
87
"os"
98
"path/filepath"
109

@@ -15,27 +14,22 @@ import (
1514
"github.com/hashicorp/terraform/helper/schema"
1615
)
1716

18-
func resourceFile() *schema.Resource {
17+
func dataSourceFile() *schema.Resource {
1918
return &schema.Resource{
20-
Create: resourceFileCreate,
21-
Delete: resourceFileDelete,
22-
Exists: resourceFileExists,
23-
Read: resourceFileRead,
19+
Read: dataSourceFileRead,
2420

2521
Schema: map[string]*schema.Schema{
2622
"template": &schema.Schema{
2723
Type: schema.TypeString,
2824
Optional: true,
2925
Description: "Contents of the template",
30-
ForceNew: true,
3126
ConflictsWith: []string{"filename"},
3227
ValidateFunc: validateTemplateAttribute,
3328
},
3429
"filename": &schema.Schema{
3530
Type: schema.TypeString,
3631
Optional: true,
3732
Description: "file to read template from",
38-
ForceNew: true,
3933
// Make a "best effort" attempt to relativize the file path.
4034
StateFunc: func(v interface{}) string {
4135
if v == nil || v.(string) == "" {
@@ -59,7 +53,6 @@ func resourceFile() *schema.Resource {
5953
Optional: true,
6054
Default: make(map[string]interface{}),
6155
Description: "variables to substitute",
62-
ForceNew: true,
6356
},
6457
"rendered": &schema.Schema{
6558
Type: schema.TypeString,
@@ -70,7 +63,7 @@ func resourceFile() *schema.Resource {
7063
}
7164
}
7265

73-
func resourceFileCreate(d *schema.ResourceData, meta interface{}) error {
66+
func dataSourceFileRead(d *schema.ResourceData, meta interface{}) error {
7467
rendered, err := renderFile(d)
7568
if err != nil {
7669
return err
@@ -80,32 +73,6 @@ func resourceFileCreate(d *schema.ResourceData, meta interface{}) error {
8073
return nil
8174
}
8275

83-
func resourceFileDelete(d *schema.ResourceData, meta interface{}) error {
84-
d.SetId("")
85-
return nil
86-
}
87-
88-
func resourceFileExists(d *schema.ResourceData, meta interface{}) (bool, error) {
89-
rendered, err := renderFile(d)
90-
if err != nil {
91-
if _, ok := err.(templateRenderError); ok {
92-
log.Printf("[DEBUG] Got error while rendering in Exists: %s", err)
93-
log.Printf("[DEBUG] Returning false so the template re-renders using latest variables from config.")
94-
return false, nil
95-
} else {
96-
return false, err
97-
}
98-
}
99-
return hash(rendered) == d.Id(), nil
100-
}
101-
102-
func resourceFileRead(d *schema.ResourceData, meta interface{}) error {
103-
// Logic is handled in Exists, which only returns true if the rendered
104-
// contents haven't changed. That means if we get here there's nothing to
105-
// do.
106-
return nil
107-
}
108-
10976
type templateRenderError error
11077

11178
func renderFile(d *schema.ResourceData) (string, error) {

builtin/providers/template/resource_template_file_test.go renamed to builtin/providers/template/datasource_template_file_test.go

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ func TestTemplateRendering(t *testing.T) {
2323
want string
2424
}{
2525
{`{}`, `ABC`, `ABC`},
26-
{`{a="foo"}`, `${a}`, `foo`},
27-
{`{a="hello"}`, `${replace(a, "ello", "i")}`, `hi`},
26+
{`{a="foo"}`, `$${a}`, `foo`},
27+
{`{a="hello"}`, `$${replace(a, "ello", "i")}`, `hi`},
2828
{`{}`, `${1+2+3}`, `6`},
2929
}
3030

3131
for _, tt := range cases {
32-
r.Test(t, r.TestCase{
32+
r.UnitTest(t, r.TestCase{
3333
Providers: testProviders,
3434
Steps: []r.TestStep{
3535
r.TestStep{
@@ -47,39 +47,6 @@ func TestTemplateRendering(t *testing.T) {
4747
}
4848
}
4949

50-
// https://github.com/hashicorp/terraform/issues/2344
51-
func TestTemplateVariableChange(t *testing.T) {
52-
steps := []struct {
53-
vars string
54-
template string
55-
want string
56-
}{
57-
{`{a="foo"}`, `${a}`, `foo`},
58-
{`{b="bar"}`, `${b}`, `bar`},
59-
}
60-
61-
var testSteps []r.TestStep
62-
for i, step := range steps {
63-
testSteps = append(testSteps, r.TestStep{
64-
Config: testTemplateConfig(step.template, step.vars),
65-
Check: func(i int, want string) r.TestCheckFunc {
66-
return func(s *terraform.State) error {
67-
got := s.RootModule().Outputs["rendered"]
68-
if want != got.Value {
69-
return fmt.Errorf("[%d] got:\n%q\nwant:\n%q\n", i, got, want)
70-
}
71-
return nil
72-
}
73-
}(i, step.want),
74-
})
75-
}
76-
77-
r.Test(t, r.TestCase{
78-
Providers: testProviders,
79-
Steps: testSteps,
80-
})
81-
}
82-
8350
func TestValidateTemplateAttribute(t *testing.T) {
8451
file, err := ioutil.TempFile("", "testtemplate")
8552
if err != nil {
@@ -129,11 +96,11 @@ func TestTemplateSharedMemoryRace(t *testing.T) {
12996

13097
func testTemplateConfig(template, vars string) string {
13198
return fmt.Sprintf(`
132-
resource "template_file" "t0" {
99+
data "template_file" "t0" {
133100
template = "%s"
134101
vars = %s
135102
}
136103
output "rendered" {
137-
value = "${template_file.t0.rendered}"
104+
value = "${data.template_file.t0.rendered}"
138105
}`, template, vars)
139106
}

builtin/providers/template/provider.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,19 @@ import (
77

88
func Provider() terraform.ResourceProvider {
99
return &schema.Provider{
10+
DataSourcesMap: map[string]*schema.Resource{
11+
"template_file": dataSourceFile(),
12+
"template_cloudinit_config": dataSourceCloudinitConfig(),
13+
},
1014
ResourcesMap: map[string]*schema.Resource{
11-
"template_file": resourceFile(),
12-
"template_cloudinit_config": resourceCloudinitConfig(),
15+
"template_file": schema.DataSourceResourceShim(
16+
"template_file",
17+
dataSourceFile(),
18+
),
19+
"template_cloudinit_config": schema.DataSourceResourceShim(
20+
"template_cloudinit_config",
21+
dataSourceCloudinitConfig(),
22+
),
1323
},
1424
}
1525
}

0 commit comments

Comments
 (0)