mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Merge pull request #1911 from hashicorp/b-template-diffs
provider/template: don't diff when there's no diff
This commit is contained in:
commit
cc28d04777
@ -16,22 +16,23 @@ import (
|
|||||||
func resource() *schema.Resource {
|
func resource() *schema.Resource {
|
||||||
return &schema.Resource{
|
return &schema.Resource{
|
||||||
Create: Create,
|
Create: Create,
|
||||||
Read: Read,
|
|
||||||
Update: Update,
|
|
||||||
Delete: Delete,
|
Delete: Delete,
|
||||||
Exists: Exists,
|
Exists: Exists,
|
||||||
|
Read: Read,
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"filename": &schema.Schema{
|
"filename": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
Description: "file to read template from",
|
Description: "file to read template from",
|
||||||
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
"vars": &schema.Schema{
|
"vars": &schema.Schema{
|
||||||
Type: schema.TypeMap,
|
Type: schema.TypeMap,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Default: make(map[string]interface{}),
|
Default: make(map[string]interface{}),
|
||||||
Description: "variables to substitute",
|
Description: "variables to substitute",
|
||||||
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
"rendered": &schema.Schema{
|
"rendered": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
@ -42,43 +43,58 @@ func resource() *schema.Resource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Create(d *schema.ResourceData, meta interface{}) error { return eval(d) }
|
func Create(d *schema.ResourceData, meta interface{}) error {
|
||||||
func Update(d *schema.ResourceData, meta interface{}) error { return eval(d) }
|
rendered, err := render(d)
|
||||||
func Read(d *schema.ResourceData, meta interface{}) error { return nil }
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.Set("rendered", rendered)
|
||||||
|
d.SetId(hash(rendered))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func Delete(d *schema.ResourceData, meta interface{}) error {
|
func Delete(d *schema.ResourceData, meta interface{}) error {
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Exists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
func Exists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||||
// Reload every time in case something has changed.
|
rendered, err := render(d)
|
||||||
// This should be cheap, and cache invalidation is hard.
|
if err != nil {
|
||||||
return false, nil
|
return false, err
|
||||||
|
}
|
||||||
|
return hash(rendered) == d.Id(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Read(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
// Logic is handled in Exists, which only returns true if the rendered
|
||||||
|
// contents haven't changed. That means if we get here there's nothing to
|
||||||
|
// do.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var readfile func(string) ([]byte, error) = ioutil.ReadFile // testing hook
|
var readfile func(string) ([]byte, error) = ioutil.ReadFile // testing hook
|
||||||
|
|
||||||
func eval(d *schema.ResourceData) error {
|
func render(d *schema.ResourceData) (string, error) {
|
||||||
filename := d.Get("filename").(string)
|
filename := d.Get("filename").(string)
|
||||||
vars := d.Get("vars").(map[string]interface{})
|
vars := d.Get("vars").(map[string]interface{})
|
||||||
|
|
||||||
path, err := homedir.Expand(filename)
|
path, err := homedir.Expand(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, err := readfile(path)
|
buf, err := readfile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
rendered, err := execute(string(buf), vars)
|
rendered, err := execute(string(buf), vars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to render %v: %v", filename, err)
|
return "", fmt.Errorf("failed to render %v: %v", filename, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Set("rendered", rendered)
|
return rendered, nil
|
||||||
d.SetId(hash(rendered))
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute parses and executes a template using vars.
|
// execute parses and executes a template using vars.
|
||||||
@ -122,5 +138,5 @@ func execute(s string, vars map[string]interface{}) (string, error) {
|
|||||||
|
|
||||||
func hash(s string) string {
|
func hash(s string) string {
|
||||||
sha := sha256.Sum256([]byte(s))
|
sha := sha256.Sum256([]byte(s))
|
||||||
return hex.EncodeToString(sha[:])[:20]
|
return hex.EncodeToString(sha[:])
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ output "rendered" {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
TransientResource: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -75,12 +75,6 @@ type TestStep struct {
|
|||||||
|
|
||||||
// Destroy will create a destroy plan if set to true.
|
// Destroy will create a destroy plan if set to true.
|
||||||
Destroy bool
|
Destroy bool
|
||||||
|
|
||||||
// TransientResource indicates that resources created as part
|
|
||||||
// of this test step are temporary and might be recreated anew
|
|
||||||
// with every planning step. This should only be set for
|
|
||||||
// pseudo-resources, like the null resource or templates.
|
|
||||||
TransientResource bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test performs an acceptance test on a resource.
|
// Test performs an acceptance test on a resource.
|
||||||
@ -269,7 +263,7 @@ func testStep(
|
|||||||
if p, err := ctx.Plan(); err != nil {
|
if p, err := ctx.Plan(); err != nil {
|
||||||
return state, fmt.Errorf("Error on second follow-up plan: %s", err)
|
return state, fmt.Errorf("Error on second follow-up plan: %s", err)
|
||||||
} else {
|
} else {
|
||||||
if p.Diff != nil && !p.Diff.Empty() && !step.TransientResource {
|
if p.Diff != nil && !p.Diff.Empty() {
|
||||||
return state, fmt.Errorf(
|
return state, fmt.Errorf(
|
||||||
"After applying this step and refreshing, the plan was not empty:\n\n%s", p)
|
"After applying this step and refreshing, the plan was not empty:\n\n%s", p)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user