Skip to content

Commit a71fe82

Browse files
Update the owner reference of resources, if the reference is not correct. (#230)
This addresses the situation when a resource, that a SolrCloud or SolrPrometheusExporter is supposed to control, has a different OwnerReference with controller= true. If this is found, then the controlling owner resource will be downgraded to controller=false, and a controlling OwnerReference will be created for either the SolrCloud or SolrPrometheusExporter.
1 parent 497630e commit a71fe82

File tree

4 files changed

+133
-68
lines changed

4 files changed

+133
-68
lines changed

controllers/solrcloud_controller.go

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,26 @@ func (r *SolrCloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
116116

117117
// Generate Common Service
118118
commonService := util.GenerateCommonService(instance)
119-
if err := controllerutil.SetControllerReference(instance, commonService, r.scheme); err != nil {
120-
return requeueOrNot, err
121-
}
122119

123120
// Check if the Common Service already exists
124121
commonServiceLogger := logger.WithValues("service", commonService.Name)
125122
foundCommonService := &corev1.Service{}
126123
err = r.Get(context.TODO(), types.NamespacedName{Name: commonService.Name, Namespace: commonService.Namespace}, foundCommonService)
127124
if err != nil && errors.IsNotFound(err) {
128125
commonServiceLogger.Info("Creating Common Service")
129-
err = r.Create(context.TODO(), commonService)
130-
} else if err == nil && util.CopyServiceFields(commonService, foundCommonService, commonServiceLogger) {
126+
if err = controllerutil.SetControllerReference(instance, commonService, r.scheme); err == nil {
127+
err = r.Create(context.TODO(), commonService)
128+
}
129+
} else if err == nil {
130+
var needsUpdate bool
131+
needsUpdate, err = util.OvertakeControllerRef(instance, foundCommonService, r.scheme)
132+
needsUpdate = util.CopyServiceFields(commonService, foundCommonService, commonServiceLogger) || needsUpdate
133+
131134
// Update the found Service and write the result back if there are any changes
132-
commonServiceLogger.Info("Updating Common Service")
133-
err = r.Update(context.TODO(), foundCommonService)
135+
if needsUpdate && err == nil {
136+
commonServiceLogger.Info("Updating Common Service")
137+
err = r.Update(context.TODO(), foundCommonService)
138+
}
134139
}
135140
if err != nil {
136141
return requeueOrNot, err
@@ -161,21 +166,26 @@ func (r *SolrCloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
161166
// Generate HeadlessService
162167
if instance.UsesHeadlessService() {
163168
headless := util.GenerateHeadlessService(instance)
164-
if err := controllerutil.SetControllerReference(instance, headless, r.scheme); err != nil {
165-
return requeueOrNot, err
166-
}
167169

168170
// Check if the HeadlessService already exists
169171
headlessServiceLogger := logger.WithValues("service", headless.Name)
170172
foundHeadless := &corev1.Service{}
171173
err = r.Get(context.TODO(), types.NamespacedName{Name: headless.Name, Namespace: headless.Namespace}, foundHeadless)
172174
if err != nil && errors.IsNotFound(err) {
173-
headlessServiceLogger.Info("Creating HeadlessService")
174-
err = r.Create(context.TODO(), headless)
175-
} else if err == nil && util.CopyServiceFields(headless, foundHeadless, headlessServiceLogger) {
175+
headlessServiceLogger.Info("Creating Headless Service")
176+
if err = controllerutil.SetControllerReference(instance, headless, r.scheme); err == nil {
177+
err = r.Create(context.TODO(), headless)
178+
}
179+
} else if err == nil {
180+
var needsUpdate bool
181+
needsUpdate, err = util.OvertakeControllerRef(instance, foundHeadless, r.scheme)
182+
needsUpdate = util.CopyServiceFields(headless, foundHeadless, headlessServiceLogger) || needsUpdate
183+
176184
// Update the found HeadlessService and write the result back if there are any changes
177-
headlessServiceLogger.Info("Updating HeadlessService")
178-
err = r.Update(context.TODO(), foundHeadless)
185+
if needsUpdate && err == nil {
186+
headlessServiceLogger.Info("Updating Headless Service")
187+
err = r.Update(context.TODO(), foundHeadless)
188+
}
179189
}
180190
if err != nil {
181191
return requeueOrNot, err
@@ -235,9 +245,6 @@ func (r *SolrCloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
235245
if reconcileConfigInfo[util.SolrXmlFile] == "" {
236246
// no user provided solr.xml, so create the default
237247
configMap := util.GenerateConfigMap(instance)
238-
if err := controllerutil.SetControllerReference(instance, configMap, r.scheme); err != nil {
239-
return requeueOrNot, err
240-
}
241248

242249
reconcileConfigInfo[util.SolrXmlMd5Annotation] = fmt.Sprintf("%x", md5.Sum([]byte(configMap.Data[util.SolrXmlFile])))
243250
reconcileConfigInfo[util.SolrXmlFile] = configMap.Name
@@ -248,11 +255,19 @@ func (r *SolrCloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
248255
err = r.Get(context.TODO(), types.NamespacedName{Name: configMap.Name, Namespace: configMap.Namespace}, foundConfigMap)
249256
if err != nil && errors.IsNotFound(err) {
250257
configMapLogger.Info("Creating ConfigMap")
251-
err = r.Create(context.TODO(), configMap)
252-
} else if err == nil && util.CopyConfigMapFields(configMap, foundConfigMap, configMapLogger) {
258+
if err = controllerutil.SetControllerReference(instance, configMap, r.scheme); err == nil {
259+
err = r.Create(context.TODO(), configMap)
260+
}
261+
} else if err == nil {
262+
var needsUpdate bool
263+
needsUpdate, err = util.OvertakeControllerRef(instance, foundConfigMap, r.scheme)
264+
needsUpdate = util.CopyConfigMapFields(configMap, foundConfigMap, configMapLogger) || needsUpdate
265+
253266
// Update the found ConfigMap and write the result back if there are any changes
254-
configMapLogger.Info("Updating ConfigMap")
255-
err = r.Update(context.TODO(), foundConfigMap)
267+
if needsUpdate && err == nil {
268+
configMapLogger.Info("Updating ConfigMap")
269+
err = r.Update(context.TODO(), foundConfigMap)
270+
}
256271
}
257272
if err != nil {
258273
return requeueOrNot, err
@@ -395,28 +410,33 @@ func (r *SolrCloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
395410
if !blockReconciliationOfStatefulSet {
396411
// Generate StatefulSet
397412
statefulSet := util.GenerateStatefulSet(instance, &newStatus, hostNameIpMap, reconcileConfigInfo, needsPkcs12InitContainer, tlsCertMd5)
398-
if err := controllerutil.SetControllerReference(instance, statefulSet, r.scheme); err != nil {
399-
return requeueOrNot, err
400-
}
401413

402414
// Check if the StatefulSet already exists
403415
statefulSetLogger := logger.WithValues("statefulSet", statefulSet.Name)
404416
foundStatefulSet := &appsv1.StatefulSet{}
405417
err = r.Get(context.TODO(), types.NamespacedName{Name: statefulSet.Name, Namespace: statefulSet.Namespace}, foundStatefulSet)
406418
if err != nil && errors.IsNotFound(err) {
407419
statefulSetLogger.Info("Creating StatefulSet")
408-
err = r.Create(context.TODO(), statefulSet)
420+
if err = controllerutil.SetControllerReference(instance, statefulSet, r.scheme); err == nil {
421+
err = r.Create(context.TODO(), statefulSet)
422+
}
409423
// Find which labels the PVCs will be using, to use for the finalizer
410424
pvcLabelSelector = statefulSet.Spec.Selector.MatchLabels
411425
} else if err == nil {
412426
statefulSetStatus = foundStatefulSet.Status
413-
if util.CopyStatefulSetFields(statefulSet, foundStatefulSet, statefulSetLogger) {
414-
// Update the found StatefulSet and write the result back if there are any changes
427+
// Find which labels the PVCs will be using, to use for the finalizer
428+
pvcLabelSelector = foundStatefulSet.Spec.Selector.MatchLabels
429+
430+
// Check to see if the StatefulSet needs an update
431+
var needsUpdate bool
432+
needsUpdate, err = util.OvertakeControllerRef(instance, foundStatefulSet, r.scheme)
433+
needsUpdate = util.CopyStatefulSetFields(statefulSet, foundStatefulSet, statefulSetLogger) || needsUpdate
434+
435+
// Update the found StatefulSet and write the result back if there are any changes
436+
if needsUpdate && err == nil {
415437
statefulSetLogger.Info("Updating StatefulSet")
416438
err = r.Update(context.TODO(), foundStatefulSet)
417439
}
418-
// Find which labels the PVCs will be using, to use for the finalizer
419-
pvcLabelSelector = foundStatefulSet.Spec.Selector.MatchLabels
420440
}
421441
if err != nil {
422442
return requeueOrNot, err
@@ -493,21 +513,26 @@ func (r *SolrCloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
493513
if extAddressabilityOpts != nil && extAddressabilityOpts.Method == solr.Ingress {
494514
// Generate Ingress
495515
ingress := util.GenerateIngress(instance, solrNodeNames)
496-
if err := controllerutil.SetControllerReference(instance, ingress, r.scheme); err != nil {
497-
return requeueOrNot, err
498-
}
499516

500517
// Check if the Ingress already exists
501518
ingressLogger := logger.WithValues("ingress", ingress.Name)
502519
foundIngress := &netv1.Ingress{}
503520
err = r.Get(context.TODO(), types.NamespacedName{Name: ingress.Name, Namespace: ingress.Namespace}, foundIngress)
504521
if err != nil && errors.IsNotFound(err) {
505522
ingressLogger.Info("Creating Ingress")
506-
err = r.Create(context.TODO(), ingress)
507-
} else if err == nil && util.CopyIngressFields(ingress, foundIngress, ingressLogger) {
523+
if err = controllerutil.SetControllerReference(instance, ingress, r.scheme); err == nil {
524+
err = r.Create(context.TODO(), ingress)
525+
}
526+
} else if err == nil {
527+
var needsUpdate bool
528+
needsUpdate, err = util.OvertakeControllerRef(instance, foundIngress, r.scheme)
529+
needsUpdate = util.CopyIngressFields(ingress, foundIngress, ingressLogger) || needsUpdate
530+
508531
// Update the found Ingress and write the result back if there are any changes
509-
ingressLogger.Info("Updating Ingress")
510-
err = r.Update(context.TODO(), foundIngress)
532+
if needsUpdate && err == nil {
533+
ingressLogger.Info("Updating Ingress")
534+
err = r.Update(context.TODO(), foundIngress)
535+
}
511536
}
512537
if err != nil {
513538
return requeueOrNot, err
@@ -651,24 +676,29 @@ func reconcileCloudStatus(r *SolrCloudReconciler, solrCloud *solr.SolrCloud, new
651676
func reconcileNodeService(r *SolrCloudReconciler, logger logr.Logger, instance *solr.SolrCloud, nodeName string) (err error, ip string) {
652677
// Generate Node Service
653678
service := util.GenerateNodeService(instance, nodeName)
654-
if err := controllerutil.SetControllerReference(instance, service, r.scheme); err != nil {
655-
return err, ip
656-
}
657679

658680
// Check if the Node Service already exists
659681
nodeServiceLogger := logger.WithValues("service", service.Name)
660682
foundService := &corev1.Service{}
661683
err = r.Get(context.TODO(), types.NamespacedName{Name: service.Name, Namespace: service.Namespace}, foundService)
662684
if err != nil && errors.IsNotFound(err) {
663685
nodeServiceLogger.Info("Creating Node Service")
664-
err = r.Create(context.TODO(), service)
686+
if err = controllerutil.SetControllerReference(instance, service, r.scheme); err == nil {
687+
err = r.Create(context.TODO(), service)
688+
}
665689
} else if err == nil {
666-
if util.CopyServiceFields(service, foundService, nodeServiceLogger) {
690+
ip = foundService.Spec.ClusterIP
691+
692+
// Check to see if the Service needs an update
693+
var needsUpdate bool
694+
needsUpdate, err = util.OvertakeControllerRef(instance, foundService, r.scheme)
695+
needsUpdate = util.CopyServiceFields(service, foundService, nodeServiceLogger) || needsUpdate
696+
697+
if needsUpdate && err == nil {
667698
// Update the found Node service because there are differences between our version and the existing version
668699
nodeServiceLogger.Info("Updating Node Service")
669700
err = r.Update(context.TODO(), foundService)
670701
}
671-
ip = foundService.Spec.ClusterIP
672702
}
673703
if err != nil {
674704
return err, ip
@@ -689,20 +719,23 @@ func reconcileZk(r *SolrCloudReconciler, logger logr.Logger, instance *solr.Solr
689719
return errors.NewBadRequest("Cannot create a Zookeeper Cluster, as the Solr Operator is not configured to use the Zookeeper CRD")
690720
}
691721
zkCluster := util.GenerateZookeeperCluster(instance, pzk)
692-
if err := controllerutil.SetControllerReference(instance, zkCluster, r.scheme); err != nil {
693-
return err
694-
}
695722

696723
// Check if the ZookeeperCluster already exists
697724
zkLogger := logger.WithValues("zookeeperCluster", zkCluster.Name)
698725
foundZkCluster := &zk.ZookeeperCluster{}
699726
err := r.Get(context.TODO(), types.NamespacedName{Name: zkCluster.Name, Namespace: zkCluster.Namespace}, foundZkCluster)
700727
if err != nil && errors.IsNotFound(err) {
701728
zkLogger.Info("Creating Zookeeer Cluster")
702-
err = r.Create(context.TODO(), zkCluster)
729+
if err = controllerutil.SetControllerReference(instance, zkCluster, r.scheme); err == nil {
730+
err = r.Create(context.TODO(), zkCluster)
731+
}
703732
} else if err == nil {
704-
if util.CopyZookeeperClusterFields(zkCluster, foundZkCluster, zkLogger) {
705-
// Update the found ZookeeperCluster and write the result back if there are any changes
733+
var needsUpdate bool
734+
needsUpdate, err = util.OvertakeControllerRef(instance, foundZkCluster, r.scheme)
735+
needsUpdate = util.CopyZookeeperClusterFields(zkCluster, foundZkCluster, zkLogger) || needsUpdate
736+
737+
// Update the found ZookeeperCluster and write the result back if there are any changes
738+
if needsUpdate && err == nil {
706739
zkLogger.Info("Updating Zookeeer Cluster")
707740
err = r.Update(context.TODO(), foundZkCluster)
708741
}

controllers/solrprometheusexporter_controller.go

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,6 @@ func (r *SolrPrometheusExporterReconciler) Reconcile(req ctrl.Request) (ctrl.Res
111111
if prometheusExporter.Spec.Config != "" {
112112
// Generate ConfigMap
113113
configMap := util.GenerateMetricsConfigMap(prometheusExporter)
114-
if err := controllerutil.SetControllerReference(prometheusExporter, configMap, r.scheme); err != nil {
115-
return ctrl.Result{}, err
116-
}
117114

118115
// capture the MD5 for the default config XML, otherwise we already computed it above
119116
if configXmlMd5 == "" {
@@ -126,11 +123,19 @@ func (r *SolrPrometheusExporterReconciler) Reconcile(req ctrl.Request) (ctrl.Res
126123
err = r.Get(context.TODO(), types.NamespacedName{Name: configMap.Name, Namespace: configMap.Namespace}, foundConfigMap)
127124
if err != nil && errors.IsNotFound(err) {
128125
configMapLogger.Info("Creating ConfigMap")
129-
err = r.Create(context.TODO(), configMap)
130-
} else if err == nil && util.CopyConfigMapFields(configMap, foundConfigMap, configMapLogger) {
126+
if err = controllerutil.SetControllerReference(prometheusExporter, configMap, r.scheme); err == nil {
127+
err = r.Create(context.TODO(), configMap)
128+
}
129+
} else if err == nil {
130+
var needsUpdate bool
131+
needsUpdate, err = util.OvertakeControllerRef(prometheusExporter, foundConfigMap, r.scheme)
132+
needsUpdate = util.CopyConfigMapFields(configMap, foundConfigMap, configMapLogger) || needsUpdate
133+
131134
// Update the found ConfigMap and write the result back if there are any changes
132-
configMapLogger.Info("Updating ConfigMap")
133-
err = r.Update(context.TODO(), foundConfigMap)
135+
if needsUpdate && err == nil {
136+
configMapLogger.Info("Updating ConfigMap")
137+
err = r.Update(context.TODO(), foundConfigMap)
138+
}
134139
}
135140
if err != nil {
136141
return ctrl.Result{}, err
@@ -139,21 +144,26 @@ func (r *SolrPrometheusExporterReconciler) Reconcile(req ctrl.Request) (ctrl.Res
139144

140145
// Generate Metrics Service
141146
metricsService := util.GenerateSolrMetricsService(prometheusExporter)
142-
if err := controllerutil.SetControllerReference(prometheusExporter, metricsService, r.scheme); err != nil {
143-
return ctrl.Result{}, err
144-
}
145147

146148
// Check if the Metrics Service already exists
147149
serviceLogger := logger.WithValues("service", metricsService.Name)
148150
foundMetricsService := &corev1.Service{}
149151
err = r.Get(context.TODO(), types.NamespacedName{Name: metricsService.Name, Namespace: metricsService.Namespace}, foundMetricsService)
150152
if err != nil && errors.IsNotFound(err) {
151153
serviceLogger.Info("Creating Service")
152-
err = r.Create(context.TODO(), metricsService)
153-
} else if err == nil && util.CopyServiceFields(metricsService, foundMetricsService, serviceLogger) {
154+
if err = controllerutil.SetControllerReference(prometheusExporter, metricsService, r.scheme); err == nil {
155+
err = r.Create(context.TODO(), metricsService)
156+
}
157+
} else if err == nil {
158+
var needsUpdate bool
159+
needsUpdate, err = util.OvertakeControllerRef(prometheusExporter, foundMetricsService, r.scheme)
160+
needsUpdate = util.CopyServiceFields(metricsService, foundMetricsService, serviceLogger) || needsUpdate
161+
154162
// Update the found Metrics Service and write the result back if there are any changes
155-
serviceLogger.Info("Updating Service")
156-
err = r.Update(context.TODO(), foundMetricsService)
163+
if needsUpdate && err == nil {
164+
serviceLogger.Info("Updating Service")
165+
err = r.Update(context.TODO(), foundMetricsService)
166+
}
157167
}
158168
if err != nil {
159169
return ctrl.Result{}, err
@@ -225,9 +235,6 @@ func (r *SolrPrometheusExporterReconciler) Reconcile(req ctrl.Request) (ctrl.Res
225235
}
226236

227237
deploy := util.GenerateSolrPrometheusExporterDeployment(prometheusExporter, solrConnectionInfo, configXmlMd5, tlsClientOptions, basicAuthMd5)
228-
if err := controllerutil.SetControllerReference(prometheusExporter, deploy, r.scheme); err != nil {
229-
return ctrl.Result{}, err
230-
}
231238

232239
ready := false
233240
// Check if the Metrics Deployment already exists
@@ -236,9 +243,16 @@ func (r *SolrPrometheusExporterReconciler) Reconcile(req ctrl.Request) (ctrl.Res
236243
err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, foundDeploy)
237244
if err != nil && errors.IsNotFound(err) {
238245
deploymentLogger.Info("Creating Deployment")
239-
err = r.Create(context.TODO(), deploy)
246+
if err = controllerutil.SetControllerReference(prometheusExporter, deploy, r.scheme); err == nil {
247+
err = r.Create(context.TODO(), deploy)
248+
}
240249
} else if err == nil {
241-
if util.CopyDeploymentFields(deploy, foundDeploy, deploymentLogger) {
250+
var needsUpdate bool
251+
needsUpdate, err = util.OvertakeControllerRef(prometheusExporter, foundDeploy, r.scheme)
252+
needsUpdate = util.CopyDeploymentFields(deploy, foundDeploy, deploymentLogger) || needsUpdate
253+
254+
// Update the found Metrics Service and write the result back if there are any changes
255+
if needsUpdate && err == nil {
242256
deploymentLogger.Info("Updating Deployment")
243257
err = r.Update(context.TODO(), foundDeploy)
244258
}

controllers/util/common.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ import (
2323
corev1 "k8s.io/api/core/v1"
2424
netv1 "k8s.io/api/networking/v1beta1"
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/apimachinery/pkg/runtime"
27+
"k8s.io/utils/pointer"
2628
"reflect"
29+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2730
"strconv"
2831
"strings"
2932
)
@@ -536,3 +539,17 @@ func CopyPodContainers(fromPtr, toPtr *[]corev1.Container, basePath string, logg
536539
}
537540
return requireUpdate
538541
}
542+
543+
// OvertakeControllerRef makes sure that the controlled object has the owner as the controller ref.
544+
// If the object has a different controller, then that ref will be downgraded to an "owner" and the new controller ref will be added
545+
func OvertakeControllerRef(owner metav1.Object, controlled metav1.Object, scheme *runtime.Scheme) (needsUpdate bool, err error) {
546+
if !metav1.IsControlledBy(controlled, owner) {
547+
if otherController := metav1.GetControllerOfNoCopy(controlled); otherController != nil {
548+
otherController.Controller = pointer.BoolPtr(false)
549+
otherController.BlockOwnerDeletion = pointer.BoolPtr(false)
550+
}
551+
err = controllerutil.SetControllerReference(owner, controlled, scheme)
552+
needsUpdate = true
553+
}
554+
return needsUpdate, err
555+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ require (
2222
k8s.io/apimachinery v0.19.0
2323
k8s.io/client-go v0.19.0
2424
k8s.io/klog/v2 v2.3.0 // indirect
25+
k8s.io/utils v0.0.0-20200729134348-d5654de09c73
2526
sigs.k8s.io/controller-runtime v0.6.2
2627
)

0 commit comments

Comments
 (0)