1
16
17 package roundtrip
18
19 import (
20 "fmt"
21 "reflect"
22 "strconv"
23 "strings"
24 "time"
25
26 apimeta "k8s.io/apimachinery/pkg/api/meta"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apimachinery/pkg/util/intstr"
31 )
32
33
34
35
36 func defaultFillFuncs() map[reflect.Type]FillFunc {
37 funcs := map[reflect.Type]FillFunc{}
38 funcs[reflect.TypeOf(&runtime.RawExtension{})] = func(s string, i int, obj interface{}) {
39
40
41 obj.(*runtime.RawExtension).Raw = []byte(`{"apiVersion":"example.com/v1","kind":"CustomType","spec":{"replicas":1},"status":{"available":1}}`)
42 }
43 funcs[reflect.TypeOf(&metav1.TypeMeta{})] = func(s string, i int, obj interface{}) {
44
45 obj.(*metav1.TypeMeta).APIVersion = ""
46 obj.(*metav1.TypeMeta).Kind = ""
47 }
48 funcs[reflect.TypeOf(&metav1.FieldsV1{})] = func(s string, i int, obj interface{}) {
49 obj.(*metav1.FieldsV1).Raw = []byte(`{}`)
50 }
51 funcs[reflect.TypeOf(&metav1.Time{})] = func(s string, i int, obj interface{}) {
52
53 obj.(*metav1.Time).Time = time.Date(2000+i, 1, 1, 1, 1, 1, 0, time.UTC)
54 }
55 funcs[reflect.TypeOf(&metav1.MicroTime{})] = func(s string, i int, obj interface{}) {
56
57 obj.(*metav1.MicroTime).Time = time.Date(2000+i, 1, 1, 1, 1, 1, i*int(time.Microsecond), time.UTC)
58 }
59 funcs[reflect.TypeOf(&intstr.IntOrString{})] = func(s string, i int, obj interface{}) {
60
61 obj.(*intstr.IntOrString).Type = intstr.String
62 obj.(*intstr.IntOrString).StrVal = s + "Value"
63 }
64 return funcs
65 }
66
67
68 func CompatibilityTestObject(scheme *runtime.Scheme, gvk schema.GroupVersionKind, fillFuncs map[reflect.Type]FillFunc) (runtime.Object, error) {
69
70 obj, err := scheme.New(gvk)
71 if err != nil {
72 return nil, err
73 }
74
75 fill("", 0, reflect.TypeOf(obj), reflect.ValueOf(obj), fillFuncs, map[reflect.Type]bool{})
76
77
78 if typeAcc, err := apimeta.TypeAccessor(obj); err != nil {
79 return nil, err
80 } else {
81 typeAcc.SetKind(gvk.Kind)
82 typeAcc.SetAPIVersion(gvk.GroupVersion().String())
83 }
84
85 return obj, nil
86 }
87
88 func fill(dataString string, dataInt int, t reflect.Type, v reflect.Value, fillFuncs map[reflect.Type]FillFunc, filledTypes map[reflect.Type]bool) {
89 if filledTypes[t] {
90
91 return
92 }
93 filledTypes[t] = true
94 defer delete(filledTypes, t)
95
96
97 if t.Kind() == reflect.Pointer && v.IsNil() {
98 if v.CanSet() {
99 v.Set(reflect.New(t.Elem()))
100 } else if v.IsNil() {
101 panic(fmt.Errorf("unsettable nil pointer of type %v in field %s", t, dataString))
102 }
103 }
104
105 if f, ok := fillFuncs[t]; ok {
106
107 f(dataString, dataInt, v.Interface())
108 return
109 }
110
111 switch t.Kind() {
112 case reflect.Slice:
113
114 v.Set(reflect.MakeSlice(t, 1, 1))
115
116 fill(dataString, dataInt, t.Elem(), v.Index(0), fillFuncs, filledTypes)
117
118 case reflect.Map:
119
120 key := reflect.ValueOf(dataString + "Key").Convert(t.Key())
121
122 item := reflect.New(t.Elem())
123
124 fill(dataString, dataInt, t.Elem(), item.Elem(), fillFuncs, filledTypes)
125
126 v.Set(reflect.MakeMap(t))
127 v.SetMapIndex(key, item.Elem())
128
129 case reflect.Struct:
130 for i := 0; i < t.NumField(); i++ {
131 field := t.Field(i)
132
133 if !field.IsExported() {
134 continue
135 }
136
137
138 dataString := strings.Split(field.Tag.Get("json"), ",")[0]
139 if len(dataString) == 0 {
140
141 dataString = "<no json tag> " + field.Name
142 }
143
144
145 dataInt := 0
146 if protobufTagParts := strings.Split(field.Tag.Get("protobuf"), ","); len(protobufTagParts) > 1 {
147 if tag, err := strconv.Atoi(protobufTagParts[1]); err != nil {
148 panic(err)
149 } else {
150 dataInt = tag
151 }
152 }
153 if dataInt == 0 {
154
155 dataInt = -len(dataString)
156 }
157
158 fieldType := field.Type
159 fieldValue := v.Field(i)
160
161 fill(dataString, dataInt, reflect.PointerTo(fieldType), fieldValue.Addr(), fillFuncs, filledTypes)
162 }
163
164 case reflect.Pointer:
165 fill(dataString, dataInt, t.Elem(), v.Elem(), fillFuncs, filledTypes)
166
167 case reflect.String:
168
169 v.Set(reflect.ValueOf(dataString + "Value").Convert(t))
170
171 case reflect.Bool:
172
173 v.Set(reflect.ValueOf(true).Convert(t))
174
175 case reflect.Int, reflect.Uint, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
176
177 v.Set(reflect.ValueOf(dataInt).Convert(t))
178 case reflect.Float64, reflect.Float32:
179 v.Set(reflect.ValueOf(dataInt).Convert(t))
180
181 default:
182 panic(fmt.Errorf("unhandled type %v in field %s", t, dataString))
183 }
184 }
185
View as plain text