@@ -13,6 +13,7 @@ import (
1313 rbacv1 "k8s.io/api/rbac/v1"
1414 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1515 "k8s.io/apimachinery/pkg/runtime"
16+ "k8s.io/apimachinery/pkg/types"
1617 "k8s.io/client-go/util/retry"
1718 ctrl "sigs.k8s.io/controller-runtime"
1819 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -56,10 +57,12 @@ func BuildCollector(params manifests.Params) ([]client.Object, error) {
5657 }
5758 return resources , nil
5859}
59-
60- // reconcileDesiredObjects runs the reconcile process using the mutateFn over the given list of objects.
61- func reconcileDesiredObjects (ctx context.Context , kubeClient client.Client , logger logr.Logger , owner metav1.Object , scheme * runtime.Scheme , desiredObjects ... client.Object ) error {
60+ func reconcileDesiredObjectUIDs (ctx context.Context , kubeClient client.Client , logger logr.Logger ,
61+ owner metav1.Object , scheme * runtime.Scheme , desiredObjects ... client.Object ) (map [types.UID ]client.Object , error ) {
6262 var errs []error
63+ existingObjectMap := make (map [types.UID ]client.Object )
64+ var existingObjectList []client.Object
65+
6366 for _ , desired := range desiredObjects {
6467 l := logger .WithValues (
6568 "object_name" , desired .GetName (),
@@ -76,6 +79,8 @@ func reconcileDesiredObjects(ctx context.Context, kubeClient client.Client, logg
7679 // existing is an object the controller runtime will hydrate for us
7780 // we obtain the existing object by deep copying the desired object because it's the most convenient way
7881 existing := desired .DeepCopyObject ().(client.Object )
82+ existingObjectList = append (existingObjectList , existing ) //uid are not assigned yet
83+
7984 mutateFn := manifests .MutateFuncFor (existing , desired )
8085 var op controllerutil.OperationResult
8186 crudErr := retry .RetryOnConflict (retry .DefaultRetry , func () error {
@@ -87,7 +92,7 @@ func reconcileDesiredObjects(ctx context.Context, kubeClient client.Client, logg
8792 l .Error (crudErr , "detected immutable field change, trying to delete, new object will be created on next reconcile" , "existing" , existing .GetName ())
8893 delErr := kubeClient .Delete (ctx , existing )
8994 if delErr != nil {
90- return delErr
95+ return nil , delErr
9196 }
9297 continue
9398 } else if crudErr != nil {
@@ -99,11 +104,61 @@ func reconcileDesiredObjects(ctx context.Context, kubeClient client.Client, logg
99104 l .V (1 ).Info (fmt .Sprintf ("desired has been %s" , op ))
100105 }
101106 if len (errs ) > 0 {
102- return fmt .Errorf ("failed to create objects for %s: %w" , owner .GetName (), errors .Join (errs ... ))
107+ return nil , fmt .Errorf ("failed to create objects for %s: %w" , owner .GetName (), errors .Join (errs ... ))
108+ }
109+ for _ , obj := range existingObjectList {
110+ existingObjectMap [obj .GetUID ()] = obj
111+ }
112+ return existingObjectMap , nil
113+ }
114+
115+ func reconcileDesiredObjectsWPrune (ctx context.Context , kubeClient client.Client , logger logr.Logger , owner v1alpha1.AmazonCloudWatchAgent , scheme * runtime.Scheme ,
116+ desiredObjects []client.Object ,
117+ searchOwnedObjectsFunc func (ctx context.Context , owner v1alpha1.AmazonCloudWatchAgent ) (map [types.UID ]client.Object , error ),
118+ ) error {
119+ previouslyOwnedObjects , err := searchOwnedObjectsFunc (ctx , owner )
120+ if err != nil {
121+ return fmt .Errorf ("failed to search owned objects: %w" , err )
122+ }
123+
124+ desiredObjectMap , err := reconcileDesiredObjectUIDs (ctx , kubeClient , logger , & owner , scheme , desiredObjects ... )
125+
126+ // Pruning owned objects in the cluster which are not should not be present after the reconciliation.
127+ err = pruneStaleObjects (ctx , kubeClient , logger , previouslyOwnedObjects , desiredObjectMap )
128+ if err != nil {
129+ return fmt .Errorf ("failed to prune objects for %s: %w" , owner .GetName (), err )
103130 }
104131 return nil
105132}
106133
134+ // reconcileDesiredObjects runs the reconcile process using the mutateFn over the given list of objects.
135+ func reconcileDesiredObjects (ctx context.Context , kubeClient client.Client , logger logr.Logger , owner metav1.Object , scheme * runtime.Scheme , desiredObjects ... client.Object ) error {
136+ _ , err := reconcileDesiredObjectUIDs (ctx , kubeClient , logger , owner , scheme , desiredObjects ... )
137+ return err
138+ }
139+
140+ func pruneStaleObjects (ctx context.Context , kubeClient client.Client , logger logr.Logger , previouslyOwnedMap , desiredMap map [types.UID ]client.Object ) error {
141+ // Pruning owned objects in the cluster which should not be present after the reconciliation.
142+ var pruneErrs []error
143+ for uid , obj := range previouslyOwnedMap {
144+ l := logger .WithValues (
145+ "object_name" , obj .GetName (),
146+ "object_kind" , obj .GetObjectKind ().GroupVersionKind ().Kind ,
147+ )
148+ if _ , found := desiredMap [uid ]; found {
149+ continue
150+ }
151+
152+ l .Info ("pruning unmanaged resource" )
153+ err := kubeClient .Delete (ctx , obj )
154+ if err != nil {
155+ l .Error (err , "failed to delete resource" )
156+ pruneErrs = append (pruneErrs , err )
157+ }
158+ }
159+ return errors .Join (pruneErrs ... )
160+ }
161+
107162func enabledAcceleratedComputeByAgentConfig (ctx context.Context , c client.Client , log logr.Logger ) bool {
108163 agentResource := getAmazonCloudWatchAgentResource (ctx , c )
109164 // missing feature flag means it's on by default
0 commit comments