1
16
17 package explain
18
19 import (
20 "fmt"
21 "io"
22 "strings"
23
24 "k8s.io/apimachinery/pkg/api/meta"
25 "k8s.io/apimachinery/pkg/runtime/schema"
26 "k8s.io/client-go/util/jsonpath"
27 "k8s.io/kube-openapi/pkg/util/proto"
28 )
29
30 type fieldsPrinter interface {
31 PrintFields(proto.Schema) error
32 }
33
34
35 func jsonPathParse(in string) ([]jsonpath.Node, error) {
36
37 in = strings.TrimSuffix(in, ".")
38
39
40 jpp, err := jsonpath.Parse("user", "{."+in+"}")
41 if err != nil {
42 return nil, err
43 }
44
45
46
47
48 outerNodeList := jpp.Root.Nodes
49 if len(outerNodeList) != 1 {
50 return nil, fmt.Errorf("must pass in 1 jsonpath string")
51 }
52
53
54 return outerNodeList[0].(*jsonpath.ListNode).Nodes, nil
55 }
56
57
58 func SplitAndParseResourceRequest(inResource string, mapper meta.RESTMapper) (schema.GroupVersionResource, []string, error) {
59 inResourceNodeList, err := jsonPathParse(inResource)
60 if err != nil {
61 return schema.GroupVersionResource{}, nil, err
62 }
63
64 if inResourceNodeList[0].Type() != jsonpath.NodeField {
65 return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node")
66 }
67 resource := inResourceNodeList[0].(*jsonpath.FieldNode).Value
68 gvr, err := mapper.ResourceFor(schema.GroupVersionResource{Resource: resource})
69 if err != nil {
70 return schema.GroupVersionResource{}, nil, err
71 }
72
73 var fieldsPath []string
74 for _, node := range inResourceNodeList[1:] {
75 if node.Type() != jsonpath.NodeField {
76 return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, all nodes must be field nodes")
77 }
78 fieldsPath = append(fieldsPath, node.(*jsonpath.FieldNode).Value)
79 }
80
81 return gvr, fieldsPath, nil
82 }
83
84
85
86 func SplitAndParseResourceRequestWithMatchingPrefix(inResource string, mapper meta.RESTMapper) (gvr schema.GroupVersionResource, fieldsPath []string, err error) {
87 inResourceNodeList, err := jsonPathParse(inResource)
88 if err != nil {
89 return schema.GroupVersionResource{}, nil, err
90 }
91
92
93 if inResourceNodeList[0].Type() != jsonpath.NodeField {
94 return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node")
95 }
96 resource := inResourceNodeList[0].(*jsonpath.FieldNode).Value
97
98 gvrs, err := mapper.ResourcesFor(schema.GroupVersionResource{Resource: resource})
99 if err != nil {
100 return schema.GroupVersionResource{}, nil, err
101 }
102
103 for _, gvrItem := range gvrs {
104
105 groupResource := gvrItem.GroupResource().String()
106 if strings.HasPrefix(inResource, groupResource) {
107 resourceSuffix := inResource[len(groupResource):]
108 var fieldsPath []string
109 if len(resourceSuffix) > 0 {
110
111 resourceSuffixNodeList, err := jsonPathParse(resourceSuffix)
112 if err != nil {
113 return schema.GroupVersionResource{}, nil, err
114 }
115
116 if len(resourceSuffixNodeList) > 0 {
117 nodeList := resourceSuffixNodeList[1:]
118 for _, node := range nodeList {
119 if node.Type() != jsonpath.NodeField {
120 return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node")
121 }
122 fieldsPath = append(fieldsPath, node.(*jsonpath.FieldNode).Value)
123 }
124 }
125 }
126 return gvrItem, fieldsPath, nil
127 }
128 }
129
130
131 fieldsPath = []string{}
132 if len(gvrs) > 0 {
133 gvr = gvrs[0]
134
135 fieldsPathNodeList, err := jsonPathParse(inResource)
136 if err != nil {
137 return schema.GroupVersionResource{}, nil, err
138 }
139
140 for _, node := range fieldsPathNodeList[1:] {
141 if node.Type() != jsonpath.NodeField {
142 return schema.GroupVersionResource{}, nil, fmt.Errorf("invalid jsonpath syntax, first node must be field node")
143 }
144 fieldsPath = append(fieldsPath, node.(*jsonpath.FieldNode).Value)
145 }
146 }
147
148 return gvr, fieldsPath, nil
149 }
150
151
152
153
154 func PrintModelDescription(fieldsPath []string, w io.Writer, schema proto.Schema, gvk schema.GroupVersionKind, recursive bool) error {
155 fieldName := ""
156 if len(fieldsPath) != 0 {
157 fieldName = fieldsPath[len(fieldsPath)-1]
158 }
159
160
161 schema, err := LookupSchemaForField(schema, fieldsPath)
162 if err != nil {
163 return err
164 }
165 b := fieldsPrinterBuilder{Recursive: recursive}
166 f := &Formatter{Writer: w, Wrap: 80}
167 return PrintModel(fieldName, f, b, schema, gvk)
168 }
169
View as plain text