Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions integrationtests/controller/bundle/label_migration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package bundle

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/rancher/fleet/integrationtests/utils"
"github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

var _ = Describe("Bundle label migration", func() {
BeforeEach(func() {
var err error
namespace, err = utils.NewNamespaceName()
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: namespace},
})).ToNot(HaveOccurred())

_, err = utils.CreateCluster(ctx, k8sClient, "cluster", namespace, nil, namespace)
Expect(err).NotTo(HaveOccurred())

DeferCleanup(func() {
Expect(k8sClient.Delete(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}})).ToNot(HaveOccurred())
})
})

createBundle := func(name string, labels map[string]string) {
bundle := &v1alpha1.Bundle{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: labels,
},
Spec: v1alpha1.BundleSpec{
BundleDeploymentOptions: v1alpha1.BundleDeploymentOptions{
DefaultNamespace: "default",
},
Targets: []v1alpha1.BundleTarget{
{
BundleDeploymentOptions: v1alpha1.BundleDeploymentOptions{
TargetNamespace: "targetNs",
},
Name: "cluster",
ClusterName: "cluster",
},
},
},
}
Expect(k8sClient.Create(ctx, bundle)).ToNot(HaveOccurred())
}

DescribeTable("should remove deprecated label after migration",
func(bundleName string, initialLabels map[string]string) {
const deprecatedLabel = "fleet.cattle.io/created-by-display-name"

createBundle(bundleName, initialLabels)
DeferCleanup(func() {
Expect(k8sClient.Delete(ctx, &v1alpha1.Bundle{
ObjectMeta: metav1.ObjectMeta{Name: bundleName, Namespace: namespace},
})).ToNot(HaveOccurred())
})

Eventually(func(g Gomega) {
bundle := &v1alpha1.Bundle{}
g.Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: bundleName}, bundle)).To(Succeed())
g.Expect(bundle.Status.ObservedGeneration).To(BeNumerically(">", 0))
}).Should(Succeed())

bundle := &v1alpha1.Bundle{}
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: bundleName}, bundle)).To(Succeed())

Expect(bundle.Labels).ToNot(HaveKey(deprecatedLabel))
Expect(bundle.Labels).To(HaveKey(v1alpha1.CreatedByUserIDLabel))
},
Entry("with label present initially",
"bundle-with-label",
map[string]string{
"fleet.cattle.io/created-by-display-name": "admin",
v1alpha1.CreatedByUserIDLabel: "user-12345",
},
),
Entry("without label present initially",
"bundle-without-label",
map[string]string{
v1alpha1.CreatedByUserIDLabel: "user-12345",
},
),
)
})
82 changes: 82 additions & 0 deletions integrationtests/gitjob/controller/label_migration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package controller

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/rancher/fleet/integrationtests/utils"
"github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

var _ = Describe("GitRepo label migration", func() {
var namespace string

BeforeEach(func() {
var err error
namespace, err = utils.NewNamespaceName()
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: namespace},
})).ToNot(HaveOccurred())

DeferCleanup(func() {
Expect(k8sClient.Delete(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}})).ToNot(HaveOccurred())
})
})

createGitRepo := func(name string, labels map[string]string) {
gitrepo := &v1alpha1.GitRepo{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: labels,
},
Spec: v1alpha1.GitRepoSpec{
Repo: "https://github.com/rancher/fleet-test-data/not-found",
},
}
Expect(k8sClient.Create(ctx, gitrepo)).ToNot(HaveOccurred())
}

DescribeTable("should remove deprecated label after migration",
func(gitRepoName string, initialLabels map[string]string) {
const deprecatedLabel = "fleet.cattle.io/created-by-display-name"

createGitRepo(gitRepoName, initialLabels)
DeferCleanup(func() {
Expect(k8sClient.Delete(ctx, &v1alpha1.GitRepo{
ObjectMeta: metav1.ObjectMeta{Name: gitRepoName, Namespace: namespace},
})).ToNot(HaveOccurred())
})

Eventually(func(g Gomega) {
gitrepo := &v1alpha1.GitRepo{}
g.Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: gitRepoName}, gitrepo)).To(Succeed())
g.Expect(gitrepo.Status.ObservedGeneration).To(BeNumerically(">", 0))
}).Should(Succeed())

gitrepo := &v1alpha1.GitRepo{}
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: gitRepoName}, gitrepo)).To(Succeed())

Expect(gitrepo.Labels).ToNot(HaveKey(deprecatedLabel))
Expect(gitrepo.Labels).To(HaveKey(v1alpha1.CreatedByUserIDLabel))
},
Entry("with label present initially",
"gitrepo-with-label",
map[string]string{
"fleet.cattle.io/created-by-display-name": "admin",
v1alpha1.CreatedByUserIDLabel: "user-12345",
},
),
Entry("without label present initially",
"gitrepo-without-label",
map[string]string{
v1alpha1.CreatedByUserIDLabel: "user-12345",
},
),
)
})
28 changes: 28 additions & 0 deletions internal/cmd/controller/gitops/reconciler/gitjob_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ func (r *GitJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
return ctrl.Result{RequeueAfter: durations.DefaultRequeueAfter}, nil
}

