mirror of
https://github.com/kubernetes/client-go.git
synced 2025-08-16 22:36:48 +00:00
Merge pull request #88464 from brianpursley/kubernetes-86130
Fixed bug where jsonpath expression with nested range produces wrong output Kubernetes-commit: 6747678a396ada2f4761ff104495ddcc3ef050b3
This commit is contained in:
commit
4b490f30ca
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
@ -352,7 +352,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/apimachinery",
|
"ImportPath": "k8s.io/apimachinery",
|
||||||
"Rev": "591a38b7a7b7"
|
"Rev": "4c6179225362"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/gengo",
|
"ImportPath": "k8s.io/gengo",
|
||||||
|
4
go.mod
4
go.mod
@ -29,7 +29,7 @@ require (
|
|||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
||||||
google.golang.org/appengine v1.5.0 // indirect
|
google.golang.org/appengine v1.5.0 // indirect
|
||||||
k8s.io/api v0.0.0-20200403220253-fa879b399cd0
|
k8s.io/api v0.0.0-20200403220253-fa879b399cd0
|
||||||
k8s.io/apimachinery v0.0.0-20200407101112-591a38b7a7b7
|
k8s.io/apimachinery v0.0.0-20200408061145-4c6179225362
|
||||||
k8s.io/klog v1.0.0
|
k8s.io/klog v1.0.0
|
||||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
|
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
|
||||||
sigs.k8s.io/yaml v1.2.0
|
sigs.k8s.io/yaml v1.2.0
|
||||||
@ -39,5 +39,5 @@ replace (
|
|||||||
golang.org/x/sys => golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // pinned to release-branch.go1.13
|
golang.org/x/sys => golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // pinned to release-branch.go1.13
|
||||||
golang.org/x/tools => golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 // pinned to release-branch.go1.13
|
golang.org/x/tools => golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 // pinned to release-branch.go1.13
|
||||||
k8s.io/api => k8s.io/api v0.0.0-20200403220253-fa879b399cd0
|
k8s.io/api => k8s.io/api v0.0.0-20200403220253-fa879b399cd0
|
||||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20200407101112-591a38b7a7b7
|
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20200408061145-4c6179225362
|
||||||
)
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -188,7 +188,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
k8s.io/api v0.0.0-20200403220253-fa879b399cd0/go.mod h1:IHUHI0RKOjAF2/LmT+5g7hlTufmlzdZqccff7saac3A=
|
k8s.io/api v0.0.0-20200403220253-fa879b399cd0/go.mod h1:IHUHI0RKOjAF2/LmT+5g7hlTufmlzdZqccff7saac3A=
|
||||||
k8s.io/apimachinery v0.0.0-20200407101112-591a38b7a7b7/go.mod h1:plsINh5MKcZh761kXB2H+kXnD8vwFIAy7bitct1VPNU=
|
k8s.io/apimachinery v0.0.0-20200408061145-4c6179225362/go.mod h1:plsINh5MKcZh761kXB2H+kXnD8vwFIAy7bitct1VPNU=
|
||||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
|
@ -29,12 +29,12 @@ import (
|
|||||||
type JSONPath struct {
|
type JSONPath struct {
|
||||||
name string
|
name string
|
||||||
parser *Parser
|
parser *Parser
|
||||||
stack [][]reflect.Value // push and pop values in different scopes
|
|
||||||
cur []reflect.Value // current scope values
|
|
||||||
beginRange int
|
beginRange int
|
||||||
inRange int
|
inRange int
|
||||||
endRange int
|
endRange int
|
||||||
|
|
||||||
|
lastEndNode *Node
|
||||||
|
|
||||||
allowMissingKeys bool
|
allowMissingKeys bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,12 +81,12 @@ func (j *JSONPath) FindResults(data interface{}) ([][]reflect.Value, error) {
|
|||||||
return nil, fmt.Errorf("%s is an incomplete jsonpath template", j.name)
|
return nil, fmt.Errorf("%s is an incomplete jsonpath template", j.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
j.cur = []reflect.Value{reflect.ValueOf(data)}
|
cur := []reflect.Value{reflect.ValueOf(data)}
|
||||||
nodes := j.parser.Root.Nodes
|
nodes := j.parser.Root.Nodes
|
||||||
fullResult := [][]reflect.Value{}
|
fullResult := [][]reflect.Value{}
|
||||||
for i := 0; i < len(nodes); i++ {
|
for i := 0; i < len(nodes); i++ {
|
||||||
node := nodes[i]
|
node := nodes[i]
|
||||||
results, err := j.walk(j.cur, node)
|
results, err := j.walk(cur, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -94,25 +94,32 @@ func (j *JSONPath) FindResults(data interface{}) ([][]reflect.Value, error) {
|
|||||||
// encounter an end node, break the current block
|
// encounter an end node, break the current block
|
||||||
if j.endRange > 0 && j.endRange <= j.inRange {
|
if j.endRange > 0 && j.endRange <= j.inRange {
|
||||||
j.endRange--
|
j.endRange--
|
||||||
|
j.lastEndNode = &nodes[i]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// encounter a range node, start a range loop
|
// encounter a range node, start a range loop
|
||||||
if j.beginRange > 0 {
|
if j.beginRange > 0 {
|
||||||
j.beginRange--
|
j.beginRange--
|
||||||
j.inRange++
|
j.inRange++
|
||||||
for k, value := range results {
|
for _, value := range results {
|
||||||
j.parser.Root.Nodes = nodes[i+1:]
|
j.parser.Root.Nodes = nodes[i+1:]
|
||||||
if k == len(results)-1 {
|
|
||||||
j.inRange--
|
|
||||||
}
|
|
||||||
nextResults, err := j.FindResults(value.Interface())
|
nextResults, err := j.FindResults(value.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fullResult = append(fullResult, nextResults...)
|
fullResult = append(fullResult, nextResults...)
|
||||||
}
|
}
|
||||||
|
j.inRange--
|
||||||
|
|
||||||
|
// Fast forward to resume processing after the most recent end node that was encountered
|
||||||
|
for k := i + 1; k < len(nodes); k++ {
|
||||||
|
if &nodes[k] == j.lastEndNode {
|
||||||
|
i = k
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
fullResult = append(fullResult, results)
|
fullResult = append(fullResult, results)
|
||||||
}
|
}
|
||||||
return fullResult, nil
|
return fullResult, nil
|
||||||
@ -212,17 +219,11 @@ func (j *JSONPath) evalIdentifier(input []reflect.Value, node *IdentifierNode) (
|
|||||||
results := []reflect.Value{}
|
results := []reflect.Value{}
|
||||||
switch node.Name {
|
switch node.Name {
|
||||||
case "range":
|
case "range":
|
||||||
j.stack = append(j.stack, j.cur)
|
|
||||||
j.beginRange++
|
j.beginRange++
|
||||||
results = input
|
results = input
|
||||||
case "end":
|
case "end":
|
||||||
if j.endRange < j.inRange { // inside a loop, break the current block
|
if j.inRange > 0 {
|
||||||
j.endRange++
|
j.endRange++
|
||||||
break
|
|
||||||
}
|
|
||||||
// the loop is about to end, pop value and continue the following execution
|
|
||||||
if len(j.stack) > 0 {
|
|
||||||
j.cur, j.stack = j.stack[len(j.stack)-1], j.stack[:len(j.stack)-1]
|
|
||||||
} else {
|
} else {
|
||||||
return results, fmt.Errorf("not in range, nothing to end")
|
return results, fmt.Errorf("not in range, nothing to end")
|
||||||
}
|
}
|
||||||
|
@ -298,6 +298,133 @@ func TestKubernetes(t *testing.T) {
|
|||||||
testJSONPathSortOutput(randomPrintOrderTests, t)
|
testJSONPathSortOutput(randomPrintOrderTests, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNestedRanges(t *testing.T) {
|
||||||
|
var input = []byte(`{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "pod1"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"another": [
|
||||||
|
{ "name": "value1" },
|
||||||
|
{ "name": "value2" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"another": [
|
||||||
|
{ "name": "value1" },
|
||||||
|
{ "name": "value2" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "pod2"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "baz",
|
||||||
|
"another": [
|
||||||
|
{ "name": "value1" },
|
||||||
|
{ "name": "value2" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
var data interface{}
|
||||||
|
err := json.Unmarshal(input, &data)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testJSONPath(
|
||||||
|
[]jsonpathTest{
|
||||||
|
{
|
||||||
|
"nested range with a trailing newline",
|
||||||
|
`{range .items[*]}` +
|
||||||
|
`{.metadata.name}` +
|
||||||
|
`{":"}` +
|
||||||
|
`{range @.spec.containers[*]}` +
|
||||||
|
`{.name}` +
|
||||||
|
`{","}` +
|
||||||
|
`{end}` +
|
||||||
|
`{"+"}` +
|
||||||
|
`{end}`,
|
||||||
|
data,
|
||||||
|
"pod1:foo,bar,+pod2:baz,+",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
t,
|
||||||
|
)
|
||||||
|
|
||||||
|
testJSONPath(
|
||||||
|
[]jsonpathTest{
|
||||||
|
{
|
||||||
|
"nested range with a trailing character within another nested range with a trailing newline",
|
||||||
|
`{range .items[*]}` +
|
||||||
|
`{.metadata.name}` +
|
||||||
|
`{"~"}` +
|
||||||
|
`{range @.spec.containers[*]}` +
|
||||||
|
`{.name}` +
|
||||||
|
`{":"}` +
|
||||||
|
`{range @.another[*]}` +
|
||||||
|
`{.name}` +
|
||||||
|
`{","}` +
|
||||||
|
`{end}` +
|
||||||
|
`{"+"}` +
|
||||||
|
`{end}` +
|
||||||
|
`{"#"}` +
|
||||||
|
`{end}`,
|
||||||
|
data,
|
||||||
|
"pod1~foo:value1,value2,+bar:value1,value2,+#pod2~baz:value1,value2,+#",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
t,
|
||||||
|
)
|
||||||
|
|
||||||
|
testJSONPath(
|
||||||
|
[]jsonpathTest{
|
||||||
|
{
|
||||||
|
"two nested ranges at the same level with a trailing newline",
|
||||||
|
`{range .items[*]}` +
|
||||||
|
`{.metadata.name}` +
|
||||||
|
`{"\t"}` +
|
||||||
|
`{range @.spec.containers[*]}` +
|
||||||
|
`{.name}` +
|
||||||
|
`{" "}` +
|
||||||
|
`{end}` +
|
||||||
|
`{"\t"}` +
|
||||||
|
`{range @.spec.containers[*]}` +
|
||||||
|
`{.name}` +
|
||||||
|
`{" "}` +
|
||||||
|
`{end}` +
|
||||||
|
`{"\n"}` +
|
||||||
|
`{end}`,
|
||||||
|
data,
|
||||||
|
"pod1\tfoo bar \tfoo bar \npod2\tbaz \tbaz \n",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
t,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFilterPartialMatchesSometimesMissingAnnotations(t *testing.T) {
|
func TestFilterPartialMatchesSometimesMissingAnnotations(t *testing.T) {
|
||||||
// for https://issues.k8s.io/45546
|
// for https://issues.k8s.io/45546
|
||||||
var input = []byte(`{
|
var input = []byte(`{
|
||||||
|
Loading…
Reference in New Issue
Block a user