Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Remove managed-by label when module is unmanaged #1913

Merged
merged 36 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4e95a12
Add label removal finalizer
nesmabadr Oct 1, 2024
e2c99e0
Handle labels deletion from resources and default CR
nesmabadr Oct 1, 2024
61e6b4e
Add unit tests
nesmabadr Oct 2, 2024
5bff57a
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 2, 2024
03cf3e2
Fix linting issues
nesmabadr Oct 2, 2024
a07fbdb
Add E2E test
nesmabadr Oct 2, 2024
e7722ac
Fix linting
nesmabadr Oct 2, 2024
d050d77
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 2, 2024
0a085e4
Fix test
nesmabadr Oct 2, 2024
254e310
Fix test
nesmabadr Oct 2, 2024
1e86868
Merge branch 'feat/unmanaged_module_labels' into remove_labels_unmanaged
nesmabadr Oct 2, 2024
d4abc1f
Fix test
nesmabadr Oct 2, 2024
e490c02
Fix test
nesmabadr Oct 2, 2024
1c801c6
Merge branch 'feat/unmanaged_module_labels' into remove_labels_unmanaged
nesmabadr Oct 2, 2024
99fe6b6
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 2, 2024
ba1945d
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 2, 2024
023b859
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 2, 2024
aa0a5c2
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 3, 2024
cef9da6
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 4, 2024
9b1b1e1
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 4, 2024
d264eef
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 4, 2024
cc77b1c
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 6, 2024
0b83b06
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 8, 2024
6b07829
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 8, 2024
e76fd94
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 8, 2024
667372f
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 9, 2024
1bc8e76
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 9, 2024
bbeec56
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 10, 2024
52871c6
Extract ManifestApiClient and label removal into new services
nesmabadr Oct 10, 2024
f9c62a0
Remove watched by label since we no longer have it on the resources
nesmabadr Oct 10, 2024
ae119ec
fix unit test
nesmabadr Oct 10, 2024
36d4bbe
review comments
nesmabadr Oct 10, 2024
4a27fa9
Review comments - 2
nesmabadr Oct 11, 2024
1e2c3d6
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 11, 2024
ec02bb7
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 11, 2024
18dff91
Merge branch 'main' into remove_labels_unmanaged
nesmabadr Oct 11, 2024
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
8 changes: 6 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import (
"github.com/kyma-project/lifecycle-manager/internal/crd"
"github.com/kyma-project/lifecycle-manager/internal/descriptor/provider"
"github.com/kyma-project/lifecycle-manager/internal/event"
"github.com/kyma-project/lifecycle-manager/internal/manifest/manifestclient"
"github.com/kyma-project/lifecycle-manager/internal/pkg/flags"
"github.com/kyma-project/lifecycle-manager/internal/pkg/metrics"
"github.com/kyma-project/lifecycle-manager/internal/remote"
Expand All @@ -68,7 +69,6 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth"
_ "ocm.software/ocm/api/ocm"
//nolint:gci // kubebuilder's scaffold imports must be appended here.
// +kubebuilder:scaffold:imports
)