// Migration: Remove the obsolete created-by-display-name label if it exists
if err := r.removeDisplayNameLabel(ctx, req.NamespacedName); err != nil {
logger.V(1).Error(err, "Failed to remove display name label")
return ctrl.Result{}, err
}

logger = logger.WithValues("generation", gitrepo.Generation, "commit", gitrepo.Status.Commit).WithValues("conditions", gitrepo.Status.Conditions)

if userID := gitrepo.Labels[v1alpha1.CreatedByUserIDLabel]; userID != "" {
Expand Down Expand Up @@ -405,6 +411,28 @@ func (r *GitJobReconciler) addGitRepoFinalizer(ctx context.Context, nsName types
return nil
}

// removeDisplayNameLabel removes the obsolete created-by-display-name label from the gitrepo if it exists.
func (r *GitJobReconciler) removeDisplayNameLabel(ctx context.Context, nsName types.NamespacedName) error {
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
gitrepo := &v1alpha1.GitRepo{}
if err := r.Get(ctx, nsName, gitrepo); err != nil {
return err
}

if gitrepo.Labels == nil {
return nil
}

const deprecatedLabel = "fleet.cattle.io/created-by-display-name"
if _, exists := gitrepo.Labels[deprecatedLabel]; !exists {
return nil
}

delete(gitrepo.Labels, deprecatedLabel)
return r.Update(ctx, gitrepo)
})
}

func (r *GitJobReconciler) validateExternalSecretExist(ctx context.Context, gitrepo *v1alpha1.GitRepo) error {
if gitrepo.Spec.HelmSecretNameForPaths != "" {
if err := r.Get(ctx, types.NamespacedName{Namespace: gitrepo.Namespace, Name: gitrepo.Spec.HelmSecretNameForPaths}, &corev1.Secret{}); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/controller/gitops/reconciler/gitjob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ func TestReconcile_Error_WhenGetGitJobErrors(t *testing.T) {
mockClient.EXPECT().List(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil)

mockClient.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&fleetv1.GitRepo{}), gomock.Any()).
Times(2).
Times(3).
DoAndReturn(
func(ctx context.Context, req types.NamespacedName, gitrepo *fleetv1.GitRepo, opts ...interface{}) error {
gitrepo.Name = gitRepo.Name
Expand Down Expand Up @@ -607,7 +607,7 @@ func TestReconcile_Error_WhenSecretDoesNotExist(t *testing.T) {
mockClient := mocks.NewMockK8sClient(mockCtrl)
mockClient.EXPECT().List(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil)

mockClient.EXPECT().Get(gomock.Any(), gomock.Any(), &gitRepoPointerMatcher{}, gomock.Any()).Times(2).DoAndReturn(
mockClient.EXPECT().Get(gomock.Any(), gomock.Any(), &gitRepoPointerMatcher{}, gomock.Any()).Times(3).DoAndReturn(
func(ctx context.Context, req types.NamespacedName, gitrepo *fleetv1.GitRepo, opts ...interface{}) error {
gitrepo.Name = gitRepo.Name
gitrepo.Namespace = gitRepo.Namespace
Expand Down
23 changes: 23 additions & 0 deletions internal/cmd/controller/reconciler/bundle_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ func (r *BundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
return ctrl.Result{}, fmt.Errorf("%w, failed to add finalizer to bundle: %w", fleetutil.ErrRetryable, err)
}

// Migration: Remove the obsolete created-by-display-name label if it exists
if err := r.removeDisplayNameLabel(ctx, bundle); err != nil {
return r.computeResult(ctx, logger, bundleOrig, bundle, "failed to remove display name label", err)
}

logger.V(1).Info(
"Reconciling bundle, checking targets, calculating changes, building objects",
"generation",
Expand Down Expand Up @@ -454,6 +459,24 @@ func (r *BundleReconciler) ensureFinalizer(ctx context.Context, bundle *fleet.Bu
return r.Update(ctx, bundle)
}

// removeDisplayNameLabel removes the obsolete created-by-display-name label from the bundle if it exists.
func (r *BundleReconciler) removeDisplayNameLabel(ctx context.Context, bundle *fleet.Bundle) error {
if bundle.Labels == nil {
return nil
}

const deprecatedLabel = "fleet.cattle.io/created-by-display-name"
if _, exists := bundle.Labels[deprecatedLabel]; !exists {
return nil
}

delete(bundle.Labels, deprecatedLabel)
if err := r.Update(ctx, bundle); err != nil {
return fmt.Errorf("%w: %w", fleetutil.ErrRetryable, err)
}
return nil
}

func (r *BundleReconciler) createBundleDeployment(
ctx context.Context,
l logr.Logger,
Expand Down