Unverified Commit 8f76ab4f authored by Angus Lees's avatar Angus Lees
Browse files

Add native convenience functions to parse JSON and YAML

Fixes #12
parent bc02b27a
......@@ -12,9 +12,14 @@ all: kubecfg
kubecfg:
$(GO) build $(GO_FLAGS) .
test:
test: gotest jsonnettest
gotest:
$(GO) test $(GO_FLAGS) $(GO_PACKAGES)
jsonnettest: kubecfg lib/kubecfg_test.jsonnet
./kubecfg -J lib show lib/kubecfg_test.jsonnet
vet:
$(GO) vet $(GO_FLAGS) $(GO_PACKAGES)
......
......@@ -63,6 +63,7 @@ avoid an immediate `Killed: 9`.
- Supports JSON, YAML or jsonnet files (by file suffix).
- Best-effort sorts objects before updating, so that dependencies are
pushed to the server before objects that refer to them.
- Additional jsonnet builtin functions. See `lib/kubecfg.libsonnet`.
## Infrastructure-as-code Philosophy
......
......@@ -91,6 +91,8 @@ func JsonnetVM(cmd *cobra.Command) (*jsonnet.VM, error) {
vm.ExtVar(kv[0], kv[1])
}
utils.RegisterNativeFuncs(vm)
return vm, nil
}
......
{
// parseJson(data): parses the `data` string as a json document, and
// returns the resulting jsonnet object.
parseJson:: std.native("parseJson"),
// parseYaml(data): parse the `data` string as a YAML stream, and
// returns an *array* of the resulting jsonnet objects. A single
// YAML document will still be returned as an array with one
// element.
parseYaml:: std.native("parseYaml"),
}
// Run me with `../kubecfg show kubecfg_test.jsonnet`
local kubecfg = import "kubecfg.libsonnet";
assert kubecfg.parseJson("[3, 4]") == [3, 4];
local x = kubecfg.parseYaml("---
- 3
- 4
---
foo: bar
baz: xyzzy
");
assert x == [[3, 4], {foo: "bar", baz: "xyzzy"}] : "got " + x;
// Kubecfg wants to see something that looks like a k8s object
{
apiVersion: "test",
kind: "Result",
result: "SUCCESS"
}
package utils
import (
"bytes"
"encoding/json"
"io"
jsonnet "github.com/strickyak/jsonnet_cgo"
"k8s.io/client-go/pkg/util/yaml"
)
func RegisterNativeFuncs(vm *jsonnet.VM) {
vm.NativeCallback("parseJson", []string{"json"}, func(data []byte) (res interface{}, err error) {
err = json.Unmarshal(data, &res)
return
})
vm.NativeCallback("parseYaml", []string{"yaml"}, func(data []byte) ([]interface{}, error) {
ret := []interface{}{}
d := yaml.NewYAMLToJSONDecoder(bytes.NewReader(data))
for {
var doc interface{}
if err := d.Decode(&doc); err != nil {
if err == io.EOF {
break
}
return nil, err
}
ret = append(ret, doc)
}
return ret, nil
})
}
package utils
import (
"testing"
jsonnet "github.com/strickyak/jsonnet_cgo"
)
// check there is no err, and a == b.
func check(t *testing.T, err error, actual, expected string) {
if err != nil {
t.Errorf("Expected %q, got error: %q", expected, err.Error())
} else if actual != expected {
t.Errorf("Expected %q, got %q", expected, actual)
}
}
func TestParseJson(t *testing.T) {
vm := jsonnet.Make()
defer vm.Destroy()
RegisterNativeFuncs(vm)
_, err := vm.EvaluateSnippet("failtest", `std.native("parseJson")("barf{")`)
if err == nil {
t.Errorf("parseJson succeeded on invalid json")
}
x, err := vm.EvaluateSnippet("test", `std.native("parseJson")("null")`)
check(t, err, x, "null\n")
x, err = vm.EvaluateSnippet("test", `
local a = std.native("parseJson")('{"foo": 3, "bar": 4}');
a.foo + a.bar`)
check(t, err, x, "7\n")
}
func TestParseYaml(t *testing.T) {
vm := jsonnet.Make()
defer vm.Destroy()
RegisterNativeFuncs(vm)
_, err := vm.EvaluateSnippet("failtest", `std.native("parseYaml")("[barf")`)
if err == nil {
t.Errorf("parseYaml succeeded on invalid yaml")
}
x, err := vm.EvaluateSnippet("test", `std.native("parseYaml")("")`)
check(t, err, x, "[ ]\n")
x, err = vm.EvaluateSnippet("test", `
local a = std.native("parseYaml")("foo:\n- 3\n- 4\n")[0];
a.foo[0] + a.foo[1]`)
check(t, err, x, "7\n")
x, err = vm.EvaluateSnippet("test", `
local a = std.native("parseYaml")("---\nhello\n---\nworld");
a[0] + a[1]`)
check(t, err, x, "\"helloworld\"\n")
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment