sorter.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package get
  14. import (
  15. "fmt"
  16. "io"
  17. "reflect"
  18. "sort"
  19. "k8s.io/klog"
  20. corev1 "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/api/meta"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
  24. metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
  25. "k8s.io/apimachinery/pkg/runtime"
  26. "k8s.io/cli-runtime/pkg/printers"
  27. "k8s.io/client-go/util/jsonpath"
  28. "k8s.io/utils/integer"
  29. "vbom.ml/util/sortorder"
  30. )
  31. // SortingPrinter sorts list types before delegating to another printer.
  32. // Non-list types are simply passed through
  33. type SortingPrinter struct {
  34. SortField string
  35. Delegate printers.ResourcePrinter
  36. Decoder runtime.Decoder
  37. }
  38. func (s *SortingPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
  39. if table, isTable := obj.(*metav1beta1.Table); isTable && len(table.Rows) > 1 {
  40. parsedField, err := RelaxedJSONPathExpression(s.SortField)
  41. if err != nil {
  42. parsedField = s.SortField
  43. }
  44. if sorter, err := NewTableSorter(table, parsedField); err != nil {
  45. return err
  46. } else if err := sorter.Sort(); err != nil {
  47. return err
  48. }
  49. return s.Delegate.PrintObj(table, out)
  50. }
  51. if meta.IsListType(obj) {
  52. if err := s.sortObj(obj); err != nil {
  53. return err
  54. }
  55. return s.Delegate.PrintObj(obj, out)
  56. }
  57. return s.Delegate.PrintObj(obj, out)
  58. }
  59. func (s *SortingPrinter) sortObj(obj runtime.Object) error {
  60. objs, err := meta.ExtractList(obj)
  61. if err != nil {
  62. return err
  63. }
  64. if len(objs) == 0 {
  65. return nil
  66. }
  67. sorter, err := SortObjects(s.Decoder, objs, s.SortField)
  68. if err != nil {
  69. return err
  70. }
  71. switch list := obj.(type) {
  72. case *corev1.List:
  73. outputList := make([]runtime.RawExtension, len(objs))
  74. for ix := range objs {
  75. outputList[ix] = list.Items[sorter.OriginalPosition(ix)]
  76. }
  77. list.Items = outputList
  78. return nil
  79. }
  80. return meta.SetList(obj, objs)
  81. }
  82. func SortObjects(decoder runtime.Decoder, objs []runtime.Object, fieldInput string) (*RuntimeSort, error) {
  83. for ix := range objs {
  84. item := objs[ix]
  85. switch u := item.(type) {
  86. case *runtime.Unknown:
  87. var err error
  88. // decode runtime.Unknown to runtime.Unstructured for sorting.
  89. // we don't actually want the internal versions of known types.
  90. if objs[ix], _, err = decoder.Decode(u.Raw, nil, &unstructured.Unstructured{}); err != nil {
  91. return nil, err
  92. }
  93. }
  94. }
  95. field, err := RelaxedJSONPathExpression(fieldInput)
  96. if err != nil {
  97. return nil, err
  98. }
  99. parser := jsonpath.New("sorting").AllowMissingKeys(true)
  100. if err := parser.Parse(field); err != nil {
  101. return nil, err
  102. }
  103. // We don't do any model validation here, so we traverse all objects to be sorted
  104. // and, if the field is valid to at least one of them, we consider it to be a
  105. // valid field; otherwise error out.
  106. // Note that this requires empty fields to be considered later, when sorting.
  107. var fieldFoundOnce bool
  108. for _, obj := range objs {
  109. values, err := findJSONPathResults(parser, obj)
  110. if err != nil {
  111. return nil, err
  112. }
  113. if len(values) > 0 && len(values[0]) > 0 {
  114. fieldFoundOnce = true
  115. break
  116. }
  117. }
  118. if !fieldFoundOnce {
  119. return nil, fmt.Errorf("couldn't find any field with path %q in the list of objects", field)
  120. }
  121. sorter := NewRuntimeSort(field, objs)
  122. sort.Sort(sorter)
  123. return sorter, nil
  124. }
  125. // RuntimeSort is an implementation of the golang sort interface that knows how to sort
  126. // lists of runtime.Object
  127. type RuntimeSort struct {
  128. field string
  129. objs []runtime.Object
  130. origPosition []int
  131. }
  132. func NewRuntimeSort(field string, objs []runtime.Object) *RuntimeSort {
  133. sorter := &RuntimeSort{field: field, objs: objs, origPosition: make([]int, len(objs))}
  134. for ix := range objs {
  135. sorter.origPosition[ix] = ix
  136. }
  137. return sorter
  138. }
  139. func (r *RuntimeSort) Len() int {
  140. return len(r.objs)
  141. }
  142. func (r *RuntimeSort) Swap(i, j int) {
  143. r.objs[i], r.objs[j] = r.objs[j], r.objs[i]
  144. r.origPosition[i], r.origPosition[j] = r.origPosition[j], r.origPosition[i]
  145. }
  146. func isLess(i, j reflect.Value) (bool, error) {
  147. switch i.Kind() {
  148. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  149. return i.Int() < j.Int(), nil
  150. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  151. return i.Uint() < j.Uint(), nil
  152. case reflect.Float32, reflect.Float64:
  153. return i.Float() < j.Float(), nil
  154. case reflect.String:
  155. return sortorder.NaturalLess(i.String(), j.String()), nil
  156. case reflect.Ptr:
  157. return isLess(i.Elem(), j.Elem())
  158. case reflect.Struct:
  159. // sort metav1.Time
  160. in := i.Interface()
  161. if t, ok := in.(metav1.Time); ok {
  162. time := j.Interface().(metav1.Time)
  163. return t.Before(&time), nil
  164. }
  165. // fallback to the fields comparison
  166. for idx := 0; idx < i.NumField(); idx++ {
  167. less, err := isLess(i.Field(idx), j.Field(idx))
  168. if err != nil || !less {
  169. return less, err
  170. }
  171. }
  172. return true, nil
  173. case reflect.Array, reflect.Slice:
  174. // note: the length of i and j may be different
  175. for idx := 0; idx < integer.IntMin(i.Len(), j.Len()); idx++ {
  176. less, err := isLess(i.Index(idx), j.Index(idx))
  177. if err != nil || !less {
  178. return less, err
  179. }
  180. }
  181. return true, nil
  182. case reflect.Interface:
  183. switch itype := i.Interface().(type) {
  184. case uint8:
  185. if jtype, ok := j.Interface().(uint8); ok {
  186. return itype < jtype, nil
  187. }
  188. case uint16:
  189. if jtype, ok := j.Interface().(uint16); ok {
  190. return itype < jtype, nil
  191. }
  192. case uint32:
  193. if jtype, ok := j.Interface().(uint32); ok {
  194. return itype < jtype, nil
  195. }
  196. case uint64:
  197. if jtype, ok := j.Interface().(uint64); ok {
  198. return itype < jtype, nil
  199. }
  200. case int8:
  201. if jtype, ok := j.Interface().(int8); ok {
  202. return itype < jtype, nil
  203. }
  204. case int16:
  205. if jtype, ok := j.Interface().(int16); ok {
  206. return itype < jtype, nil
  207. }
  208. case int32:
  209. if jtype, ok := j.Interface().(int32); ok {
  210. return itype < jtype, nil
  211. }
  212. case int64:
  213. if jtype, ok := j.Interface().(int64); ok {
  214. return itype < jtype, nil
  215. }
  216. case uint:
  217. if jtype, ok := j.Interface().(uint); ok {
  218. return itype < jtype, nil
  219. }
  220. case int:
  221. if jtype, ok := j.Interface().(int); ok {
  222. return itype < jtype, nil
  223. }
  224. case float32:
  225. if jtype, ok := j.Interface().(float32); ok {
  226. return itype < jtype, nil
  227. }
  228. case float64:
  229. if jtype, ok := j.Interface().(float64); ok {
  230. return itype < jtype, nil
  231. }
  232. case string:
  233. if jtype, ok := j.Interface().(string); ok {
  234. return sortorder.NaturalLess(itype, jtype), nil
  235. }
  236. default:
  237. return false, fmt.Errorf("unsortable type: %T", itype)
  238. }
  239. return false, fmt.Errorf("unsortable interface: %v", i.Kind())
  240. default:
  241. return false, fmt.Errorf("unsortable type: %v", i.Kind())
  242. }
  243. }
  244. func (r *RuntimeSort) Less(i, j int) bool {
  245. iObj := r.objs[i]
  246. jObj := r.objs[j]
  247. var iValues [][]reflect.Value
  248. var jValues [][]reflect.Value
  249. var err error
  250. parser := jsonpath.New("sorting").AllowMissingKeys(true)
  251. err = parser.Parse(r.field)
  252. if err != nil {
  253. panic(err)
  254. }
  255. iValues, err = findJSONPathResults(parser, iObj)
  256. if err != nil {
  257. klog.Fatalf("Failed to get i values for %#v using %s (%#v)", iObj, r.field, err)
  258. }
  259. jValues, err = findJSONPathResults(parser, jObj)
  260. if err != nil {
  261. klog.Fatalf("Failed to get j values for %#v using %s (%v)", jObj, r.field, err)
  262. }
  263. if len(iValues) == 0 || len(iValues[0]) == 0 {
  264. return true
  265. }
  266. if len(jValues) == 0 || len(jValues[0]) == 0 {
  267. return false
  268. }
  269. iField := iValues[0][0]
  270. jField := jValues[0][0]
  271. less, err := isLess(iField, jField)
  272. if err != nil {
  273. klog.Fatalf("Field %s in %T is an unsortable type: %s, err: %v", r.field, iObj, iField.Kind().String(), err)
  274. }
  275. return less
  276. }
  277. // OriginalPosition returns the starting (original) position of a particular index.
  278. // e.g. If OriginalPosition(0) returns 5 than the
  279. // the item currently at position 0 was at position 5 in the original unsorted array.
  280. func (r *RuntimeSort) OriginalPosition(ix int) int {
  281. if ix < 0 || ix > len(r.origPosition) {
  282. return -1
  283. }
  284. return r.origPosition[ix]
  285. }
  286. type TableSorter struct {
  287. field string
  288. obj *metav1beta1.Table
  289. parsedRows [][][]reflect.Value
  290. }
  291. func (t *TableSorter) Len() int {
  292. return len(t.obj.Rows)
  293. }
  294. func (t *TableSorter) Swap(i, j int) {
  295. t.obj.Rows[i], t.obj.Rows[j] = t.obj.Rows[j], t.obj.Rows[i]
  296. t.parsedRows[i], t.parsedRows[j] = t.parsedRows[j], t.parsedRows[i]
  297. }
  298. func (t *TableSorter) Less(i, j int) bool {
  299. iValues := t.parsedRows[i]
  300. jValues := t.parsedRows[j]
  301. if len(iValues) == 0 || len(iValues[0]) == 0 {
  302. return true
  303. }
  304. if len(jValues) == 0 || len(jValues[0]) == 0 {
  305. return false
  306. }
  307. iField := iValues[0][0]
  308. jField := jValues[0][0]
  309. less, err := isLess(iField, jField)
  310. if err != nil {
  311. klog.Fatalf("Field %s in %T is an unsortable type: %s, err: %v", t.field, t.parsedRows, iField.Kind().String(), err)
  312. }
  313. return less
  314. }
  315. func (t *TableSorter) Sort() error {
  316. sort.Sort(t)
  317. return nil
  318. }
  319. func NewTableSorter(table *metav1beta1.Table, field string) (*TableSorter, error) {
  320. var parsedRows [][][]reflect.Value
  321. parser := jsonpath.New("sorting").AllowMissingKeys(true)
  322. err := parser.Parse(field)
  323. if err != nil {
  324. return nil, fmt.Errorf("sorting error: %v", err)
  325. }
  326. fieldFoundOnce := false
  327. for i := range table.Rows {
  328. parsedRow, err := findJSONPathResults(parser, table.Rows[i].Object.Object)
  329. if err != nil {
  330. return nil, fmt.Errorf("Failed to get values for %#v using %s (%#v)", parsedRow, field, err)
  331. }
  332. parsedRows = append(parsedRows, parsedRow)
  333. if len(parsedRow) > 0 && len(parsedRow[0]) > 0 {
  334. fieldFoundOnce = true
  335. }
  336. }
  337. if len(table.Rows) > 0 && !fieldFoundOnce {
  338. return nil, fmt.Errorf("couldn't find any field with path %q in the list of objects", field)
  339. }
  340. return &TableSorter{
  341. obj: table,
  342. field: field,
  343. parsedRows: parsedRows,
  344. }, nil
  345. }
  346. func findJSONPathResults(parser *jsonpath.JSONPath, from runtime.Object) ([][]reflect.Value, error) {
  347. if unstructuredObj, ok := from.(*unstructured.Unstructured); ok {
  348. return parser.FindResults(unstructuredObj.Object)
  349. }
  350. return parser.FindResults(reflect.ValueOf(from).Elem().Interface())
  351. }