Skip to content

Commit a525fc7

Browse files
authored
fix: apply different strategies to refresh pods (#82)
- Only refresh pods get watch namespace from configmap - Refresh Operator pods by delete the operator pod - Refresh Operand pods by rolling update
1 parent 3fc058a commit a525fc7

File tree

1 file changed

+121
-6
lines changed

1 file changed

+121
-6
lines changed

controllers/namespacescope_controller.go

Lines changed: 121 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"strings"
2424
"time"
2525

26+
appsv1 "k8s.io/api/apps/v1"
2627
authorizationv1 "k8s.io/api/authorization/v1"
2728
corev1 "k8s.io/api/core/v1"
2829
rbacv1 "k8s.io/api/rbac/v1"
@@ -179,7 +180,7 @@ func (r *NamespaceScopeReconciler) UpdateConfigMap(instance *operatorv1.Namespac
179180
}
180181
klog.Infof("Created ConfigMap %s", cmKey.String())
181182

182-
if err := r.RestartPods(instance.Spec.RestartLabels, instance.Namespace); err != nil {
183+
if err := r.RestartPods(instance.Spec.RestartLabels, cm, instance.Namespace); err != nil {
183184
return err
184185
}
185186
return nil
@@ -209,7 +210,7 @@ func (r *NamespaceScopeReconciler) UpdateConfigMap(instance *operatorv1.Namespac
209210

210211
// When the configmap updated, restart all the pods with the RestartLabels
211212
if restartpod {
212-
if err := r.RestartPods(instance.Spec.RestartLabels, instance.Namespace); err != nil {
213+
if err := r.RestartPods(instance.Spec.RestartLabels, cm, instance.Namespace); err != nil {
213214
return err
214215
}
215216
}
@@ -607,19 +608,133 @@ func (r *NamespaceScopeReconciler) DeleteRoleBinding(labels map[string]string, t
607608
}
608609

609610
// Restart pods in specific namespace with the matching labels
610-
func (r *NamespaceScopeReconciler) RestartPods(labels map[string]string, namespace string) error {
611+
func (r *NamespaceScopeReconciler) RestartPods(labels map[string]string, cm *corev1.ConfigMap, namespace string) error {
611612
klog.Infof("Restarting pods in namespace %s with matching labels: %v", namespace, labels)
612-
opts := []client.DeleteAllOfOption{
613+
opts := []client.ListOption{
613614
client.MatchingLabels(labels),
614615
client.InNamespace(namespace),
615616
}
616-
if err := r.DeleteAllOf(ctx, &corev1.Pod{}, opts...); err != nil {
617-
klog.Errorf("Failed to restart pods with matching labels %s in namespace %s: %v", labels, namespace, err)
617+
podList := &corev1.PodList{}
618+
if err := r.Client.List(ctx, podList, opts...); err != nil {
619+
klog.Errorf("Failed to list pods with matching labels %s in namespace %s: %v", labels, namespace, err)
618620
return err
619621
}
622+
623+
deploymentNameList := make([]string, 0)
624+
daemonSetNameList := make([]string, 0)
625+
statefulSetNameList := make([]string, 0)
626+
for _, pod := range podList.Items {
627+
// Check if the pod is required to be refreshed
628+
if !needRestart(pod, cm.Name) {
629+
continue
630+
}
631+
// Delete operator pod to refresh it
632+
podLabels := pod.GetLabels()
633+
_, ok := podLabels["olm.operatorGroup"]
634+
if ok {
635+
if err := r.Client.Delete(ctx, &pod); err != nil {
636+
klog.Errorf("Failed to delete pods %s in namespace %s: %v", pod.Name, pod.Namespace, err)
637+
return err
638+
}
639+
continue
640+
}
641+
// Rolling update operand pods
642+
ownerReferences := pod.GetOwnerReferences()
643+
for _, or := range ownerReferences {
644+
if !*or.Controller {
645+
continue
646+
}
647+
switch or.Kind {
648+
case "ReplicaSet":
649+
splitedDN := strings.Split(or.Name, "-")
650+
deploymentName := strings.Join(splitedDN[:len(splitedDN)-1], "-")
651+
deploymentNameList = append(deploymentNameList, deploymentName)
652+
case "DaemonSet":
653+
daemonSetNameList = append(daemonSetNameList, or.Name)
654+
case "StatefulSet":
655+
statefulSetNameList = append(statefulSetNameList, or.Name)
656+
}
657+
}
658+
}
659+
660+
hashedData := sha256.Sum256([]byte(cm.Data["namespaces"]))
661+
annotationValue := hex.EncodeToString(hashedData[0:7])
662+
663+
// Refresh pods from deployment
664+
deploymentNameList = util.ToStringSlice(util.MakeSet(deploymentNameList))
665+
for _, deploymentName := range deploymentNameList {
666+
deploy := &appsv1.Deployment{}
667+
if err := r.Client.Get(ctx, types.NamespacedName{Name: deploymentName, Namespace: namespace}, deploy); err != nil {
668+
klog.Errorf("Failed to get deployment %s in namespace %s: %v", deploymentName, namespace, err)
669+
return err
670+
}
671+
originalDeploy := deploy
672+
if deploy.Spec.Template.Annotations == nil {
673+
deploy.Spec.Template.Annotations = make(map[string]string)
674+
}
675+
deploy.Spec.Template.Annotations["nss.ibm.com/namespaceList"] = annotationValue
676+
if err := r.Patch(ctx, deploy, client.MergeFrom(originalDeploy)); err != nil {
677+
klog.Errorf("Failed to update the annotation of the deployment %s in namespace %s: %v", deploymentName, namespace, err)
678+
return err
679+
}
680+
}
681+
682+
// Refresh pods from daemonSet
683+
daemonSetNameList = util.ToStringSlice(util.MakeSet(daemonSetNameList))
684+
for _, daemonSetName := range daemonSetNameList {
685+
daemonSet := &appsv1.DaemonSet{}
686+
if err := r.Client.Get(ctx, types.NamespacedName{Name: daemonSetName, Namespace: namespace}, daemonSet); err != nil {
687+
klog.Errorf("Failed to get daemonSet %s in namespace %s: %v", daemonSetName, namespace, err)
688+
return err
689+
}
690+
originalDaemonSet := daemonSet
691+
if daemonSet.Spec.Template.Annotations == nil {
692+
daemonSet.Spec.Template.Annotations = make(map[string]string)
693+
}
694+
daemonSet.Spec.Template.Annotations["nss.ibm.com/namespaceList"] = annotationValue
695+
if err := r.Patch(ctx, daemonSet, client.MergeFrom(originalDaemonSet)); err != nil {
696+
klog.Errorf("Failed to update the annotation of the daemonSet %s in namespace %s: %v", daemonSetName, namespace, err)
697+
return err
698+
}
699+
}
700+
701+
// Refresh pods from statefulSet
702+
statefulSetNameList = util.ToStringSlice(util.MakeSet(statefulSetNameList))
703+
for _, statefulSetName := range statefulSetNameList {
704+
statefulSet := &appsv1.StatefulSet{}
705+
if err := r.Client.Get(ctx, types.NamespacedName{Name: statefulSetName, Namespace: namespace}, statefulSet); err != nil {
706+
klog.Errorf("Failed to get statefulSet %s in namespace %s: %v", statefulSetName, namespace, err)
707+
return err
708+
}
709+
originalStatefulSet := statefulSet
710+
if statefulSet.Spec.Template.Annotations == nil {
711+
statefulSet.Spec.Template.Annotations = make(map[string]string)
712+
}
713+
statefulSet.Spec.Template.Annotations["nss.ibm.com/namespaceList"] = annotationValue
714+
if err := r.Patch(ctx, statefulSet, client.MergeFrom(originalStatefulSet)); err != nil {
715+
klog.Errorf("Failed to update the annotation of the statefulSet %s in namespace %s: %v", statefulSetName, namespace, err)
716+
return err
717+
}
718+
}
620719
return nil
621720
}
622721

722+
func needRestart(pod corev1.Pod, cmName string) bool {
723+
for _, volume := range pod.Spec.Volumes {
724+
if volume.ConfigMap != nil && volume.ConfigMap.Name == cmName {
725+
return true
726+
}
727+
}
728+
for _, container := range pod.Spec.Containers {
729+
for _, env := range container.Env {
730+
if env.ValueFrom != nil && env.ValueFrom.ConfigMapKeyRef != nil && env.ValueFrom.ConfigMapKeyRef.Name == cmName {
731+
return true
732+
}
733+
}
734+
}
735+
return false
736+
}
737+
623738
func (r *NamespaceScopeReconciler) setDefaults(instance *operatorv1.NamespaceScope) *operatorv1.NamespaceScope {
624739
if instance.Spec.ConfigmapName == "" {
625740
instance.Spec.ConfigmapName = constant.NamespaceScopeConfigmapName

0 commit comments

Comments
 (0)