const (
Expand Down Expand Up @@ -184,7 +184,7 @@ func setupManager(flagVar *flags.FlagVar, cacheOptions cache.Options, scheme *ma
setupKymaReconciler(mgr, descriptorProvider, skrContextProvider, eventRecorder, flagVar, options, skrWebhookManager,
kymaMetrics,
setupLog)
setupManifestReconciler(mgr, flagVar, options, sharedMetrics, mandatoryModulesMetrics, setupLog)
setupManifestReconciler(mgr, flagVar, options, sharedMetrics, mandatoryModulesMetrics, setupLog, eventRecorder)
setupMandatoryModuleReconciler(mgr, descriptorProvider, flagVar, options, mandatoryModulesMetrics, setupLog)
setupMandatoryModuleDeletionReconciler(mgr, descriptorProvider, eventRecorder, flagVar, options, setupLog)
if flagVar.EnablePurgeFinalizer {
Expand Down Expand Up @@ -383,11 +383,14 @@ func setupPurgeReconciler(mgr ctrl.Manager,
func setupManifestReconciler(mgr ctrl.Manager, flagVar *flags.FlagVar, options ctrlruntime.Options,
sharedMetrics *metrics.SharedMetrics, mandatoryModulesMetrics *metrics.MandatoryModulesMetrics,
setupLog logr.Logger,
event event.Event,
) {
options.MaxConcurrentReconciles = flagVar.MaxConcurrentManifestReconciles
options.RateLimiter = internal.ManifestRateLimiter(flagVar.FailureBaseDelay,
flagVar.FailureMaxDelay, flagVar.RateLimiterFrequency, flagVar.RateLimiterBurst)

manifestClient := manifestclient.NewManifestClient(event, mgr.GetClient())

if err := manifest.SetupWithManager(
mgr, options, queue.RequeueIntervals{
Success: flagVar.ManifestRequeueSuccessInterval,
Expand All @@ -400,6 +403,7 @@ func setupManifestReconciler(mgr ctrl.Manager, flagVar *flags.FlagVar, options c
ListenerAddr: flagVar.ManifestListenerAddr,
EnableDomainNameVerification: flagVar.EnableDomainNameVerification,
}, metrics.NewManifestMetrics(sharedMetrics), mandatoryModulesMetrics,
manifestClient,
); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Manifest")
os.Exit(bootstrapFailedExitCode)
Expand Down
3 changes: 2 additions & 1 deletion internal/controller/manifest/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func NewReconciler(mgr manager.Manager,
requeueIntervals queue.RequeueIntervals,
manifestMetrics *metrics.ManifestMetrics,
mandatoryModulesMetrics *metrics.MandatoryModulesMetrics,
manifestClient declarativev2.ManifestAPIClient,
) *declarativev2.Reconciler {
kcp := &declarativev2.ClusterInfo{
Client: mgr.GetClient(),
Expand All @@ -30,7 +31,7 @@ func NewReconciler(mgr manager.Manager,
statefulChecker := statecheck.NewStatefulSetStateCheck()
deploymentChecker := statecheck.NewDeploymentStateCheck()
return declarativev2.NewFromManager(
mgr, requeueIntervals, manifestMetrics, mandatoryModulesMetrics,
mgr, requeueIntervals, manifestMetrics, mandatoryModulesMetrics, manifestClient,
manifest.NewSpecResolver(keyChainLookup, extractor),
declarativev2.WithCustomStateCheck(statecheck.NewManagerStateCheck(statefulChecker, deploymentChecker)),
declarativev2.WithRemoteTargetCluster(lookup.ConfigResolver),
Expand Down
5 changes: 4 additions & 1 deletion internal/controller/manifest/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/kyma-project/lifecycle-manager/api/shared"
"github.com/kyma-project/lifecycle-manager/api/v1beta2"
declarativev2 "github.com/kyma-project/lifecycle-manager/internal/declarative/v2"
"github.com/kyma-project/lifecycle-manager/internal/pkg/metrics"
"github.com/kyma-project/lifecycle-manager/pkg/queue"
"github.com/kyma-project/lifecycle-manager/pkg/security"
Expand All @@ -40,6 +41,7 @@ func SetupWithManager(mgr manager.Manager,
settings SetupOptions,
manifestMetrics *metrics.ManifestMetrics,
mandatoryModulesMetrics *metrics.MandatoryModulesMetrics,
manifestClient declarativev2.ManifestAPIClient,
) error {
var verifyFunc watcherevent.Verify
if settings.EnableDomainNameVerification {
Expand Down Expand Up @@ -84,7 +86,8 @@ func SetupWithManager(mgr manager.Manager,
predicate.LabelChangedPredicate{}))).
WatchesRawSource(skrEventChannel).
WithOptions(opts).
Complete(NewReconciler(mgr, requeueIntervals, manifestMetrics, mandatoryModulesMetrics)); err != nil {
Complete(NewReconciler(mgr, requeueIntervals, manifestMetrics, mandatoryModulesMetrics,
manifestClient)); err != nil {
return fmt.Errorf("failed to setup manager for manifest controller: %w", err)
}

Expand Down
162 changes: 97 additions & 65 deletions internal/declarative/v2/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/kyma-project/lifecycle-manager/api/shared"
"github.com/kyma-project/lifecycle-manager/api/v1beta2"
"github.com/kyma-project/lifecycle-manager/internal"
"github.com/kyma-project/lifecycle-manager/internal/manifest/labelsremoval"
"github.com/kyma-project/lifecycle-manager/internal/pkg/metrics"
"github.com/kyma-project/lifecycle-manager/internal/pkg/resources"
"github.com/kyma-project/lifecycle-manager/pkg/common"
Expand Down Expand Up @@ -49,6 +50,7 @@ func NewFromManager(mgr manager.Manager,
requeueIntervals queue.RequeueIntervals,
metrics *metrics.ManifestMetrics,
mandatoryModulesMetrics *metrics.MandatoryModulesMetrics,
manifestAPIClient ManifestAPIClient,
specResolver SpecResolver,
options ...Option,
) *Reconciler {
Expand All @@ -57,16 +59,33 @@ func NewFromManager(mgr manager.Manager,
reconciler.MandatoryModuleMetrics = mandatoryModulesMetrics
reconciler.RequeueIntervals = requeueIntervals
reconciler.specResolver = specResolver
reconciler.manifestClient = manifestAPIClient
reconciler.managedLabelRemovalService = labelsremoval.NewManagedLabelRemovalService(manifestAPIClient)
reconciler.Options = DefaultOptions().Apply(WithManager(mgr)).Apply(options...)
return reconciler
}

type ManagedLabelRemoval interface {
RemoveManagedLabel(ctx context.Context,
manifest *v1beta2.Manifest, skrClient client.Client, defaultCR *unstructured.Unstructured,
) error
}

type ManifestAPIClient interface {
UpdateManifest(ctx context.Context, manifest *v1beta2.Manifest) error
PatchStatusIfDiffExist(ctx context.Context, manifest *v1beta2.Manifest,
previousStatus shared.Status) error
SsaSpec(ctx context.Context, obj client.Object) error
}

type Reconciler struct {
queue.RequeueIntervals
*Options
ManifestMetrics *metrics.ManifestMetrics
MandatoryModuleMetrics *metrics.MandatoryModulesMetrics
specResolver SpecResolver
ManifestMetrics *metrics.ManifestMetrics
MandatoryModuleMetrics *metrics.MandatoryModulesMetrics
specResolver SpecResolver
manifestClient ManifestAPIClient
managedLabelRemovalService ManagedLabelRemoval
}

const waitingForResourcesMsg = "waiting for resources to become ready"
Expand Down Expand Up @@ -138,10 +157,26 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
r.MandatoryModuleMetrics.RecordMandatoryModuleState(kymaName, moduleName, state)
}

skrClient, err := r.getTargetClient(ctx, manifest)
if err != nil {
if !manifest.GetDeletionTimestamp().IsZero() && errors.Is(err, ErrAccessSecretNotFound) {
return r.cleanupManifest(ctx, req, manifest, manifestStatus, metrics.ManifestClientInit,
err)
}

manifest.SetStatus(manifest.GetStatus().WithState(shared.StateError).WithErr(err))
return r.finishReconcile(ctx, manifest, metrics.ManifestClientInit, manifestStatus, err)
}

if manifest.IsUnmanaged() {
if !manifest.GetDeletionTimestamp().IsZero() {
return r.cleanupManifest(ctx, req, manifest, manifestStatus, metrics.ManifestUnmanagedUpdate, nil)
}

if controllerutil.ContainsFinalizer(manifest, labelsremoval.LabelRemovalFinalizer) {
return r.handleLabelsRemovalFinalizer(ctx, skrClient, manifest)
}

if err := r.Delete(ctx, manifest); err != nil {
return ctrl.Result{}, fmt.Errorf("manifestController: %w", err)
}
Expand All @@ -150,7 +185,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu

if manifest.GetDeletionTimestamp().IsZero() {
partialMeta := r.partialObjectMetadata(manifest)
if controllerutil.AddFinalizer(partialMeta, defaultFinalizer) {
defaultFinalizerAdded := controllerutil.AddFinalizer(partialMeta, defaultFinalizer)
labelRemovalFinalizerAdded := controllerutil.AddFinalizer(partialMeta, labelsremoval.LabelRemovalFinalizer)
if defaultFinalizerAdded || labelRemovalFinalizerAdded {
return r.ssaSpec(ctx, partialMeta, metrics.ManifestAddFinalizer)
}
}
Expand All @@ -169,17 +206,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return r.updateManifest(ctx, manifest, metrics.ManifestInitSyncedOCIRef)
}

skrClient, err := r.getTargetClient(ctx, manifest)
if err != nil {
if !manifest.GetDeletionTimestamp().IsZero() && errors.Is(err, ErrAccessSecretNotFound) {
return r.cleanupManifest(ctx, req, manifest, manifestStatus, metrics.ManifestClientInit,
err)
}

manifest.SetStatus(manifest.GetStatus().WithState(shared.StateError).WithErr(err))
return r.finishReconcile(ctx, manifest, metrics.ManifestClientInit, manifestStatus, err)
}

target, current, err := r.renderResources(ctx, skrClient, manifest, spec)
if err != nil {
if util.IsConnectionRelatedError(err) {
Expand Down Expand Up @@ -231,12 +257,29 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return r.finishReconcile(ctx, manifest, metrics.ManifestReconcileFinished, manifestStatus, nil)
}

func (r *Reconciler) handleLabelsRemovalFinalizer(ctx context.Context, skrClient client.Client,
manifest *v1beta2.Manifest,
) (ctrl.Result, error) {
defaultCR, err := getCR(ctx, skrClient, manifest)
if err != nil {
return ctrl.Result{}, err
}

if err := r.managedLabelRemovalService.RemoveManagedLabel(ctx, manifest, skrClient,
defaultCR); err != nil {
return ctrl.Result{}, err
}

r.ManifestMetrics.RecordRequeueReason(metrics.ManifestResourcesLabelRemoval, queue.IntendedRequeue)
return ctrl.Result{Requeue: true}, nil
}

func (r *Reconciler) cleanupManifest(ctx context.Context, req ctrl.Request, manifest *v1beta2.Manifest,
manifestStatus shared.Status, requeueReason metrics.ManifestRequeueReason, originalErr error,
) (ctrl.Result, error) {
r.ManifestMetrics.RemoveManifestDuration(req.Name)
r.cleanUpMandatoryModuleMetrics(manifest)
finalizersToRemove := []string{defaultFinalizer}
finalizersToRemove := []string{defaultFinalizer, labelsremoval.LabelRemovalFinalizer}
if errors.Is(originalErr, ErrAccessSecretNotFound) || manifest.IsUnmanaged() {
finalizersToRemove = manifest.GetFinalizers()
}
Expand Down Expand Up @@ -483,30 +526,22 @@ func (r *Reconciler) renderTargetResources(ctx context.Context, skrClient client
return target, nil
}

func checkCRDeletion(ctx context.Context, skrClient client.Client, manifest *v1beta2.Manifest) (bool, error) {
if manifest.Spec.Resource == nil {
func checkCRDeletion(ctx context.Context, skrClient client.Client, manifestCR *v1beta2.Manifest) (bool,
error,
) {
if manifestCR.Spec.Resource == nil {
return true, nil
}

name := manifest.Spec.Resource.GetName()
namespace := manifest.Spec.Resource.GetNamespace()
gvk := manifest.Spec.Resource.GroupVersionKind()

resourceCR := &unstructured.Unstructured{}
resourceCR.SetGroupVersionKind(schema.GroupVersionKind{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
})

if err := skrClient.Get(ctx,
client.ObjectKey{Name: name, Namespace: namespace}, resourceCR); err != nil {
resourceCR, err := getCR(ctx, skrClient, manifestCR)
if err != nil {
if util.IsNotFound(err) {
return true, nil
}
return false, fmt.Errorf("%w: failed to fetch default resource CR", err)
}
return false, nil

return resourceCR == nil, nil
}

func (r *Reconciler) pruneDiff(ctx context.Context, clnt Client, manifest *v1beta2.Manifest,
Expand Down Expand Up @@ -633,9 +668,8 @@ func (r *Reconciler) configClient(ctx context.Context, manifest *v1beta2.Manifes
func (r *Reconciler) finishReconcile(ctx context.Context, manifest *v1beta2.Manifest,
requeueReason metrics.ManifestRequeueReason, previousStatus shared.Status, originalErr error,
) (ctrl.Result, error) {
if err := r.patchStatusIfDiffExist(ctx, manifest, previousStatus); err != nil {
r.Event(manifest, "Warning", "PatchStatus", err.Error())
return ctrl.Result{}, fmt.Errorf("failed to patch status: %w", err)
if err := r.manifestClient.PatchStatusIfDiffExist(ctx, manifest, previousStatus); err != nil {
return ctrl.Result{}, err
}
if originalErr != nil {
r.ManifestMetrics.RecordRequeueReason(requeueReason, queue.UnexpectedRequeue)
Expand All @@ -646,49 +680,25 @@ func (r *Reconciler) finishReconcile(ctx context.Context, manifest *v1beta2.Mani
return ctrl.Result{RequeueAfter: requeueAfter}, nil
}

func (r *Reconciler) patchStatusIfDiffExist(ctx context.Context, manifest *v1beta2.Manifest,
previousStatus shared.Status,
) error {
if hasStatusDiff(manifest.GetStatus(), previousStatus) {
resetNonPatchableField(manifest)
if err := r.Status().Patch(ctx, manifest, client.Apply, client.ForceOwnership, defaultFieldOwner); err != nil {
return fmt.Errorf("failed to patch status: %w", err)
}
}

return nil
}

func hasStatusDiff(first, second shared.Status) bool {
return first.State != second.State || first.LastOperation.Operation != second.LastOperation.Operation
}

func (r *Reconciler) ssaSpec(ctx context.Context, obj client.Object,
requeueReason metrics.ManifestRequeueReason,
) (ctrl.Result, error) {
resetNonPatchableField(obj)
r.ManifestMetrics.RecordRequeueReason(requeueReason, queue.IntendedRequeue)
if err := r.Patch(ctx, obj, client.Apply, client.ForceOwnership, defaultFieldOwner); err != nil {
r.Event(obj, "Warning", "PatchObject", err.Error())
return ctrl.Result{}, fmt.Errorf("failed to patch object: %w", err)
if err := r.manifestClient.SsaSpec(ctx, obj); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{Requeue: true}, nil
}

func resetNonPatchableField(obj client.Object) {
obj.SetUID("")
obj.SetManagedFields(nil)
obj.SetResourceVersion("")
}

func (r *Reconciler) updateManifest(ctx context.Context, manifest *v1beta2.Manifest,
requeueReason metrics.ManifestRequeueReason,
) (ctrl.Result, error) {
r.ManifestMetrics.RecordRequeueReason(requeueReason, queue.IntendedRequeue)
if err := r.Update(ctx, manifest); err != nil {
r.Event(manifest, "Warning", "UpdateObject", err.Error())
return ctrl.Result{}, fmt.Errorf("failed to update object: %w", err)

if err := r.manifestClient.UpdateManifest(ctx, manifest); err != nil {
return ctrl.Result{}, err
}

return ctrl.Result{Requeue: true}, nil
}

Expand All @@ -708,3 +718,25 @@ func (r *Reconciler) cleanUpMandatoryModuleMetrics(manifest *v1beta2.Manifest) {
r.MandatoryModuleMetrics.CleanupMetrics(kymaName, moduleName)
}
}

func getCR(ctx context.Context, skrClient client.Client, manifest *v1beta2.Manifest) (*unstructured.Unstructured,
error,
) {
resourceCR := &unstructured.Unstructured{}
name := manifest.Spec.Resource.GetName()
namespace := manifest.Spec.Resource.GetNamespace()
gvk := manifest.Spec.Resource.GroupVersionKind()

resourceCR.SetGroupVersionKind(schema.GroupVersionKind{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
})

if err := skrClient.Get(ctx,
client.ObjectKey{Name: name, Namespace: namespace}, resourceCR); err != nil {
return nil, fmt.Errorf("%w: failed to fetch default resource CR", err)
}

return resourceCR, nil
}
Loading
Loading