github.com/giantswarm/apiextensions/v6@v6.6.0/pkg/crd/functions.go (about) 1 package crd 2 3 import ( 4 "bufio" 5 "bytes" 6 "errors" 7 "fmt" 8 "io" 9 "os" 10 "path/filepath" 11 12 "github.com/giantswarm/microerror" 13 v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 14 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 15 "k8s.io/apimachinery/pkg/runtime" 16 apiyaml "k8s.io/apimachinery/pkg/util/yaml" 17 "k8s.io/client-go/kubernetes/scheme" 18 "sigs.k8s.io/yaml" 19 ) 20 21 // decodeCRDs reads a slice of CRDs from multi-document YAML-formatted data provided by the given io.ReadCloser and 22 // closes it when complete or an error occurs. 23 func decodeCRDs(readCloser io.ReadCloser) ([]v1.CustomResourceDefinition, error) { 24 reader := apiyaml.NewYAMLReader(bufio.NewReader(readCloser)) 25 decoder := scheme.Codecs.UniversalDecoder() 26 27 defer func(contentReader io.ReadCloser) { 28 err := readCloser.Close() 29 if err != nil { 30 panic(err) 31 } 32 }(readCloser) 33 34 var crds []v1.CustomResourceDefinition 35 36 for { 37 doc, err := reader.Read() 38 if errors.Is(err, io.EOF) { 39 break 40 } else if err != nil { 41 return nil, microerror.Mask(err) 42 } 43 44 // Skip over empty documents, i.e. a leading `---` 45 if len(bytes.TrimSpace(doc)) == 0 { 46 continue 47 } 48 49 var object unstructured.Unstructured 50 _, decodedGVK, err := decoder.Decode(doc, nil, &object) 51 if err != nil { 52 return nil, microerror.Mask(err) 53 } 54 55 switch *decodedGVK { 56 case crdV1GVK: 57 var crd v1.CustomResourceDefinition 58 _, _, err = decoder.Decode(doc, nil, &crd) 59 if err != nil { 60 return nil, microerror.Mask(err) 61 } 62 63 crds = append(crds, crd) 64 } 65 } 66 67 return crds, nil 68 } 69 70 func helmChartDirectory(helmDirectory, provider string) string { 71 chartName := fmt.Sprintf("crds-%s", provider) 72 return filepath.Join(helmDirectory, chartName) 73 } 74 75 // patchCRD applies a patch function to a deep copy of the given CRD if defined in the given patch map. If no patch is 76 // defined, the CRD will be returned unchanged. 77 func patchCRD(provider string, patches map[string]Patch, crd v1.CustomResourceDefinition) (v1.CustomResourceDefinition, error) { 78 patch, ok := patches[crd.Name] 79 if !ok { 80 return crd, nil 81 } 82 83 crdCopy := crd.DeepCopy() 84 patch(provider, crdCopy) 85 86 return *crdCopy, nil 87 } 88 89 func contains(s []string, str string) bool { 90 for _, v := range s { 91 if v == str { 92 return true 93 } 94 } 95 96 return false 97 } 98 99 func writeObjects(writer io.Writer, objects []runtime.Object) error { 100 for _, object := range objects { 101 _, err := writer.Write([]byte("\n---\n")) 102 if err != nil { 103 return microerror.Mask(err) 104 } 105 106 crdBytes, err := yaml.Marshal(object) 107 if err != nil { 108 return microerror.Mask(err) 109 } 110 111 _, err = writer.Write(crdBytes) 112 if err != nil { 113 return microerror.Mask(err) 114 } 115 } 116 117 return nil 118 } 119 120 func writeObjectsToFile(filename string, objects []runtime.Object) error { 121 writeBuffer, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0755) 122 if err != nil { 123 return microerror.Mask(err) 124 } 125 126 defer func() { 127 err = writeBuffer.Close() 128 if err != nil { 129 panic(microerror.JSON(microerror.Mask(err))) 130 } 131 }() 132 133 return writeObjects(writeBuffer, objects) 134 } 135 136 func writeCRDsToDirectory(outputDirectory string, crds []v1.CustomResourceDefinition) error { 137 if len(crds) == 0 { 138 return nil 139 } 140 141 for _, crd := range crds { 142 filename := filepath.Join(outputDirectory, fmt.Sprintf("%s_%s.yaml", crd.Spec.Group, crd.Spec.Names.Plural)) 143 if err := writeObjectsToFile(filename, []runtime.Object{crd.DeepCopy()}); err != nil { 144 return microerror.Mask(err) 145 } 146 } 147 148 return nil 149 }