github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/pkg/kubernetes/crds.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"gopkg.in/yaml.v3"
     7  	"io"
     8  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
     9  	"sigs.k8s.io/controller-tools/pkg/crd"
    10  	"sigs.k8s.io/controller-tools/pkg/deepcopy"
    11  	"sigs.k8s.io/controller-tools/pkg/genall"
    12  	"sigs.k8s.io/controller-tools/pkg/loader"
    13  	"sigs.k8s.io/controller-tools/pkg/markers"
    14  	"strings"
    15  )
    16  
    17  var (
    18  	buffer = bytes.Buffer{}
    19  
    20  	allGenerators = map[string]genall.Generator{
    21  		"crd":    crd.Generator{},
    22  		"object": deepcopy.Generator{},
    23  	}
    24  
    25  	allOutputRules = map[string]genall.OutputRule{
    26  		"dir":       genall.OutputToDirectory(""),
    27  		"none":      genall.OutputToNothing,
    28  		"stdout":    genall.OutputToStdout,
    29  		"buffer":    outputToBuffer{},
    30  		"artifacts": genall.OutputArtifacts{},
    31  	}
    32  
    33  	optionsRegistry = &markers.Registry{}
    34  )
    35  
    36  func getYamlsFromBuffer() []string {
    37  	yamls := strings.Split(buffer.String(), "---")
    38  	buffer.Reset()
    39  	return yamls
    40  }
    41  
    42  func GetCRDs(boilerplatePath, path string) ([]string, error) {
    43  	if err := generateDeepCopy(boilerplatePath, path); err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	if err := generateCrd(path); err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	return getYamlsFromBuffer(), nil
    52  }
    53  
    54  func WriteCRDs(boilerplatePath, path, destinationFolder string) error {
    55  	if err := generateDeepCopy(boilerplatePath, path); err != nil {
    56  		return err
    57  	}
    58  
    59  	return generateCrdToFolder(path, destinationFolder)
    60  }
    61  
    62  func ApplyCRDs(boilerplatePath, path string, k8sClient ClientInt) error {
    63  	if err := generateDeepCopy(boilerplatePath, path); err != nil {
    64  		return err
    65  	}
    66  
    67  	if err := generateCrd(path); err != nil {
    68  		return err
    69  	}
    70  
    71  	for _, crd := range getYamlsFromBuffer() {
    72  		if crd == "" || crd == "\n" {
    73  			continue
    74  		}
    75  
    76  		//crdDefinition := apixv1beta1.CustomResourceDefinition{}
    77  		crdDefinition := &unstructured.Unstructured{}
    78  		if err := yaml.Unmarshal([]byte(crd), &crdDefinition.Object); err != nil {
    79  			return err
    80  		}
    81  
    82  		if err := k8sClient.ApplyCRDResource(
    83  			crdDefinition,
    84  		); err != nil {
    85  			return err
    86  		}
    87  	}
    88  	return nil
    89  }
    90  
    91  type outputToBuffer struct{}
    92  
    93  func (o outputToBuffer) Open(_ *loader.Package, itemPath string) (io.WriteCloser, error) {
    94  	return nopCloser{&buffer}, nil
    95  }
    96  
    97  type nopCloser struct {
    98  	io.Writer
    99  }
   100  
   101  func (n nopCloser) Close() error {
   102  	return nil
   103  }
   104  
   105  func init() {
   106  	for genName, gen := range allGenerators {
   107  		// make the generator options marker itself
   108  		defn := markers.Must(markers.MakeDefinition(genName, markers.DescribesPackage, gen))
   109  		if err := optionsRegistry.Register(defn); err != nil {
   110  			panic(err)
   111  		}
   112  		if helpGiver, hasHelp := gen.(genall.HasHelp); hasHelp {
   113  			if help := helpGiver.Help(); help != nil {
   114  				optionsRegistry.AddHelp(defn, help)
   115  			}
   116  		}
   117  
   118  		// make per-generation output rule markers
   119  		for ruleName, rule := range allOutputRules {
   120  			ruleMarker := markers.Must(markers.MakeDefinition(fmt.Sprintf("output:%s:%s", genName, ruleName), markers.DescribesPackage, rule))
   121  			if err := optionsRegistry.Register(ruleMarker); err != nil {
   122  				panic(err)
   123  			}
   124  			if helpGiver, hasHelp := rule.(genall.HasHelp); hasHelp {
   125  				if help := helpGiver.Help(); help != nil {
   126  					optionsRegistry.AddHelp(ruleMarker, help)
   127  				}
   128  			}
   129  		}
   130  	}
   131  
   132  	// make "default output" output rule markers
   133  	for ruleName, rule := range allOutputRules {
   134  		ruleMarker := markers.Must(markers.MakeDefinition("output:"+ruleName, markers.DescribesPackage, rule))
   135  		if err := optionsRegistry.Register(ruleMarker); err != nil {
   136  			panic(err)
   137  		}
   138  		if helpGiver, hasHelp := rule.(genall.HasHelp); hasHelp {
   139  			if help := helpGiver.Help(); help != nil {
   140  				optionsRegistry.AddHelp(ruleMarker, help)
   141  			}
   142  		}
   143  	}
   144  
   145  	// add in the common options markers
   146  	if err := genall.RegisterOptionsMarkers(optionsRegistry); err != nil {
   147  		panic(err)
   148  	}
   149  }
   150  
   151  func generate(rawOpts []string) error {
   152  	rt, err := genall.FromOptions(optionsRegistry, rawOpts)
   153  	if err != nil {
   154  		panic(err)
   155  	}
   156  	if len(rt.Generators) == 0 {
   157  		return fmt.Errorf("no generators specified")
   158  	}
   159  
   160  	if hadErrs := rt.Run(); hadErrs {
   161  		return fmt.Errorf("not all generators ran successfully")
   162  	}
   163  
   164  	return nil
   165  }
   166  
   167  func generateDeepCopy(boilerplatePath, path string) error {
   168  	return generate([]string{
   169  		"object:headerFile=\"" + boilerplatePath + "\"",
   170  		"paths=\"" + path + "\"",
   171  	})
   172  }
   173  
   174  func generateCrd(path string) error {
   175  	return generate([]string{
   176  		"crd:trivialVersions=true",
   177  		"crd",
   178  		"paths=\"" + path + "\"",
   179  		"output:crd:buffer",
   180  	})
   181  }
   182  
   183  func generateCrdToFolder(path, folder string) error {
   184  	return generate([]string{
   185  		"crd:trivialVersions=true",
   186  		"crd",
   187  		"paths=\"" + path + "\"",
   188  		"output:crd:artifacts:config=\"" + folder + "\"",
   189  	})
   190  }