github.com/grahambrereton-form3/tilt@v0.10.18/internal/k8s/extract.go (about) 1 package k8s 2 3 import ( 4 "fmt" 5 "reflect" 6 7 v1 "k8s.io/api/core/v1" 8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 ) 10 11 func ExtractPods(obj interface{}) ([]*v1.PodSpec, error) { 12 extracted, err := newExtractor(reflect.TypeOf(v1.PodSpec{})).extractPointersFrom(obj) 13 if err != nil { 14 return nil, err 15 } 16 17 result := make([]*v1.PodSpec, len(extracted)) 18 for i, e := range extracted { 19 c, ok := e.(*v1.PodSpec) 20 if !ok { 21 return nil, fmt.Errorf("extractPods: expected Pod, actual %T", e) 22 } 23 result[i] = c 24 } 25 return result, nil 26 } 27 28 func ExtractPodTemplateSpec(obj interface{}) ([]*v1.PodTemplateSpec, error) { 29 extracted, err := newExtractor(reflect.TypeOf(v1.PodTemplateSpec{})).extractPointersFrom(obj) 30 if err != nil { 31 return nil, err 32 } 33 34 result := make([]*v1.PodTemplateSpec, len(extracted)) 35 for i, e := range extracted { 36 c, ok := e.(*v1.PodTemplateSpec) 37 if !ok { 38 return nil, fmt.Errorf("extractPods: expected Pod, actual %T", e) 39 } 40 result[i] = c 41 } 42 return result, nil 43 } 44 45 func extractObjectMetas(obj interface{}, filter func(v reflect.Value) bool) ([]*metav1.ObjectMeta, error) { 46 extracted, err := newExtractor(reflect.TypeOf(metav1.ObjectMeta{})). 47 withFilter(filter). 48 extractPointersFrom(obj) 49 if err != nil { 50 return nil, err 51 } 52 53 result := make([]*metav1.ObjectMeta, len(extracted)) 54 for i, e := range extracted { 55 c, ok := e.(*metav1.ObjectMeta) 56 if !ok { 57 return nil, fmt.Errorf("ExtractObjectMetas: expected ObjectMeta, actual %T", e) 58 } 59 result[i] = c 60 } 61 return result, nil 62 } 63 64 func extractSelectors(obj interface{}, filter func(v reflect.Value) bool) ([]*metav1.LabelSelector, error) { 65 extracted, err := newExtractor(reflect.TypeOf(metav1.LabelSelector{})). 66 withFilter(filter). 67 extractPointersFrom(obj) 68 if err != nil { 69 return nil, err 70 } 71 72 result := make([]*metav1.LabelSelector, len(extracted)) 73 for i, e := range extracted { 74 c, ok := e.(*metav1.LabelSelector) 75 if !ok { 76 return nil, fmt.Errorf("ExtractSelectors: expected LabelSelector, actual %T", e) 77 } 78 result[i] = c 79 } 80 return result, nil 81 } 82 83 func extractEnvVars(obj interface{}) ([]*v1.EnvVar, error) { 84 extracted, err := newExtractor(reflect.TypeOf(v1.EnvVar{})).extractPointersFrom(obj) 85 if err != nil { 86 return nil, err 87 } 88 89 result := make([]*v1.EnvVar, len(extracted)) 90 for i, e := range extracted { 91 ev, ok := e.(*v1.EnvVar) 92 if !ok { 93 return nil, fmt.Errorf("extractEnvVars: expected %T, actual %T", v1.EnvVar{}, e) 94 } 95 result[i] = ev 96 } 97 return result, nil 98 } 99 100 func extractContainers(obj interface{}) ([]*v1.Container, error) { 101 extracted, err := newExtractor(reflect.TypeOf(v1.Container{})).extractPointersFrom(obj) 102 if err != nil { 103 return nil, err 104 } 105 106 result := make([]*v1.Container, len(extracted)) 107 for i, e := range extracted { 108 c, ok := e.(*v1.Container) 109 if !ok { 110 return nil, fmt.Errorf("extractContainers: expected Container, actual %T", e) 111 } 112 result[i] = c 113 } 114 return result, nil 115 } 116 117 type extractor struct { 118 // The type we want to return pointers to 119 pType reflect.Type 120 121 // Return true to visit the value, or false to skip it. 122 filter func(v reflect.Value) bool 123 } 124 125 func newExtractor(pType reflect.Type) extractor { 126 return extractor{ 127 pType: pType, 128 filter: NoFilter, 129 } 130 } 131 132 func (e extractor) withFilter(f func(v reflect.Value) bool) extractor { 133 e.filter = f 134 return e 135 } 136 137 // Get pointers to all the pType structs in this object. 138 func (e extractor) extractPointersFrom(obj interface{}) ([]interface{}, error) { 139 v := reflect.ValueOf(obj) 140 result := make([]interface{}, 0) 141 142 // Recursively iterate over the struct fields. 143 var extract func(v reflect.Value) error 144 extract = func(v reflect.Value) error { 145 if !e.filter(v) { 146 return nil 147 } 148 149 switch v.Kind() { 150 case reflect.Ptr, reflect.Interface: 151 if v.IsNil() { 152 return nil 153 } 154 return extract(v.Elem()) 155 156 case reflect.Struct: 157 if v.Type() == e.pType { 158 if !v.CanAddr() { 159 return fmt.Errorf("Error addressing: %v", v) 160 } 161 result = append(result, v.Addr().Interface()) 162 return nil 163 } 164 165 for i := 0; i < v.NumField(); i++ { 166 field := v.Field(i) 167 err := extract(field) 168 if err != nil { 169 return err 170 } 171 } 172 return nil 173 174 case reflect.Slice: 175 for i := 0; i < v.Len(); i++ { 176 field := v.Index(i) 177 err := extract(field) 178 if err != nil { 179 return err 180 } 181 } 182 return nil 183 184 } 185 return nil 186 } 187 188 err := extract(v) 189 if err != nil { 190 return nil, err 191 } 192 return result, nil 193 } 194 195 var NoFilter = func(v reflect.Value) bool { 196 return true 197 }