From 655133b81cf8a66fd3519704fdac129d52d9fce2 Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Thu, 19 Feb 2026 17:38:23 +0300 Subject: [PATCH] fix(installer): move PackageSource creation from Helm template to operator Replace the Helm hook approach with programmatic PackageSource creation in the operator startup sequence. Helm hooks are unsuitable for persistent resources like PackageSource because before-hook-creation policy causes cascade deletion of owned ArtifactGenerators during upgrades. The operator now creates the platform PackageSource after installing CRDs and the Flux source resource, using the same create-or-update pattern as installPlatformSourceResource(). The sourceRef.kind is derived from the platform source URL (OCIRepository for oci://, GitRepository for git). Also fix stale comment in e2e test referencing deleted crds/ directory. Co-Authored-By: Claude Signed-off-by: Aleksei Sviridkin --- Makefile | 3 - cmd/cozystack-operator/main.go | 126 ++++++++++++++++++ hack/e2e-install-cozystack.bats | 2 +- .../installer/templates/packagesource.yaml | 59 -------- 4 files changed, 127 insertions(+), 63 deletions(-) delete mode 100644 packages/core/installer/templates/packagesource.yaml diff --git a/Makefile b/Makefile index 226ee9d0..ca48197c 100644 --- a/Makefile +++ b/Makefile @@ -42,20 +42,17 @@ manifests: # Talos variant (default) helm template installer packages/core/installer -n cozy-system \ --show-only templates/cozystack-operator.yaml \ - --show-only templates/packagesource.yaml \ > _out/assets/cozystack-operator-talos.yaml # Generic Kubernetes variant (k3s, kubeadm, RKE2) helm template installer packages/core/installer -n cozy-system \ --set cozystackOperator.variant=generic \ --set cozystack.apiServerHost=REPLACE_ME \ --show-only templates/cozystack-operator.yaml \ - --show-only templates/packagesource.yaml \ > _out/assets/cozystack-operator-generic.yaml # Hosted variant (managed Kubernetes) helm template installer packages/core/installer -n cozy-system \ --set cozystackOperator.variant=hosted \ --show-only templates/cozystack-operator.yaml \ - --show-only templates/packagesource.yaml \ > _out/assets/cozystack-operator-hosted.yaml cozypkg: diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index d3c40f7e..ba5730e2 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -222,6 +222,20 @@ func main() { } else { setupLog.Info("Platform source resource installation completed successfully") } + + // Create platform PackageSource that references the source resource + setupLog.Info("Creating platform PackageSource", "platformSourceName", platformSourceName) + sourceType, _, _ := parsePlatformSourceURL(platformSourceURL) + sourceRefKind := "OCIRepository" + if sourceType == "git" { + sourceRefKind = "GitRepository" + } + if err := installPlatformPackageSource(installCtx, directClient, platformSourceName, sourceRefKind); err != nil { + setupLog.Error(err, "failed to create platform PackageSource") + os.Exit(1) + } else { + setupLog.Info("Platform PackageSource creation completed successfully") + } } // Setup PackageSource reconciler @@ -552,3 +566,115 @@ func generateGitRepository(name, repoURL string, refMap map[string]string) (*sou return obj, nil } + +// installPlatformPackageSource creates the platform PackageSource resource +// that references the Flux source resource (OCIRepository or GitRepository). +func installPlatformPackageSource(ctx context.Context, k8sClient client.Client, platformSourceName, sourceRefKind string) error { + logger := log.FromContext(ctx) + + packageSourceName := "cozystack." + platformSourceName + + ps := &cozyv1alpha1.PackageSource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: cozyv1alpha1.GroupVersion.String(), + Kind: "PackageSource", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: packageSourceName, + Annotations: map[string]string{ + "operator.cozystack.io/skip-cozystack-values": "true", + }, + }, + Spec: cozyv1alpha1.PackageSourceSpec{ + SourceRef: &cozyv1alpha1.PackageSourceRef{ + Kind: sourceRefKind, + Name: platformSourceName, + Namespace: "cozy-system", + Path: "/", + }, + Variants: []cozyv1alpha1.Variant{ + { + Name: "default", + Components: []cozyv1alpha1.Component{ + { + Name: "platform", + Path: "core/platform", + Install: &cozyv1alpha1.ComponentInstall{ + Namespace: "cozy-system", + ReleaseName: "cozystack-platform", + }, + ValuesFiles: []string{"values.yaml"}, + }, + }, + }, + { + Name: "isp-full", + Components: []cozyv1alpha1.Component{ + { + Name: "platform", + Path: "core/platform", + Install: &cozyv1alpha1.ComponentInstall{ + Namespace: "cozy-system", + ReleaseName: "cozystack-platform", + }, + ValuesFiles: []string{"values.yaml", "values-isp-full.yaml"}, + }, + }, + }, + { + Name: "isp-hosted", + Components: []cozyv1alpha1.Component{ + { + Name: "platform", + Path: "core/platform", + Install: &cozyv1alpha1.ComponentInstall{ + Namespace: "cozy-system", + ReleaseName: "cozystack-platform", + }, + ValuesFiles: []string{"values.yaml", "values-isp-hosted.yaml"}, + }, + }, + }, + { + Name: "isp-full-generic", + Components: []cozyv1alpha1.Component{ + { + Name: "platform", + Path: "core/platform", + Install: &cozyv1alpha1.ComponentInstall{ + Namespace: "cozy-system", + ReleaseName: "cozystack-platform", + }, + ValuesFiles: []string{"values.yaml", "values-isp-full-generic.yaml"}, + }, + }, + }, + }, + }, + } + + logger.Info("Applying platform PackageSource", "name", packageSourceName) + + existing := &cozyv1alpha1.PackageSource{} + key := client.ObjectKeyFromObject(ps) + + err := k8sClient.Get(ctx, key, existing) + if err != nil { + if client.IgnoreNotFound(err) == nil { + if err := k8sClient.Create(ctx, ps); err != nil { + return fmt.Errorf("failed to create PackageSource %s: %w", packageSourceName, err) + } + logger.Info("Created platform PackageSource", "name", packageSourceName) + } else { + return fmt.Errorf("failed to check if PackageSource exists: %w", err) + } + } else { + ps.SetResourceVersion(existing.GetResourceVersion()) + if err := k8sClient.Update(ctx, ps); err != nil { + return fmt.Errorf("failed to update PackageSource %s: %w", packageSourceName, err) + } + logger.Info("Updated platform PackageSource", "name", packageSourceName) + } + + return nil +} diff --git a/hack/e2e-install-cozystack.bats b/hack/e2e-install-cozystack.bats index 5e518cad..5a705906 100644 --- a/hack/e2e-install-cozystack.bats +++ b/hack/e2e-install-cozystack.bats @@ -8,7 +8,7 @@ } @test "Install Cozystack" { - # Install cozy-installer chart (CRDs from crds/ are applied automatically) + # Install cozy-installer chart (operator installs CRDs on startup via --install-crds) helm upgrade installer packages/core/installer \ --install \ --namespace cozy-system \ diff --git a/packages/core/installer/templates/packagesource.yaml b/packages/core/installer/templates/packagesource.yaml deleted file mode 100644 index daaf7eb8..00000000 --- a/packages/core/installer/templates/packagesource.yaml +++ /dev/null @@ -1,59 +0,0 @@ -{{- $validVariants := list "talos" "generic" "hosted" -}} -{{- if not (has .Values.cozystackOperator.variant $validVariants) -}} -{{- fail (printf "Invalid cozystackOperator.variant %q: must be one of talos, generic, hosted" .Values.cozystackOperator.variant) -}} -{{- end -}} ---- -apiVersion: cozystack.io/v1alpha1 -kind: PackageSource -metadata: - name: cozystack.cozystack-platform - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-delete-policy": before-hook-creation - operator.cozystack.io/skip-cozystack-values: "true" -spec: - sourceRef: - kind: OCIRepository - name: cozystack-platform - namespace: cozy-system - path: / - variants: - - name: default - components: - - install: - namespace: cozy-system - releaseName: cozystack-platform - name: platform - path: core/platform - valuesFiles: - - values.yaml - - name: isp-full - components: - - install: - namespace: cozy-system - releaseName: cozystack-platform - name: platform - path: core/platform - valuesFiles: - - values.yaml - - values-isp-full.yaml - - name: isp-hosted - components: - - install: - namespace: cozy-system - releaseName: cozystack-platform - name: platform - path: core/platform - valuesFiles: - - values.yaml - - values-isp-hosted.yaml - - name: isp-full-generic - components: - - install: - namespace: cozy-system - releaseName: cozystack-platform - name: platform - path: core/platform - valuesFiles: - - values.yaml - - values-isp-full-generic.yaml