parent
15c75c501f
commit
745d83a995
|
@ -0,0 +1,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/builtin/providers/template"
|
||||
"github.com/hashicorp/terraform/plugin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.Serve(&plugin.ServeOpts{
|
||||
ProviderFunc: template.Provider,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package template
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func Provider() terraform.ResourceProvider {
|
||||
return &schema.Provider{
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"template_file": resource(),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package template
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package template
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
"github.com/hashicorp/terraform/config/lang"
|
||||
"github.com/hashicorp/terraform/config/lang/ast"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resource() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: Create,
|
||||
Read: Read,
|
||||
Update: Update,
|
||||
Delete: Delete,
|
||||
Exists: Exists,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"filename": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "file to read template from",
|
||||
},
|
||||
"vars": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Default: make(map[string]interface{}),
|
||||
Description: "variables to substitute",
|
||||
},
|
||||
"rendered": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Default: nil,
|
||||
Description: "rendered template",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func Create(d *schema.ResourceData, meta interface{}) error { return eval(d) }
|
||||
func Update(d *schema.ResourceData, meta interface{}) error { return eval(d) }
|
||||
func Read(d *schema.ResourceData, meta interface{}) error { return nil }
|
||||
func Delete(d *schema.ResourceData, meta interface{}) error {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
func Exists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
// Reload every time in case something has changed.
|
||||
// This should be cheap, and cache invalidation is hard.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func eval(d *schema.ResourceData) error {
|
||||
filename := d.Get("filename").(string)
|
||||
vars := d.Get("vars").(map[string]interface{})
|
||||
|
||||
buf, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rendered, err := execute(string(buf), vars)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to render %v: %v", filename, err)
|
||||
}
|
||||
|
||||
d.Set("rendered", rendered)
|
||||
d.SetId(hash(rendered))
|
||||
return nil
|
||||
}
|
||||
|
||||
// execute parses and executes a template using vars.
|
||||
func execute(s string, vars map[string]interface{}) (string, error) {
|
||||
root, err := lang.Parse(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
varmap := make(map[string]ast.Variable)
|
||||
for k, v := range vars {
|
||||
// As far as I can tell, v is always a string.
|
||||
// If it's not, tell the user gracefully.
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unexpected type for variable %q: %T", k, v)
|
||||
}
|
||||
varmap[k] = ast.Variable{
|
||||
Value: s,
|
||||
Type: ast.TypeString,
|
||||
}
|
||||
}
|
||||
|
||||
cfg := lang.EvalConfig{
|
||||
GlobalScope: &ast.BasicScope{
|
||||
VarMap: varmap,
|
||||
FuncMap: config.Funcs,
|
||||
},
|
||||
}
|
||||
|
||||
out, typ, err := lang.Eval(root, &cfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if typ != ast.TypeString {
|
||||
return "", fmt.Errorf("unexpected output ast.Type: %v", typ)
|
||||
}
|
||||
|
||||
return out.(string), nil
|
||||
}
|
||||
|
||||
func hash(s string) string {
|
||||
sha := sha256.Sum256([]byte(s))
|
||||
return hex.EncodeToString(sha[:])[:20]
|
||||
}
|
Loading…
Reference in New Issue