...
1
16
17 package printers
18
19 import (
20 "fmt"
21 "reflect"
22
23 "k8s.io/apimachinery/pkg/api/meta"
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/apimachinery/pkg/runtime"
26 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
27 )
28
29
30 type GenerateOptions struct {
31 NoHeaders bool
32 Wide bool
33 }
34
35
36 type TableGenerator interface {
37 GenerateTable(obj runtime.Object, options GenerateOptions) (*metav1.Table, error)
38 }
39
40
41 type PrintHandler interface {
42 TableHandler(columns []metav1.TableColumnDefinition, printFunc interface{}) error
43 }
44
45 type handlerEntry struct {
46 columnDefinitions []metav1.TableColumnDefinition
47 printFunc reflect.Value
48 }
49
50
51
52
53 type HumanReadableGenerator struct {
54 handlerMap map[reflect.Type]*handlerEntry
55 }
56
57 var _ TableGenerator = &HumanReadableGenerator{}
58 var _ PrintHandler = &HumanReadableGenerator{}
59
60
61 func NewTableGenerator() *HumanReadableGenerator {
62 return &HumanReadableGenerator{
63 handlerMap: make(map[reflect.Type]*handlerEntry),
64 }
65 }
66
67
68 func (h *HumanReadableGenerator) With(fns ...func(PrintHandler)) *HumanReadableGenerator {
69 for _, fn := range fns {
70 fn(h)
71 }
72 return h
73 }
74
75
76
77
78 func (h *HumanReadableGenerator) GenerateTable(obj runtime.Object, options GenerateOptions) (*metav1.Table, error) {
79 t := reflect.TypeOf(obj)
80 handler, ok := h.handlerMap[t]
81 if !ok {
82 return nil, fmt.Errorf("no table handler registered for this type %v", t)
83 }
84
85 args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
86 results := handler.printFunc.Call(args)
87 if !results[1].IsNil() {
88 return nil, results[1].Interface().(error)
89 }
90
91 var columns []metav1.TableColumnDefinition
92 if !options.NoHeaders {
93 columns = handler.columnDefinitions
94 if !options.Wide {
95 columns = make([]metav1.TableColumnDefinition, 0, len(handler.columnDefinitions))
96 for i := range handler.columnDefinitions {
97 if handler.columnDefinitions[i].Priority != 0 {
98 continue
99 }
100 columns = append(columns, handler.columnDefinitions[i])
101 }
102 }
103 }
104 table := &metav1.Table{
105 ListMeta: metav1.ListMeta{
106 ResourceVersion: "",
107 },
108 ColumnDefinitions: columns,
109 Rows: results[0].Interface().([]metav1.TableRow),
110 }
111 if m, err := meta.ListAccessor(obj); err == nil {
112 table.ResourceVersion = m.GetResourceVersion()
113 table.Continue = m.GetContinue()
114 table.RemainingItemCount = m.GetRemainingItemCount()
115 } else {
116 if m, err := meta.CommonAccessor(obj); err == nil {
117 table.ResourceVersion = m.GetResourceVersion()
118 }
119 }
120 return table, nil
121 }
122
123
124
125 func (h *HumanReadableGenerator) TableHandler(columnDefinitions []metav1.TableColumnDefinition, printFunc interface{}) error {
126 printFuncValue := reflect.ValueOf(printFunc)
127 if err := ValidateRowPrintHandlerFunc(printFuncValue); err != nil {
128 utilruntime.HandleError(fmt.Errorf("unable to register print function: %v", err))
129 return err
130 }
131 entry := &handlerEntry{
132 columnDefinitions: columnDefinitions,
133 printFunc: printFuncValue,
134 }
135
136 objType := printFuncValue.Type().In(0)
137 if _, ok := h.handlerMap[objType]; ok {
138 err := fmt.Errorf("registered duplicate printer for %v", objType)
139 utilruntime.HandleError(err)
140 return err
141 }
142 h.handlerMap[objType] = entry
143 return nil
144 }
145
146
147
148
149
150
151
152
153
154
155 func ValidateRowPrintHandlerFunc(printFunc reflect.Value) error {
156 if printFunc.Kind() != reflect.Func {
157 return fmt.Errorf("invalid print handler. %#v is not a function", printFunc)
158 }
159 funcType := printFunc.Type()
160 if funcType.NumIn() != 2 || funcType.NumOut() != 2 {
161 return fmt.Errorf("invalid print handler." +
162 "Must accept 2 parameters and return 2 value")
163 }
164 if funcType.In(1) != reflect.TypeOf((*GenerateOptions)(nil)).Elem() ||
165 funcType.Out(0) != reflect.TypeOf((*[]metav1.TableRow)(nil)).Elem() ||
166 funcType.Out(1) != reflect.TypeOf((*error)(nil)).Elem() {
167 return fmt.Errorf("invalid print handler. The expected signature is: "+
168 "func handler(obj %v, options GenerateOptions) ([]metav1.TableRow, error)", funcType.In(0))
169 }
170 return nil
171 }
172
View as plain text