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