feat(engine): add jq filter template func

resolve helm#11212

Signed-off-by: longkai <im.longkai@gmail.com>
pull/11237/head
longkai 3 years ago
parent bb463b4c27
commit 7221939fe9

@ -46,6 +46,8 @@ require (
sigs.k8s.io/yaml v1.3.0
)
require github.com/itchyny/timefmt-go v0.1.5 // indirect
require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
@ -96,6 +98,7 @@ require (
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/itchyny/gojq v0.12.11
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.11.13 // indirect
@ -105,7 +108,7 @@ require (
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect

@ -701,6 +701,10 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
github.com/itchyny/gojq v0.12.11 h1:YhLueoHhHiN4mkfM+3AyJV6EPcCxKZsOnYf+aVSwaQw=
github.com/itchyny/gojq v0.12.11/go.mod h1:o3FT8Gkbg/geT4pLI0tF3hvip5F3Y/uskjRz9OYa38g=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@ -798,6 +802,7 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
@ -1017,6 +1022,7 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=

@ -24,6 +24,7 @@ import (
"github.com/BurntSushi/toml"
"github.com/Masterminds/sprig/v3"
"github.com/itchyny/gojq"
"sigs.k8s.io/yaml"
)
@ -35,12 +36,11 @@ import (
//
// Known late-bound functions:
//
// - "include"
// - "tpl"
// - "include"
// - "tpl"
//
// These are late-bound in Engine.Render(). The
// version included in the FuncMap is a placeholder.
//
func funcMap() template.FuncMap {
f := sprig.TxtFuncMap()
delete(f, "env")
@ -55,6 +55,7 @@ func funcMap() template.FuncMap {
"toJson": toJSON,
"fromJson": fromJSON,
"fromJsonArray": fromJSONArray,
"jq": jq,
// This is a placeholder for the "include" function, which is
// late-bound to a template. By declaring it here, we preserve the
@ -175,3 +176,36 @@ func fromJSONArray(str string) []interface{} {
}
return a
}
// jq is like sed for JSON/YAML data - you can use it to slice and filter
// and map and transform structured data with the same ease that sed, awk, grep
// and friends let you play with text.
//
// See the [jq Tutorial](https://stedolan.github.io/jq/tutorial/) for more.
//
// This is a pure go implementation of jq. The type of v should be
// []interface{} for an array or map[string]interface{} for a map.
// Since the jq filter returns a iterator, it will be collected as a slice
// even there is only one item.
// It will insert the returned error message string as
// the first and only item in the returned array.
func jq(exp string, v interface{}) []interface{} {
query, err := gojq.Parse(exp)
if err != nil {
return []interface{}{err.Error()}
}
iter := query.Run(v)
var list []interface{}
for {
it, ok := iter.Next()
if !ok {
break
}
if err, ok := it.(error); ok {
return []interface{}{err.Error()}
}
list = append(list, it)
}
return list
}

@ -99,6 +99,28 @@ func TestFuncs(t *testing.T) {
tpl: `{{ lookup "v1" "Namespace" "" "unlikelynamespace99999999" }}`,
expect: `map[]`,
vars: `["one", "two"]`,
}, {
tpl: "{{ . | jq `.ports[] | select(.name == \"grpc\") | .containerPort` | first }}",
expect: "8080",
vars: map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"containerPort": 80,
"name": "http",
"protocol": "TCP",
},
map[string]interface{}{
"containerPort": 443,
"name": "https",
"protocol": "TCP",
},
map[string]interface{}{
"containerPort": 8080,
"name": "grpc",
"protocol": "TCP",
},
},
},
}}
for _, tt := range tests {

Loading…
Cancel
Save