diff --git a/api/crds/manifests/crossplane.services.openmcp.cloud_crossplanes.yaml b/api/crds/manifests/crossplane.services.openmcp.cloud_crossplanes.yaml index 7ea9eac..5661a8c 100644 --- a/api/crds/manifests/crossplane.services.openmcp.cloud_crossplanes.yaml +++ b/api/crds/manifests/crossplane.services.openmcp.cloud_crossplanes.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.19.0 labels: openmcp.cloud/cluster: onboarding name: crossplanes.crossplane.services.openmcp.cloud diff --git a/api/crds/manifests/crossplane.services.openmcp.cloud_providerconfigs.yaml b/api/crds/manifests/crossplane.services.openmcp.cloud_providerconfigs.yaml index 39faeb9..9045e05 100644 --- a/api/crds/manifests/crossplane.services.openmcp.cloud_providerconfigs.yaml +++ b/api/crds/manifests/crossplane.services.openmcp.cloud_providerconfigs.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.19.0 labels: openmcp.cloud/cluster: platform name: providerconfigs.crossplane.services.openmcp.cloud @@ -78,16 +78,13 @@ spec: items: type: string type: array - name: - description: Name of the Helm chart. - type: string - repository: - description: Repository is the URL to a Helm repository. + url: + description: URL is a reference to an OCI artifact repository + hosted on a remote container registry. type: string required: - availableVersions - - name - - repository + - url type: object imageMapping: additionalProperties: diff --git a/api/v1alpha1/providerconfig_types.go b/api/v1alpha1/providerconfig_types.go index 65d18b0..6c6a62c 100644 --- a/api/v1alpha1/providerconfig_types.go +++ b/api/v1alpha1/providerconfig_types.go @@ -38,13 +38,9 @@ type AvailableCrossplaneProvider struct { // ChartSpec identifies a Helm chart. type ChartSpec struct { - // Repository is the URL to a Helm repository. + // URL is a reference to an OCI artifact repository hosted on a remote container registry. // +kubebuilder:validation:Required - Repository string `json:"repository"` - - // Name of the Helm chart. - // +kubebuilder:validation:Required - Name string `json:"name"` + URL string `json:"url"` // AvailableVersions of the Helm chart. // +kubebuilder:validation:Required diff --git a/go.mod b/go.mod index 60e97cd..63ae94e 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/fluxcd/pkg/apis/meta v1.13.0 github.com/fluxcd/source-controller/api v1.6.2 github.com/go-logr/logr v1.4.3 - github.com/openmcp-project/control-plane-operator v0.1.16 + github.com/openmcp-project/control-plane-operator v0.1.17 github.com/openmcp-project/controller-utils v0.22.0 github.com/openmcp-project/openmcp-operator/api v0.15.1 github.com/openmcp-project/openmcp-operator/lib v0.15.1 diff --git a/go.sum b/go.sum index e3306b4..fa96eb8 100644 --- a/go.sum +++ b/go.sum @@ -129,8 +129,8 @@ github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= -github.com/openmcp-project/control-plane-operator v0.1.16 h1:/KRQBc6F9QKjoDRUlWZHATYJvmURNkPUqkV18BfJKPo= -github.com/openmcp-project/control-plane-operator v0.1.16/go.mod h1:/4/Z7DeBYmhMXusXF/Uk0KjM4vjtRHTAZ7wFhzwOOX4= +github.com/openmcp-project/control-plane-operator v0.1.17 h1:9PIFhzw86hSTsVpKodvHoRap9oonXUbcXlZbzjvEyXE= +github.com/openmcp-project/control-plane-operator v0.1.17/go.mod h1:CjwEOqQWPPhyGXyJCaGu/cRjandTp48DK5qTG6JIfq4= github.com/openmcp-project/controller-utils v0.22.0 h1:kdWGds+LOyOaOuKqWZGsJUv17e78HCr5y3bJOMSkdqE= github.com/openmcp-project/controller-utils v0.22.0/go.mod h1:aIF4lk7agc+yCNRN5Oqg4BLlzRKsGixqwsGmxPoO5ak= github.com/openmcp-project/openmcp-operator/api v0.15.1 h1:xjVQG9zt+QGuSyhGCE0HV0ZCVS9KTX71JALoCUM4BRU= diff --git a/hack/common b/hack/common index 3dc4c78..5ffe5c0 160000 --- a/hack/common +++ b/hack/common @@ -1 +1 @@ -Subproject commit 3dc4c7899d658b099bf4c7b9575d34560b68a5bb +Subproject commit 5ffe5c0dd747e62fd80cb2dc7ba93fd724084c9c diff --git a/internal/controller/crossplane_controller.go b/internal/controller/crossplane_controller.go index a2633ef..092dce0 100644 --- a/internal/controller/crossplane_controller.go +++ b/internal/controller/crossplane_controller.go @@ -414,7 +414,8 @@ func (r *CrossplaneReconciler) SetupWithManager(mgr ctrl.Manager) error { WithMCPScheme(scheme.MCP). WithRetryInterval(10 * time.Second). WithMCPPermissions(getMCPPermissions()). - WithMCPRoleRefs(getMCPRoleRefs()) + WithMCPRoleRefs(getMCPRoleRefs()). + SkipWorkloadCluster() // Initialize smart requeue store with sensible defaults: // - Min interval: 5 seconds (quick retry for transient issues) @@ -463,9 +464,8 @@ func (r *CrossplaneReconciler) GetResolverFunc(providerConfig *v1alpha1.Provider for _, availableVersion := range providerConfig.Spec.Chart.AvailableVersions { if availableVersion == version { return v1beta1.ComponentVersion{ - HelmRepo: providerConfig.Spec.Chart.Repository, - HelmChart: providerConfig.Spec.Chart.Name, - Version: version, + OCIURL: providerConfig.Spec.Chart.URL, + Version: version, }, nil } } diff --git a/pkg/component/crossplane_component.go b/pkg/component/crossplane_component.go index 66cd89a..4314110 100644 --- a/pkg/component/crossplane_component.go +++ b/pkg/component/crossplane_component.go @@ -7,6 +7,7 @@ import ( "time" helmv2 "github.com/fluxcd/helm-controller/api/v2" + "github.com/fluxcd/pkg/apis/meta" sourcev1 "github.com/fluxcd/source-controller/api/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -64,18 +65,24 @@ func (c *Crossplane) BuildSourceRepository(ctx context.Context) (fluxcd.SourceAd rfn := rcontext.VersionResolver(ctx) c.applyDefaultChartSpec(rfn) - repo := &sourcev1.HelmRepository{ + repo := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ Name: strings.ToLower(ComponentNameCrossplane), Namespace: rcontext.TenantNamespace(ctx), }, - Spec: sourcev1.HelmRepositorySpec{ - URL: c.ChartSpec.Repository, + Spec: sourcev1.OCIRepositorySpec{ + URL: c.ChartSpec.URL, + Reference: &sourcev1.OCIRepositoryRef{ + Tag: c.ChartSpec.Version, + }, Timeout: &metav1.Duration{Duration: 1 * time.Minute}, + SecretRef: &meta.LocalObjectReference{ + Name: c.ImagePullSecretNames[0], // always use the first secret for OCI auth + }, }, } - adapter := &fluxcd.HelmRepositoryAdapter{Source: repo} + adapter := &fluxcd.OCIRepositoryAdapter{Source: repo} adapter.ApplyDefaults() return adapter, nil } @@ -94,15 +101,9 @@ func (c *Crossplane) BuildManifesto(ctx context.Context) (fluxcd.Manifesto, erro Namespace: rcontext.TenantNamespace(ctx), }, Spec: helmv2.HelmReleaseSpec{ - Chart: &helmv2.HelmChartTemplate{ - Spec: helmv2.HelmChartTemplateSpec{ - Chart: c.ChartSpec.Name, - Version: c.ChartSpec.Version, - SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: "HelmRepository", - Name: strings.ToLower(ComponentNameCrossplane), - }, - }, + ChartRef: &helmv2.CrossNamespaceSourceReference{ + Kind: "OCIRepository", + Name: strings.ToLower(ComponentNameCrossplane), }, ReleaseName: CrossplaneRelease, TargetNamespace: CrossplaneNamespace, @@ -142,9 +143,8 @@ func (c *Crossplane) applyDefaultChartSpec(rfn v1beta1.VersionResolverFn) { if c.ChartSpec == nil { c.ChartSpec = &v1beta1.ChartSpec{ - Repository: comp.HelmRepo, - Name: comp.HelmChart, - Version: comp.Version, + URL: comp.OCIURL, + Version: comp.Version, } } } @@ -165,6 +165,11 @@ func (c *Crossplane) applyDefaultValues() error { // Add imagePullSecrets if provided in ProviderConfig spec values["imagePullSecrets"] = c.ImagePullSecretNames + // Pull Deployment image from specified chart URL provided in ProviderConfig spec + values["image"] = map[string]any{ + "repository": c.ChartSpec.URL, + } + // Write updated values encoded, err := json.Marshal(values) c.Values = &apiextensionsv1.JSON{Raw: encoded} diff --git a/pkg/component/crossplane_component_test.go b/pkg/component/crossplane_component_test.go index 7e1fcc7..ea29899 100644 --- a/pkg/component/crossplane_component_test.go +++ b/pkg/component/crossplane_component_test.go @@ -57,7 +57,7 @@ func Test_Crossplane(t *testing.T) { hasNamespace(CrossplaneNamespace), ), isFluxComponent( - returnsHelmRepo(), + returnsOCIRepository(), returnsHelmRelease( hasKubeconfigRef(), hasHelmValue(2, "replicas"), // custom value diff --git a/pkg/component/utils_test.go b/pkg/component/utils_test.go index 967a64d..0d30310 100644 --- a/pkg/component/utils_test.go +++ b/pkg/component/utils_test.go @@ -132,13 +132,13 @@ func isFluxComponent(additionalValidations ...fluxValidationFunc) validationFunc } } -func returnsHelmRepo() fluxValidationFunc { +func returnsOCIRepository() fluxValidationFunc { return func(t *testing.T, ctx context.Context, c fluxcd.FluxComponent) { s, err := c.BuildSourceRepository(ctx) assert.NoError(t, err) - h, ok := s.(*fluxcd.HelmRepositoryAdapter) - if !assert.True(t, ok, "not a HelmRepositoryAdapter") { + h, ok := s.(*fluxcd.OCIRepositoryAdapter) + if !assert.True(t, ok, "not a OCIRepositoryAdapter") { return } assert.NotNil(t, h.Source)