This repository has been archived by the owner on Oct 3, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 66
Example usage of custom defined function #5
Comments
Here is an example of doing it one way, if anyone looks how to implement it: package main
import (
"encoding/json"
"fmt"
"log"
"time"
"github.com/hashicorp/hcl2/gohcl"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/hcl2/hcldec"
"github.com/hashicorp/hcl2/hclparse"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
"github.com/zclconf/go-cty/cty/function/stdlib"
ctyjson "github.com/zclconf/go-cty/cty/json"
)
func main() {
var src = `
variable "city" {
default = "Ankara"
}
variable "year" {
default = "2000"
}
resource "fatih" "arslan" {
result = "Address: ${upper(var.city)}, Age: ${age(var.year)}"
}
`
parser := hclparse.NewParser()
file, diags := parser.ParseHCL([]byte(src), "demo.hcl")
if len(diags) != 0 {
for _, diag := range diags {
fmt.Printf("- %s\n", diag)
}
return
}
body := file.Body
type Variable struct {
Name string `hcl:"name,label"`
Default hcl.Attributes `hcl:"default,remain"`
}
type Resource struct {
Type string `hcl:"type,label"`
Name string `hcl:"name,label"`
Config hcl.Body `hcl:",remain"`
}
type Root struct {
Variables []*Variable `hcl:"variable,block"`
Resources []*Resource `hcl:"resource,block"`
}
var root Root
diags = gohcl.DecodeBody(body, nil, &root)
if len(diags) != 0 {
for _, diag := range diags {
fmt.Printf("decoding - %s\n", diag)
}
return
}
variables := map[string]cty.Value{}
for _, v := range root.Variables {
if len(v.Default) == 0 {
continue
}
val, diags := v.Default["default"].Expr.Value(nil)
if len(diags) != 0 {
for _, diag := range diags {
fmt.Printf("decoding - %s\n", diag)
}
return
}
variables[v.Name] = val
}
evalContext := &hcl.EvalContext{
Variables: map[string]cty.Value{
"var": cty.ObjectVal(variables),
},
Functions: map[string]function.Function{
"upper": stdlib.UpperFunc,
"age": age(),
},
}
// just for resource address and bar
spec := &hcldec.ObjectSpec{
"result": &hcldec.AttrSpec{
Name: "result",
Required: true,
Type: cty.String,
},
}
cfg, diags := hcldec.Decode(root.Resources[0].Config, spec, evalContext)
if len(diags) != 0 {
for _, diag := range diags {
fmt.Printf("- %s\n", diag)
}
return
}
wantCfg := cty.ObjectVal(map[string]cty.Value{
"result": cty.StringVal("Address: ANKARA, Age: 18"),
})
if !cfg.RawEquals(wantCfg) {
log.Fatalf("wrong config\ngot: %#v\nwant: %#v", cfg, wantCfg)
}
out, err := json.MarshalIndent(ctyjson.SimpleJSONValue{cfg}, "", " ")
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(out))
}
// age() is a custom function that returns back the age from the birth year
func age() function.Function {
return function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "year",
Type: cty.Number,
},
},
Type: function.StaticReturnType(cty.Number),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
in := args[0].AsBigFloat()
year, _ := in.Int64()
age := int64(time.Now().Year()) - year
return cty.NumberIntVal(age), nil
},
})
} Prints:
|
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Hi,
I see that this project will replace HCL and HIL going forward. Are there any example on how to use it with custom defined function (like how Terraform injects into the HIL's eval context). The README and doc is highly technical written and seems like until I read the source code it's not easily discoverable.
Thanks
The text was updated successfully, but these errors were encountered: