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  }