Merge pull request #12202 from daizuozhuo/kubectl
add jsonpath to kubectl
This commit is contained in:
@@ -21,7 +21,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/kubernetes/third_party/golang/template"
|
||||
)
|
||||
@@ -214,10 +213,9 @@ func (j *JSONPath) evalIdentifier(input []reflect.Value, node *IdentifierNode) (
|
||||
func (j *JSONPath) evalArray(input []reflect.Value, node *ArrayNode) ([]reflect.Value, error) {
|
||||
result := []reflect.Value{}
|
||||
for _, value := range input {
|
||||
if value.Kind() == reflect.Interface {
|
||||
value = reflect.ValueOf(value.Interface())
|
||||
}
|
||||
if value.Kind() != reflect.Array && value.Kind() != reflect.Slice {
|
||||
|
||||
value, isNil := template.Indirect(value)
|
||||
if isNil || (value.Kind() != reflect.Array && value.Kind() != reflect.Slice) {
|
||||
return input, fmt.Errorf("%v is not array or slice", value)
|
||||
}
|
||||
params := node.Params
|
||||
@@ -265,9 +263,11 @@ func (j *JSONPath) evalField(input []reflect.Value, node *FieldNode) ([]reflect.
|
||||
results := []reflect.Value{}
|
||||
for _, value := range input {
|
||||
var result reflect.Value
|
||||
if value.Kind() == reflect.Interface {
|
||||
value = reflect.ValueOf(value.Interface())
|
||||
value, isNil := template.Indirect(value)
|
||||
if isNil {
|
||||
continue
|
||||
}
|
||||
|
||||
if value.Kind() == reflect.Struct {
|
||||
result = value.FieldByName(node.Value)
|
||||
} else if value.Kind() == reflect.Map {
|
||||
@@ -287,6 +287,11 @@ func (j *JSONPath) evalField(input []reflect.Value, node *FieldNode) ([]reflect.
|
||||
func (j *JSONPath) evalWildcard(input []reflect.Value, node *WildcardNode) ([]reflect.Value, error) {
|
||||
results := []reflect.Value{}
|
||||
for _, value := range input {
|
||||
value, isNil := template.Indirect(value)
|
||||
if isNil {
|
||||
continue
|
||||
}
|
||||
|
||||
kind := value.Kind()
|
||||
if kind == reflect.Struct {
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
@@ -310,6 +315,11 @@ func (j *JSONPath) evalRecursive(input []reflect.Value, node *RecursiveNode) ([]
|
||||
result := []reflect.Value{}
|
||||
for _, value := range input {
|
||||
results := []reflect.Value{}
|
||||
value, isNil := template.Indirect(value)
|
||||
if isNil {
|
||||
continue
|
||||
}
|
||||
|
||||
kind := value.Kind()
|
||||
if kind == reflect.Struct {
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
@@ -340,9 +350,8 @@ func (j *JSONPath) evalRecursive(input []reflect.Value, node *RecursiveNode) ([]
|
||||
func (j *JSONPath) evalFilter(input []reflect.Value, node *FilterNode) ([]reflect.Value, error) {
|
||||
results := []reflect.Value{}
|
||||
for _, value := range input {
|
||||
if value.Kind() == reflect.Interface {
|
||||
value = reflect.ValueOf(value.Interface())
|
||||
}
|
||||
value, _ = template.Indirect(value)
|
||||
|
||||
if value.Kind() != reflect.Array && value.Kind() != reflect.Slice {
|
||||
return input, fmt.Errorf("%v is not array or slice", value)
|
||||
}
|
||||
@@ -407,77 +416,11 @@ func (j *JSONPath) evalFilter(input []reflect.Value, node *FilterNode) ([]reflec
|
||||
|
||||
// evalToText translates reflect value to corresponding text
|
||||
func (j *JSONPath) evalToText(v reflect.Value) ([]byte, error) {
|
||||
if v.Kind() == reflect.Interface {
|
||||
v = reflect.ValueOf(v.Interface())
|
||||
iface, ok := template.PrintableValue(v)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("can't print type %s", v.Type())
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
//pass
|
||||
case reflect.Ptr:
|
||||
text, err := j.evalToText(reflect.Indirect(v))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer.Write(text)
|
||||
case reflect.Bool:
|
||||
if variable := v.Bool(); variable {
|
||||
buffer.WriteString("True")
|
||||
} else {
|
||||
buffer.WriteString("False")
|
||||
}
|
||||
case reflect.Float32:
|
||||
buffer.WriteString(strconv.FormatFloat(v.Float(), 'f', -1, 32))
|
||||
case reflect.Float64:
|
||||
buffer.WriteString(strconv.FormatFloat(v.Float(), 'f', -1, 64))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
buffer.WriteString(strconv.FormatInt(v.Int(), 10))
|
||||
case reflect.String:
|
||||
buffer.WriteString(v.String())
|
||||
case reflect.Array, reflect.Slice:
|
||||
buffer.WriteString("[")
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
text, err := j.evalToText(v.Index(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer.Write(text)
|
||||
if i != v.Len()-1 {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
}
|
||||
buffer.WriteString("]")
|
||||
case reflect.Struct:
|
||||
buffer.WriteString("{")
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
text, err := j.evalToText(v.Field(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pair := fmt.Sprintf("%s: %s", v.Type().Field(i).Name, text)
|
||||
buffer.WriteString(pair)
|
||||
if i != v.NumField()-1 {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
}
|
||||
buffer.WriteString("}")
|
||||
case reflect.Map:
|
||||
buffer.WriteString("{")
|
||||
for i, key := range v.MapKeys() {
|
||||
text, err := j.evalToText(v.MapIndex(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pair := fmt.Sprintf("%s: %s", key, text)
|
||||
buffer.WriteString(pair)
|
||||
if i != len(v.MapKeys())-1 {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
}
|
||||
buffer.WriteString("}")
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("%v is not printable", v.Kind())
|
||||
}
|
||||
fmt.Fprint(&buffer, iface)
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ package jsonpath
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -69,25 +70,30 @@ func testFailJSONPath(tests []jsonpathTest, t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type book struct {
|
||||
Category string
|
||||
Author string
|
||||
Title string
|
||||
Price float32
|
||||
}
|
||||
|
||||
func (b book) String() string {
|
||||
return fmt.Sprintf("{Category: %s, Author: %s, Title: %s, Price: %v}", b.Category, b.Author, b.Title, b.Price)
|
||||
}
|
||||
|
||||
type bicycle struct {
|
||||
Color string
|
||||
Price float32
|
||||
}
|
||||
|
||||
type store struct {
|
||||
Book []book
|
||||
Bicycle bicycle
|
||||
Name string
|
||||
Labels map[string]int
|
||||
}
|
||||
|
||||
func TestStructInput(t *testing.T) {
|
||||
type book struct {
|
||||
Category string
|
||||
Author string
|
||||
Title string
|
||||
Price float32
|
||||
}
|
||||
|
||||
type bicycle struct {
|
||||
Color string
|
||||
Price float32
|
||||
}
|
||||
|
||||
type store struct {
|
||||
Book []book
|
||||
Bicycle bicycle
|
||||
Name string
|
||||
Labels map[string]int
|
||||
}
|
||||
|
||||
storeData := store{
|
||||
Name: "jsonpath",
|
||||
@@ -106,13 +112,13 @@ func TestStructInput(t *testing.T) {
|
||||
|
||||
storeTests := []jsonpathTest{
|
||||
{"plain", "hello jsonpath", nil, "hello jsonpath"},
|
||||
{"recursive", "{..}", []int{1, 2, 3}, "[1, 2, 3]"},
|
||||
{"recursive", "{..}", []int{1, 2, 3}, "[1 2 3]"},
|
||||
{"filter", "{[?(@<5)]}", []int{2, 6, 3, 7}, "2 3"},
|
||||
{"quote", `{"{"}`, nil, "{"},
|
||||
{"union", "{[1,3,4]}", []int{0, 1, 2, 3, 4}, "1 3 4"},
|
||||
{"array", "{[0:2]}", []string{"Monday", "Tudesday"}, "Monday Tudesday"},
|
||||
{"variable", "hello {.Name}", storeData, "hello jsonpath"},
|
||||
{"dict/", "{.Labels.web/html}", storeData, "15"},
|
||||
{"dict/", "{$.Labels.web/html}", storeData, "15"},
|
||||
{"dict-", "{.Labels.k8s-app}", storeData, "20"},
|
||||
{"nest", "{.Bicycle.Color}", storeData, "red"},
|
||||
{"allarray", "{.Book[*].Author}", storeData, "Nigel Rees Evelyn Waugh Herman Melville"},
|
||||
@@ -197,18 +203,20 @@ func TestKubenates(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
nodesTests := []jsonpathTest{
|
||||
{"range item", "{range .items[*]}{.metadata.name}, {end}{.kind}", nodesData, `127.0.0.1, 127.0.0.2, List`},
|
||||
{"range addresss", "{.items[*].status.addresses[*].address}", nodesData,
|
||||
`127.0.0.1 127.0.0.2 127.0.0.3`},
|
||||
{"double range", "{range .items[*]}{range .status.addresses[*]}{.address}, {end}{end}", nodesData,
|
||||
`127.0.0.1, 127.0.0.2, 127.0.0.3, `},
|
||||
{"recursive name", "{..name}", nodesData, `127.0.0.1 127.0.0.2 myself e2e`},
|
||||
{"item name", "{.items[*].metadata.name}", nodesData, `127.0.0.1 127.0.0.2`},
|
||||
{"union nodes capacity", "{.items[*]['metadata.name', 'status.capacity']}", nodesData,
|
||||
`127.0.0.1 127.0.0.2 {cpu: 4} {cpu: 8}`},
|
||||
`127.0.0.1 127.0.0.2 map[cpu:4] map[cpu:8]`},
|
||||
{"range nodes capacity", "{range .items[*]}[{.metadata.name}, {.status.capacity}] {end}", nodesData,
|
||||
`[127.0.0.1, {cpu: 4}] [127.0.0.2, {cpu: 8}] `},
|
||||
{"user password", `{.users[?(@.name=="e2e")].user.password}`, nodesData, "secret"},
|
||||
`[127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]] `},
|
||||
{"user password", `{.users[?(@.name=="e2e")].user.password}`, &nodesData, "secret"},
|
||||
}
|
||||
testJSONPath(nodesTests, t)
|
||||
}
|
||||
|
@@ -151,7 +151,7 @@ func (p *Parser) parseInsideAction(cur *ListNode) error {
|
||||
return fmt.Errorf("unclosed action")
|
||||
case r == ' ':
|
||||
p.consumeText()
|
||||
case r == '@': //the current object, just pass it
|
||||
case r == '@' || r == '$': //the current object, just pass it
|
||||
p.consumeText()
|
||||
case r == '[':
|
||||
return p.parseArray(cur)
|
||||
|
Reference in New Issue
Block a user