github.com/giantswarm/apiextensions/v2@v2.6.2/pkg/crd/crd.go (about) 1 package crd 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "path/filepath" 7 8 "github.com/giantswarm/microerror" 9 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" 10 v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 11 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" 12 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 13 "k8s.io/apimachinery/pkg/runtime/schema" 14 "sigs.k8s.io/yaml" 15 16 "github.com/giantswarm/apiextensions/v2/pkg/crd/internal" 17 ) 18 19 const ( 20 crdKind = "CustomResourceDefinition" 21 ) 22 23 var ( 24 // GroupVersionKind of CustomResourceDefinition in apiextensions.k8s.io/v1beta1. 25 v1beta1GroupVersionKind = schema.GroupVersionKind{ 26 Group: apiextensions.GroupName, 27 Version: "v1beta1", 28 Kind: crdKind, 29 } 30 // GroupVersionKind of CustomResourceDefinition in apiextensions.k8s.io/v1. 31 v1GroupVersionKind = schema.GroupVersionKind{ 32 Group: apiextensions.GroupName, 33 Version: "v1", 34 Kind: crdKind, 35 } 36 ) 37 38 type objectHandler func(data []byte) error 39 40 func iterateResources(groupVersionKind schema.GroupVersionKind, handle objectHandler) error { 41 crdDirectory := fmt.Sprintf("/config/crd/%s", groupVersionKind.Version) 42 fs := internal.FS(false) 43 directory, err := fs.Open(crdDirectory) 44 if err != nil { 45 return microerror.Mask(err) 46 } 47 files, err := directory.Readdir(0) 48 if err != nil { 49 return microerror.Mask(err) 50 } 51 52 for _, info := range files { 53 if info.IsDir() { 54 continue 55 } 56 if filepath.Ext(info.Name()) != ".yaml" { 57 continue 58 } 59 60 // Read the file to a string. 61 file, err := fs.Open(filepath.Join(crdDirectory, info.Name())) 62 if err != nil { 63 return microerror.Mask(err) 64 } 65 contents, err := ioutil.ReadAll(file) 66 if err != nil { 67 return microerror.Mask(err) 68 } 69 70 // Unmarshal into Unstructured since we don't know if this is a v1 or v1beta1 CRD yet. 71 var object unstructured.Unstructured 72 err = yaml.UnmarshalStrict(contents, &object) 73 if err != nil { 74 return microerror.Mask(err) 75 } 76 if object.GetObjectKind().GroupVersionKind() != groupVersionKind { 77 continue 78 } 79 80 if err := handle(contents); err != nil { 81 return microerror.Mask(err) 82 } 83 } 84 85 return nil 86 } 87 88 var cache []v1.CustomResourceDefinition 89 var cacheV1Beta1 []v1beta1.CustomResourceDefinition 90 91 // ListV1Beta1 loads all v1beta1 CRDs from the virtual filesystem. 92 func ListV1Beta1() ([]v1beta1.CustomResourceDefinition, error) { 93 if cacheV1Beta1 != nil { 94 return cacheV1Beta1, nil 95 } 96 97 handler := func(data []byte) error { 98 var crd v1beta1.CustomResourceDefinition 99 err := yaml.UnmarshalStrict(data, &crd) 100 if err != nil { 101 return microerror.Mask(err) 102 } 103 cacheV1Beta1 = append(cacheV1Beta1, crd) 104 return nil 105 } 106 107 err := iterateResources(v1beta1GroupVersionKind, handler) 108 if err != nil { 109 return nil, microerror.Mask(err) 110 } 111 112 return cacheV1Beta1, nil 113 } 114 115 // ListV1 loads all v1 CRDs from the virtual filesystem. 116 func ListV1() ([]v1.CustomResourceDefinition, error) { 117 if cache != nil { 118 return cache, nil 119 } 120 121 handler := func(data []byte) error { 122 var crd v1.CustomResourceDefinition 123 err := yaml.UnmarshalStrict(data, &crd) 124 if err != nil { 125 return microerror.Mask(err) 126 } 127 cache = append(cache, crd) 128 return nil 129 } 130 131 err := iterateResources(v1GroupVersionKind, handler) 132 if err != nil { 133 return nil, microerror.Mask(err) 134 } 135 136 return cache, nil 137 } 138 139 // LoadV1Beta1 loads a v1beta1 CRD from the virtual filesystem. 140 func LoadV1Beta1(group, kind string) *v1beta1.CustomResourceDefinition { 141 crds, err := ListV1Beta1() 142 if err != nil { 143 panic(microerror.Mask(err)) 144 } 145 146 for _, crd := range crds { 147 if crd.Spec.Names.Kind == kind && crd.Spec.Group == group { 148 return &crd 149 } 150 } 151 panic(microerror.Mask(notFoundError)) 152 } 153 154 // LoadV1 loads a v1 CRD from the virtual filesystem 155 func LoadV1(group, kind string) *v1.CustomResourceDefinition { 156 crds, err := ListV1() 157 if err != nil { 158 panic(microerror.Mask(err)) 159 } 160 161 for _, crd := range crds { 162 if crd.Spec.Names.Kind == kind && crd.Spec.Group == group { 163 return &crd 164 } 165 } 166 panic(microerror.Mask(notFoundError)) 167 }