github.com/argoproj/argo-cd@v1.8.7/hack/gen-crd-spec/main.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"strings"
    10  
    11  	"github.com/argoproj/argo-cd/pkg/apis/application"
    12  
    13  	"github.com/argoproj/gitops-engine/pkg/utils/kube"
    14  	"github.com/ghodss/yaml"
    15  	extensionsobj "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
    16  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    17  )
    18  
    19  var (
    20  	kindToCRDPath = map[string]string{
    21  		application.ApplicationFullName: "manifests/crds/application-crd.yaml",
    22  		application.AppProjectFullName:  "manifests/crds/appproject-crd.yaml",
    23  	}
    24  )
    25  
    26  func getCustomResourceDefinitions() map[string]*extensionsobj.CustomResourceDefinition {
    27  	crdYamlBytes, err := exec.Command(
    28  		"controller-gen",
    29  		"paths=./pkg/apis/application/...",
    30  		"crd:trivialVersions=true",
    31  		"output:crd:stdout",
    32  	).Output()
    33  	checkErr(err)
    34  
    35  	// clean up stuff left by controller-gen
    36  	deleteFile("config/webhook/manifests.yaml")
    37  	deleteFile("config/webhook")
    38  	deleteFile("config")
    39  
    40  	objs, err := kube.SplitYAML(crdYamlBytes)
    41  	checkErr(err)
    42  	crds := make(map[string]*extensionsobj.CustomResourceDefinition)
    43  	for i := range objs {
    44  		un := objs[i]
    45  
    46  		// We need to completely remove validation of problematic fields such as creationTimestamp,
    47  		// which get marshalled to `null`, but are typed as as a `string` during Open API validation
    48  		removeValidation(un, "metadata.creationTimestamp")
    49  		// remove status validation for AppProject CRD as workaround for https://github.com/argoproj/argo-cd/issues/4158
    50  		if un.GetName() == "appprojects.argoproj.io" {
    51  			removeValidation(un, "status")
    52  		}
    53  
    54  		crd := toCRD(un)
    55  		crd.Labels = map[string]string{
    56  			"app.kubernetes.io/name":    crd.Name,
    57  			"app.kubernetes.io/part-of": "argocd",
    58  		}
    59  		delete(crd.Annotations, "controller-gen.kubebuilder.io/version")
    60  		crd.Spec.Scope = "Namespaced"
    61  		crd.Spec.PreserveUnknownFields = nil
    62  		crds[crd.Name] = crd
    63  	}
    64  	return crds
    65  }
    66  
    67  func deleteFile(path string) {
    68  	if _, err := os.Stat(path); os.IsNotExist(err) {
    69  		return
    70  	}
    71  	checkErr(os.Remove(path))
    72  }
    73  
    74  func removeValidation(un *unstructured.Unstructured, path string) {
    75  	schemaPath := []string{"spec", "validation", "openAPIV3Schema"}
    76  	for _, part := range strings.Split(path, ".") {
    77  		schemaPath = append(schemaPath, "properties", part)
    78  	}
    79  	unstructured.RemoveNestedField(un.Object, schemaPath...)
    80  }
    81  
    82  func toCRD(un *unstructured.Unstructured) *extensionsobj.CustomResourceDefinition {
    83  	unBytes, err := json.Marshal(un)
    84  	checkErr(err)
    85  
    86  	var crd extensionsobj.CustomResourceDefinition
    87  	err = json.Unmarshal(unBytes, &crd)
    88  	checkErr(err)
    89  
    90  	return &crd
    91  }
    92  
    93  func checkErr(err error) {
    94  	if err != nil {
    95  		panic(err)
    96  	}
    97  }
    98  
    99  func main() {
   100  	crds := getCustomResourceDefinitions()
   101  	for kind, path := range kindToCRDPath {
   102  		crd := crds[kind]
   103  		if crd == nil {
   104  			panic(fmt.Sprintf("CRD of kind %s was not generated", kind))
   105  		}
   106  
   107  		jsonBytes, err := json.Marshal(crd)
   108  		checkErr(err)
   109  
   110  		var r unstructured.Unstructured
   111  		err = json.Unmarshal(jsonBytes, &r.Object)
   112  		checkErr(err)
   113  
   114  		// clean up crd yaml before marshalling
   115  		unstructured.RemoveNestedField(r.Object, "status")
   116  		unstructured.RemoveNestedField(r.Object, "metadata", "creationTimestamp")
   117  		jsonBytes, err = json.MarshalIndent(r.Object, "", "    ")
   118  		checkErr(err)
   119  
   120  		yamlBytes, err := yaml.JSONToYAML(jsonBytes)
   121  		checkErr(err)
   122  
   123  		err = ioutil.WriteFile(path, yamlBytes, 0644)
   124  		checkErr(err)
   125  	}
   126  }