@@ -19,6 +19,7 @@ import (
1919 "strings"
2020
2121 "sigs.k8s.io/controller-runtime/pkg/client"
22+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2223 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2324
2425 "k8s.io/client-go/kubernetes"
@@ -67,6 +68,7 @@ type SFUtilContext struct {
6768 owner client.Object
6869 standalone bool
6970 zkChanged bool
71+ DryRun bool
7072}
7173
7274type HostAlias struct {
@@ -99,7 +101,8 @@ func (r *SFUtilContext) GetM(name string, obj client.Object) bool {
99101 client.ObjectKey {
100102 Name : name ,
101103 Namespace : r .ns ,
102- }, obj )
104+ },
105+ obj )
103106 if errors .IsNotFound (err ) {
104107 return false
105108 } else if err != nil {
@@ -110,6 +113,10 @@ func (r *SFUtilContext) GetM(name string, obj client.Object) bool {
110113
111114// CreateR creates a resource with the owner as the ownerReferences.
112115func (r * SFUtilContext ) CreateR (obj client.Object ) {
116+ if r .DryRun {
117+ logging .LogI ("[Dry Run] Would create object, name: " + obj .GetName ())
118+ return
119+ }
113120 r .setOwnerReference (obj )
114121 if err := r .Client .Create (r .ctx , obj ); err != nil && ! errors .IsAlreadyExists (err ) {
115122 panic (err .Error ())
@@ -118,13 +125,34 @@ func (r *SFUtilContext) CreateR(obj client.Object) {
118125
119126// DeleteR delete a resource.
120127func (r * SFUtilContext ) DeleteR (obj client.Object ) {
128+ if r .DryRun {
129+ logging .LogI ("[Dry Run] Would delete object, name: " + obj .GetName ())
130+ return
131+ }
121132 if err := r .Client .Delete (r .ctx , obj ); err != nil && ! errors .IsNotFound (err ) {
122133 panic (err .Error ())
123134 }
124135}
125136
126137// UpdateR updates resource with the owner as the ownerReferences.
127138func (r * SFUtilContext ) UpdateR (obj client.Object ) bool {
139+ if r .DryRun {
140+ // When dry-running, we must check that the object exists to avoid reconciliation loops.
141+ gvk , err := apiutil .GVKForObject (obj , r .Scheme )
142+ if err != nil {
143+ panic (err .Error ())
144+ }
145+ newObj , err := r .Scheme .New (gvk )
146+ if err != nil {
147+ // This should not happen if GVKForObject succeeded.
148+ panic (err .Error ())
149+ }
150+ if ! r .GetM (obj .GetName (), newObj .(client.Object )) {
151+ logging .LogI ("[Dry Run] Would have failed to update non-existent object, name: " + obj .GetName ())
152+ return false
153+ }
154+ return true
155+ }
128156 r .setOwnerReference (obj )
129157 logging .LogI ("Updating object name:" + obj .GetName ())
130158 if err := r .Client .Update (r .ctx , obj ); err != nil {
@@ -140,7 +168,9 @@ func (r *SFUtilContext) GetOrCreate(obj client.Object) bool {
140168 name := obj .GetName ()
141169
142170 if ! r .GetM (name , obj ) {
143- logging .LogI ("Creating object, name: " + obj .GetName ())
171+ if ! r .DryRun {
172+ logging .LogI ("Creating object, name: " + obj .GetName ())
173+ }
144174 r .CreateR (obj )
145175 return false
146176 }
@@ -191,15 +221,21 @@ func (r *SFUtilContext) EnsureConfigMap(baseName string, data map[string]string)
191221 name := baseName + "-config-map"
192222 var cm apiv1.ConfigMap
193223 if ! r .GetM (name , & cm ) {
194- logging .LogI ("Creating config map name: " + name )
224+ if ! r .DryRun {
225+ logging .LogI ("Creating config map name: " + name )
226+ }
195227 cm = apiv1.ConfigMap {
196228 ObjectMeta : metav1.ObjectMeta {Name : name , Namespace : r .ns },
197229 Data : data ,
198230 }
199231 r .CreateR (& cm )
200232 } else {
201233 if ! reflect .DeepEqual (cm .Data , data ) {
202- logging .LogI ("Updating configmap, name: " + name )
234+ if r .DryRun {
235+ logging .LogI ("[Dry Run] Would update ConfigMap, name: " + name + ". Reason: Data has changed." )
236+ } else {
237+ logging .LogI ("Updating configmap, name: " + name )
238+ }
203239 cm .Data = data
204240 r .UpdateR (& cm )
205241 }
@@ -213,11 +249,17 @@ func (r *SFUtilContext) EnsureSecret(secret *apiv1.Secret) {
213249 var current apiv1.Secret
214250 name := secret .GetName ()
215251 if ! r .GetM (name , & current ) {
216- logging .LogI ("Creating secret, name: " + name )
252+ if ! r .DryRun {
253+ logging .LogI ("Creating secret, name: " + name )
254+ }
217255 r .CreateR (secret )
218256 } else {
219257 if ! reflect .DeepEqual (current .Data , secret .Data ) {
220- logging .LogI ("Updating secret, name: " + name )
258+ if r .DryRun {
259+ logging .LogI ("[Dry Run] Would update Secret, name: " + name + ". Reason: Data has changed." )
260+ } else {
261+ logging .LogI ("Updating secret, name: " + name )
262+ }
221263 current .Data = secret .Data
222264 r .UpdateR (& current )
223265 }
@@ -231,7 +273,9 @@ func (r *SFUtilContext) EnsureSecret(secret *apiv1.Secret) {
231273func (r * SFUtilContext ) ensureSecretFromFunc (name string , getData func () string ) apiv1.Secret {
232274 var secret apiv1.Secret
233275 if ! r .GetM (name , & secret ) {
234- logging .LogI ("Creating secret, name: " + name )
276+ if ! r .DryRun {
277+ logging .LogI ("Creating secret, name: " + name )
278+ }
235279 secret = base .MkSecretFromFunc (name , r .ns , getData )
236280 r .CreateR (& secret )
237281 }
@@ -250,7 +294,9 @@ func (r *SFUtilContext) EnsureSecretUUID(name string) apiv1.Secret {
250294func (r * SFUtilContext ) EnsureSSHKeySecret (name string ) {
251295 var secret apiv1.Secret
252296 if ! r .GetM (name , & secret ) {
253- logging .LogI ("Creating ssh key, name: " + name )
297+ if ! r .DryRun {
298+ logging .LogI ("Creating ssh key, name: " + name )
299+ }
254300 secret := base .MkSSHKeySecret (name , r .ns )
255301 r .CreateR (& secret )
256302 }
@@ -270,12 +316,18 @@ func (r *SFUtilContext) EnsureService(service *apiv1.Service) {
270316 }
271317 name := service .GetName ()
272318 if ! r .GetM (name , & current ) {
273- logging .LogI ("Creating service, name: " + name )
319+ if ! r .DryRun {
320+ logging .LogI ("Creating service, name: " + name )
321+ }
274322 r .CreateR (service )
275323 } else {
276324 if ! reflect .DeepEqual (current .Spec .Selector , service .Spec .Selector ) ||
277325 spsAsString (current .Spec .Ports ) != spsAsString (service .Spec .Ports ) {
278- logging .LogI ("Updating service, name: " + name )
326+ if r .DryRun {
327+ logging .LogI ("[Dry Run] Would update Service, name: " + name + ". Reason: Spec has changed." )
328+ } else {
329+ logging .LogI ("Updating service, name: " + name )
330+ }
279331 current .Spec = * service .Spec .DeepCopy ()
280332 r .UpdateR (& current )
281333 }
@@ -384,6 +436,10 @@ func (r *SFUtilContext) getPods(dep *appsv1.StatefulSet) ([]apiv1.Pod, bool) {
384436
385437// IsStatefulSetReady checks if StatefulSet is ready
386438func (r * SFUtilContext ) IsStatefulSetReady (dep * appsv1.StatefulSet ) bool {
439+ if r .DryRun {
440+ return true
441+ }
442+
387443 logging .LogI ("Waiting for statefulset, name: " + dep .ObjectMeta .GetName ())
388444 rolloutOk := base .IsStatefulSetRolloutDone (dep )
389445 if rolloutOk {
@@ -407,6 +463,10 @@ func (r *SFUtilContext) IsStatefulSetReady(dep *appsv1.StatefulSet) bool {
407463
408464// IsDeploymentReady checks if Deployment is ready
409465func (r * SFUtilContext ) IsDeploymentReady (dep * appsv1.Deployment ) bool {
466+ if r .DryRun {
467+ return true
468+ }
469+
410470 logging .LogI ("Waiting for deployment, name: " + dep .ObjectMeta .GetName ())
411471 rolloutOk := base .IsDeploymentRolloutDone (dep )
412472 if rolloutOk {
@@ -646,7 +706,9 @@ func (r *SFController) EnsureDiskUsagePromRule(ruleGroups []monitoringv1.RuleGro
646706 return false
647707 } else {
648708 if ! utils .MapEquals (& currentPromRule .ObjectMeta .Annotations , & desiredDUPromRule .ObjectMeta .Annotations ) {
649- logging .LogI ("Default disk usage Prometheus rules changed, updating..." )
709+ if ! r .DryRun {
710+ logging .LogI ("Default disk usage Prometheus rules changed, updating..." )
711+ }
650712 currentPromRule .Spec = desiredDUPromRule .Spec
651713 currentPromRule .ObjectMeta .Annotations = desiredDUPromRule .ObjectMeta .Annotations
652714 r .UpdateR (& currentPromRule )
@@ -676,7 +738,9 @@ func (r *SFController) EnsureSFPodMonitor(ports []string, selector metav1.LabelS
676738 return false
677739 } else {
678740 if ! utils .MapEquals (& currentPodMonitor .ObjectMeta .Annotations , & annotations ) {
679- logging .LogI ("SF PodMonitor configuration changed, updating..." )
741+ if ! r .DryRun {
742+ logging .LogI ("SF PodMonitor configuration changed, updating..." )
743+ }
680744 currentPodMonitor .Spec = desiredPodMonitor .Spec
681745 currentPodMonitor .ObjectMeta .Annotations = annotations
682746 r .UpdateR (& currentPodMonitor )
@@ -793,7 +857,11 @@ func (r *SFController) ensureDeployment(dep appsv1.Deployment) (*appsv1.Deployme
793857 needUpdate = true
794858 }
795859 if needUpdate {
796- logging .LogI (name + " configuration changed, rollout pods ..." )
860+ if r .DryRun {
861+ logging .LogI ("[Dry Run] Would update Deployment, name: " + name + ". Reason: Spec template has changed." )
862+ } else {
863+ logging .LogI (name + " configuration changed, rollout pods ..." )
864+ }
797865 current .Spec = dep .DeepCopy ().Spec
798866 r .UpdateR (& current )
799867 return & current , true
@@ -825,7 +893,11 @@ func (r *SFController) ensureStatefulset(storageClass *string, sts appsv1.Statef
825893 needUpdate = true
826894 }
827895 if needUpdate {
828- logging .LogI (name + " configuration changed, rollout pods ..." )
896+ if r .DryRun {
897+ logging .LogI ("[Dry Run] Would update StatefulSet, name: " + name + ". Reason: Spec template has changed." )
898+ } else {
899+ logging .LogI (name + " configuration changed, rollout pods ..." )
900+ }
829901 r .UpdateR (& current )
830902 return & current , true
831903 }
0 commit comments