Skip to content

Commit 4c87ff7

Browse files
authored
multiple CRs managing the same configmap (#31)
1 parent af1dcb1 commit 4c87ff7

File tree

4 files changed

+91
-31
lines changed

4 files changed

+91
-31
lines changed

controllers/common/util.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package common
1818

1919
import (
20+
"sort"
21+
2022
gset "github.com/deckarep/golang-set"
2123
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2224
"k8s.io/apimachinery/pkg/types"
@@ -48,6 +50,20 @@ func GetListDifference(slice1 []string, slice2 []string) []string {
4850
return diff
4951
}
5052

53+
func CheckListDifference(slice1 []string, slice2 []string) bool {
54+
if len(slice1) != len(slice2) {
55+
return true
56+
}
57+
sort.Strings(slice1)
58+
sort.Strings(slice2)
59+
for i, v := range slice1 {
60+
if v != slice2[i] {
61+
return true
62+
}
63+
}
64+
return false
65+
}
66+
5167
func GetOwnerReferenceUIDs(ownerRefs []metav1.OwnerReference) []types.UID {
5268
var ownerRefUIDs []types.UID
5369
for _, ref := range ownerRefs {

controllers/constant/constants.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ const (
2222
NamespaceScopeConfigmapName = "namespace-scope"
2323
NamespaceScopeFinalizer = "finalizer.nss.operator.ibm.com"
2424
NamespaceScopeLabel = "managedby-namespace-scope"
25+
DefaultRestartLabelsKey = "intent"
26+
DefaultRestartLabelsValue = "projected"
2527
)

controllers/namespacescope_controller.go

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package controllers
1818

1919
import (
2020
"context"
21-
"fmt"
2221
"strings"
2322
"time"
2423

@@ -66,6 +65,10 @@ func (r *NamespaceScopeReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
6665
return ctrl.Result{}, err
6766
}
6867

68+
if err := r.UpdateConfigMap(instance); err != nil {
69+
return ctrl.Result{}, err
70+
}
71+
6972
// Remove NamespaceScopeFinalizer. Once all finalizers have been
7073
// removed, the object will be deleted.
7174
controllerutil.RemoveFinalizer(instance, constant.NamespaceScopeFinalizer)
@@ -129,9 +132,13 @@ func (r *NamespaceScopeReconciler) InitConfigMap(instance *operatorv1.NamespaceS
129132
cm.Namespace = cmNamespace
130133
cm.Labels = map[string]string{constant.NamespaceScopeLabel: "true"}
131134
cm.Data = make(map[string]string)
132-
cm.Data["namespaces"] = strings.Join(instance.Spec.NamespaceMembers, ",")
135+
nsMembers, err := r.getNamespaceList(instance)
136+
if err != nil {
137+
return err
138+
}
139+
cm.Data["namespaces"] = strings.Join(nsMembers, ",")
133140
// Set NamespaceScope instance as the owner of the ConfigMap.
134-
if err := controllerutil.SetControllerReference(instance, cm, r.Scheme); err != nil {
141+
if err := controllerutil.SetOwnerReference(instance, cm, r.Scheme); err != nil {
135142
klog.Errorf("Failed to set owner reference for ConfigMap %s/%s: %v", cmNamespace, cmName, err)
136143
return err
137144
}
@@ -145,21 +152,6 @@ func (r *NamespaceScopeReconciler) InitConfigMap(instance *operatorv1.NamespaceS
145152
return err
146153
}
147154

148-
ownerRefUIDs := util.GetOwnerReferenceUIDs(cm.GetOwnerReferences())
149-
if len(ownerRefUIDs) != 0 {
150-
// ConfigMap OwnerReference UIDs don't contain current NamespaceScope instance UID, means this
151-
// ConfigMap belong to another NamespaceScope instance, stop reconcile.
152-
if !util.UIDContains(ownerRefUIDs, instance.UID) {
153-
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "ConfigMap Name Conflict", "ConfigMap %s/%s has belong to another NamesapceScope instance, you need to change to a new configmapName", cmNamespace, cmName)
154-
klog.Errorf("configMap %s/%s has belong to another NamesapceScope instance, you need to change to a new configmapName", cmNamespace, cmName)
155-
return fmt.Errorf("configMap %s/%s has belong to another NamesapceScope instance, you need to change to a new configmapName", cmNamespace, cmName)
156-
}
157-
} else {
158-
r.Recorder.Eventf(instance, corev1.EventTypeWarning, "No OwnerReference", "ConfigMap %s/%s has no owner reference, you need to change to a new configmapName", cmNamespace, cmName)
159-
klog.Errorf("configMap %s/%s has no owner reference, you need to change to a new configmapName", cmNamespace, cmName)
160-
return fmt.Errorf("configMap %s/%s has no owner reference, you need to change to a new configmapName", cmNamespace, cmName)
161-
}
162-
163155
return nil
164156
}
165157

@@ -175,16 +167,35 @@ func (r *NamespaceScopeReconciler) UpdateConfigMap(instance *operatorv1.Namespac
175167
}
176168

177169
// If NamespaceMembers changed, update ConfigMap
178-
if strings.Join(instance.Spec.NamespaceMembers, ",") != cm.Data["namespaces"] {
179-
cm.Data["namespaces"] = strings.Join(instance.Spec.NamespaceMembers, ",")
170+
nsMembers, err := r.getNamespaceList(instance)
171+
if err != nil {
172+
return err
173+
}
174+
175+
// Get owner uids
176+
ownerRefUIDs := util.GetOwnerReferenceUIDs(cm.GetOwnerReferences())
177+
178+
if util.CheckListDifference(nsMembers, strings.Split(cm.Data["namespaces"], ",")) || !util.UIDContains(ownerRefUIDs, instance.UID) {
179+
restartpod := util.CheckListDifference(nsMembers, strings.Split(cm.Data["namespaces"], ","))
180+
if restartpod {
181+
cm.Data["namespaces"] = strings.Join(nsMembers, ",")
182+
}
183+
184+
if err := controllerutil.SetOwnerReference(instance, cm, r.Scheme); err != nil {
185+
klog.Errorf("Failed to set owner reference for ConfigMap %s/%s: %v", cm.Namespace, cm.Name, err)
186+
return err
187+
}
188+
180189
if err := r.Update(ctx, cm); err != nil {
181190
klog.Errorf("Failed to update ConfigMap %s : %v", cmKey.String(), err)
182191
return err
183192
}
184193

185194
// When the configmap updated, restart all the pods with the RestartLabels
186-
if err := r.RestartPods(instance.Spec.RestartLabels, instance.Namespace); err != nil {
187-
return err
195+
if restartpod {
196+
if err := r.RestartPods(instance.Spec.RestartLabels, instance.Namespace); err != nil {
197+
return err
198+
}
188199
}
189200
}
190201
return nil
@@ -197,7 +208,7 @@ func (r *NamespaceScopeReconciler) PushRbacToNamespace(instance *operatorv1.Name
197208
return err
198209
}
199210
labels := map[string]string{
200-
"projectedfrom": instance.Namespace + "-" + instance.Name,
211+
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
201212
}
202213

203214
for _, toNs := range instance.Spec.NamespaceMembers {
@@ -229,10 +240,13 @@ func (r *NamespaceScopeReconciler) DeleteRbacFromUnmanagedNamespace(instance *op
229240
if cm.Data["namespaces"] != "" {
230241
nsInCm = strings.Split(cm.Data["namespaces"], ",")
231242
}
232-
nsInCr := instance.Spec.NamespaceMembers
243+
nsInCr, err := r.getNamespaceList(instance)
244+
if err != nil {
245+
return err
246+
}
233247
unmanagedNss := util.GetListDifference(nsInCm, nsInCr)
234248
labels := map[string]string{
235-
"projectedfrom": instance.Namespace + "-" + instance.Name,
249+
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
236250
}
237251
for _, toNs := range unmanagedNss {
238252
if err := r.DeleteRoleBinding(labels, toNs); err != nil {
@@ -255,8 +269,9 @@ func (r *NamespaceScopeReconciler) DeleteRbacFromUnmanagedNamespace(instance *op
255269

256270
// When delete NamespaceScope instance, cleanup all RBAC resources
257271
func (r *NamespaceScopeReconciler) DeleteAllRbac(instance *operatorv1.NamespaceScope) error {
272+
instance = setDefaults(instance)
258273
labels := map[string]string{
259-
"projectedfrom": instance.Namespace + "-" + instance.Name,
274+
"namespace-scope-configmap": instance.Namespace + "-" + instance.Spec.ConfigmapName,
260275
}
261276
for _, toNs := range instance.Spec.NamespaceMembers {
262277
if err := r.DeleteRoleBinding(labels, toNs); err != nil {
@@ -303,7 +318,7 @@ func (r *NamespaceScopeReconciler) GetServiceAccountFromNamespace(labels map[str
303318
}
304319

305320
func (r *NamespaceScopeReconciler) CreateRole(labels map[string]string, toNs string) error {
306-
name := constant.NamespaceScopeManagedRoleName + labels["projectedfrom"]
321+
name := constant.NamespaceScopeManagedRoleName + labels["namespace-scope-configmap"]
307322
namespace := toNs
308323
role := &rbacv1.Role{
309324
ObjectMeta: metav1.ObjectMeta{
@@ -344,7 +359,7 @@ func (r *NamespaceScopeReconciler) DeleteRole(labels map[string]string, toNs str
344359
}
345360

346361
func (r *NamespaceScopeReconciler) CreateUpdateRoleBinding(labels map[string]string, saNames []string, fromNs, toNs string) error {
347-
name := constant.NamespaceScopeManagedRoleBindingName + labels["projectedfrom"]
362+
name := constant.NamespaceScopeManagedRoleBindingName + labels["namespace-scope-configmap"]
348363
namespace := toNs
349364
subjects := []rbacv1.Subject{}
350365
for _, saName := range saNames {
@@ -364,7 +379,7 @@ func (r *NamespaceScopeReconciler) CreateUpdateRoleBinding(labels map[string]str
364379
Subjects: subjects,
365380
RoleRef: rbacv1.RoleRef{
366381
Kind: "Role",
367-
Name: constant.NamespaceScopeManagedRoleName + labels["projectedfrom"],
382+
Name: constant.NamespaceScopeManagedRoleName + labels["namespace-scope-configmap"],
368383
APIGroup: "rbac.authorization.k8s.io",
369384
},
370385
}
@@ -431,10 +446,37 @@ func setDefaults(instance *operatorv1.NamespaceScope) *operatorv1.NamespaceScope
431446
if instance.Spec.ConfigmapName == "" {
432447
instance.Spec.ConfigmapName = constant.NamespaceScopeConfigmapName
433448
}
449+
if len(instance.Spec.RestartLabels) == 0 {
450+
instance.Spec.RestartLabels = map[string]string{
451+
constant.DefaultRestartLabelsKey: constant.DefaultRestartLabelsValue,
452+
}
453+
}
434454

435455
return instance
436456
}
437457

458+
func (r *NamespaceScopeReconciler) getNamespaceList(instance *operatorv1.NamespaceScope) ([]string, error) {
459+
// List the instance using the same configmap
460+
crList := &operatorv1.NamespaceScopeList{}
461+
namespaceMembersList := util.MakeSet([]string{})
462+
if err := r.List(ctx, crList, &client.ListOptions{Namespace: instance.Namespace}); err != nil {
463+
klog.Errorf("Cannot list namespacescope with in namespace %s: %v", instance.Namespace, err)
464+
return nil, err
465+
}
466+
for _, cr := range crList.Items {
467+
cr := setDefaults(&cr)
468+
if !cr.GetDeletionTimestamp().IsZero() {
469+
continue
470+
}
471+
if instance.Spec.ConfigmapName == cr.Spec.ConfigmapName {
472+
for _, ns := range cr.Spec.NamespaceMembers {
473+
namespaceMembersList.Add(ns)
474+
}
475+
}
476+
}
477+
return util.ToStringSlice(namespaceMembersList), nil
478+
}
479+
438480
func (r *NamespaceScopeReconciler) SetupWithManager(mgr ctrl.Manager) error {
439481
return ctrl.NewControllerManagedBy(mgr).
440482
Owns(&corev1.ConfigMap{}).

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ func main() {
6161

6262
gvkLabelMap := map[schema.GroupVersionKind]cache.Selector{
6363
corev1.SchemeGroupVersion.WithKind("ConfigMap"): {LabelSelector: "managedby-namespace-scope"},
64-
rbacv1.SchemeGroupVersion.WithKind("Role"): {LabelSelector: "projectedfrom"},
65-
rbacv1.SchemeGroupVersion.WithKind("RoleBinding"): {LabelSelector: "projectedfrom"},
64+
rbacv1.SchemeGroupVersion.WithKind("Role"): {LabelSelector: "namespace-scope-configmap"},
65+
rbacv1.SchemeGroupVersion.WithKind("RoleBinding"): {LabelSelector: "namespace-scope-configmap"},
6666
}
6767

6868
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{

0 commit comments

Comments
 (0)