From a4c962b98e9cbc32ec1bc02e42d0130cd41649cf Mon Sep 17 00:00:00 2001 From: Johannes Aubart Date: Thu, 28 Aug 2025 10:49:54 +0200 Subject: [PATCH] enable skipping clusters in CRD management --- pkg/crds/crds.go | 22 ++++++++++++++++------ pkg/crds/crds_test.go | 7 ++++++- pkg/crds/testdata/crd_c.yaml | 30 ++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 pkg/crds/testdata/crd_c.yaml diff --git a/pkg/crds/crds.go b/pkg/crds/crds.go index cc7224d..b22f07b 100644 --- a/pkg/crds/crds.go +++ b/pkg/crds/crds.go @@ -39,6 +39,10 @@ func (m *CRDManager) AddCRDLabelToClusterMapping(labelValue string, cluster *clu m.crdLabelsToClusterMappings[labelValue] = cluster } +func (m *CRDManager) SkipCRDsWithClusterLabel(labelValue string) { + m.crdLabelsToClusterMappings[labelValue] = nil +} + func (m *CRDManager) CreateOrUpdateCRDs(ctx context.Context, log *logging.Logger) error { crds, err := m.crdList() if err != nil { @@ -48,14 +52,20 @@ func (m *CRDManager) CreateOrUpdateCRDs(ctx context.Context, log *logging.Logger var errs error for _, crd := range crds { - c, err := m.getClusterForCRD(crd) + c, cLabel, err := m.getClusterForCRD(crd) if err != nil { errs = errors.Join(errs, err) continue } + if c == nil { + if log != nil { + log.Info("Skipping CRD because the assigned cluster is nil", "name", crd.Name, "clusterLabel", cLabel) + } + continue + } if log != nil { - log.Info("creating/updating CRD", "name", crd.Name, "cluster", c.ID()) + log.Info("Creating/updating CRD", "name", crd.Name, "cluster", c.ID()) } m := resources.NewCRDMutator(crd) m.MetadataMutator().WithLabels(crd.Labels).WithAnnotations(crd.Annotations) @@ -69,18 +79,18 @@ func (m *CRDManager) CreateOrUpdateCRDs(ctx context.Context, log *logging.Logger return nil } -func (m *CRDManager) getClusterForCRD(crd *apiextv1.CustomResourceDefinition) (*clusters.Cluster, error) { +func (m *CRDManager) getClusterForCRD(crd *apiextv1.CustomResourceDefinition) (*clusters.Cluster, string, error) { labelValue, ok := controller.GetLabel(crd, m.mappingLabelName) if !ok { - return nil, fmt.Errorf("missing label '%s' for CRD '%s'", m.mappingLabelName, crd.Name) + return nil, "", fmt.Errorf("missing label '%s' for CRD '%s'", m.mappingLabelName, crd.Name) } cluster, ok := m.crdLabelsToClusterMappings[labelValue] if !ok { - return nil, fmt.Errorf("no cluster mapping found for label value '%s' in CRD '%s'", labelValue, crd.Name) + return nil, labelValue, fmt.Errorf("no cluster mapping found for label value '%s' in CRD '%s'", labelValue, crd.Name) } - return cluster, nil + return cluster, labelValue, nil } // CRDsFromFileSystem reads CRDs from the specified filesystem path. diff --git a/pkg/crds/crds_test.go b/pkg/crds/crds_test.go index 2ef9fb1..e172e48 100644 --- a/pkg/crds/crds_test.go +++ b/pkg/crds/crds_test.go @@ -31,7 +31,7 @@ var _ = Describe("CRDsFromFileSystem", func() { crdPath := "testdata" crdsList, err := crds.CRDsFromFileSystem(testFS, crdPath) Expect(err).NotTo(HaveOccurred()) - Expect(crdsList).To(HaveLen(2)) + Expect(crdsList).To(HaveLen(3)) // Validate the first CRD Expect(crdsList[0].Name).To(Equal("testresources.example.com")) @@ -69,6 +69,11 @@ var _ = Describe("CRDManager", func() { ctx := context.Background() + // CRD creation should fail due to unknown cluster label + Expect(crdManager.CreateOrUpdateCRDs(ctx, nil)).To(HaveOccurred()) + + crdManager.SkipCRDsWithClusterLabel("cluster_c") + err = crdManager.CreateOrUpdateCRDs(ctx, nil) Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/crds/testdata/crd_c.yaml b/pkg/crds/testdata/crd_c.yaml new file mode 100644 index 0000000..ae9c5f4 --- /dev/null +++ b/pkg/crds/testdata/crd_c.yaml @@ -0,0 +1,30 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: unused.example.com + labels: + openmcp.cloud/cluster: "cluster_c" +spec: + group: example.com + names: + kind: TestResource + listKind: TestResourceList + plural: testresources + singular: testresource + scope: Namespaced + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + name: + type: string + replicas: + type: integer + minimum: 1 \ No newline at end of file