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  }