Skip to content

Commit 649a05d

Browse files
authored
🐛 [mce-2.7] Only bind the agent role for the addon group (#157) (#734)
* Only bind the agent role for the addon group * Update addon rolebinding * Start an addon informor for each addon --------- Signed-off-by: zhujian <jiazhu@redhat.com>
1 parent 07092e0 commit 649a05d

File tree

7 files changed

+80
-45
lines changed

7 files changed

+80
-45
lines changed

manifests/cluster-manager/hub/cluster-manager-addon-manager-clusterrole.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,4 @@ rules:
6161
verbs: ["approve", "sign"]
6262
- apiGroups: ["rbac.authorization.k8s.io"]
6363
resources: ["rolebindings"]
64-
verbs: ["get", "list", "watch", "create", "delete"]
64+
verbs: ["get", "list", "watch", "create", "update", "delete"]

pkg/addon/controllers/addontemplate/controller.go

+33-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import (
1818

1919
"open-cluster-management.io/addon-framework/pkg/addonfactory"
2020
"open-cluster-management.io/addon-framework/pkg/addonmanager"
21+
"open-cluster-management.io/addon-framework/pkg/index"
2122
"open-cluster-management.io/addon-framework/pkg/utils"
22-
addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
2323
addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
2424
addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned"
2525
addoninformers "open-cluster-management.io/api/client/addon/informers/externalversions"
@@ -50,6 +50,7 @@ type addonTemplateController struct {
5050
dynamicInformers dynamicinformer.DynamicSharedInformerFactory
5151
workInformers workv1informers.SharedInformerFactory
5252
runControllerFunc runController
53+
eventRecorder events.Recorder
5354
}
5455

5556
type runController func(ctx context.Context, addonName string) error
@@ -78,6 +79,7 @@ func NewAddonTemplateController(
7879
clusterInformers: clusterInformers,
7980
dynamicInformers: dynamicInformers,
8081
workInformers: workInformers,
82+
eventRecorder: recorder,
8183
}
8284

8385
if len(runController) > 0 {
@@ -89,6 +91,11 @@ func NewAddonTemplateController(
8991
return factory.New().WithInformersQueueKeysFunc(
9092
queue.QueueKeyByMetaNamespaceName,
9193
addonInformers.Addon().V1alpha1().ClusterManagementAddOns().Informer()).
94+
WithBareInformers(
95+
// do not need to queue, just make sure the controller reconciles after the addonTemplate cache is synced
96+
// otherwise, there will be "xx-addon-template" not found" errors in the log as the controller uses the
97+
// addonTemplate lister to get the template object
98+
addonInformers.Addon().V1alpha1().AddOnTemplates().Informer()).
9299
WithSync(c.sync).
93100
ToController("addon-template-controller", recorder)
94101
}
@@ -186,16 +193,17 @@ func (c *addonTemplateController) runController(
186193
listOptions.LabelSelector = metav1.FormatLabelSelector(selector)
187194
}),
188195
)
189-
getValuesClosure := func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (addonfactory.Values, error) {
196+
getValuesClosure := func(cluster *clusterv1.ManagedCluster, addon *addonv1alpha1.ManagedClusterAddOn) (addonfactory.Values, error) {
190197
return templateagent.GetAddOnRegistriesPrivateValuesFromClusterAnnotation(klog.FromContext(ctx), cluster, addon)
191198
}
192199
agentAddon := templateagent.NewCRDTemplateAgentAddon(
193200
ctx,
194201
addonName,
195202
c.kubeClient,
196203
c.addonClient,
197-
c.addonInformers,
204+
c.addonInformers, // use the shared informers, whose cache is synced already
198205
kubeInformers.Rbac().V1().RoleBindings().Lister(),
206+
c.eventRecorder,
199207
// image overrides from cluster annotation has lower priority than from the addonDeploymentConfig
200208
getValuesClosure,
201209
addonfactory.GetAddOnDeploymentConfigValues(
@@ -211,13 +219,34 @@ func (c *addonTemplateController) runController(
211219
return err
212220
}
213221

222+
// not share the addon informers
223+
addonInformerFactory := addoninformers.NewSharedInformerFactory(c.addonClient, 10*time.Minute)
224+
err = addonInformerFactory.Addon().V1alpha1().ManagedClusterAddOns().Informer().AddIndexers(
225+
cache.Indexers{
226+
index.ManagedClusterAddonByNamespace: index.IndexManagedClusterAddonByNamespace, // agentDeployController
227+
index.AddonByConfig: index.IndexAddonByConfig, // addonConfigController
228+
},
229+
)
230+
if err != nil {
231+
return err
232+
}
233+
234+
// managementAddonConfigController
235+
err = addonInformerFactory.Addon().V1alpha1().ClusterManagementAddOns().Informer().AddIndexers(
236+
cache.Indexers{
237+
index.ClusterManagementAddonByConfig: index.IndexClusterManagementAddonByConfig, // cmaConfigController
238+
})
239+
if err != nil {
240+
return err
241+
}
214242
err = mgr.StartWithInformers(ctx, c.workClient, c.workInformers.Work().V1().ManifestWorks(),
215-
kubeInformers, c.addonInformers, c.clusterInformers, c.dynamicInformers)
243+
kubeInformers, addonInformerFactory, c.clusterInformers, c.dynamicInformers)
216244
if err != nil {
217245
return err
218246
}
219247

220248
kubeInformers.Start(ctx.Done())
249+
addonInformerFactory.Start(ctx.Done())
221250

222251
return nil
223252
}

pkg/addon/manager.go

+3-6
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func RunManager(ctx context.Context, controllerContext *controllercmd.Controller
5858
}
5959

6060
clusterInformerFactory := clusterinformers.NewSharedInformerFactory(hubClusterClient, 30*time.Minute)
61-
addonInformerFactory := addoninformers.NewSharedInformerFactory(addonClient, 30*time.Minute)
61+
addonInformerFactory := addoninformers.NewSharedInformerFactory(addonClient, 10*time.Minute)
6262
workInformers := workv1informers.NewSharedInformerFactoryWithOptions(workClient, 10*time.Minute,
6363
workv1informers.WithTweakListOptions(func(listOptions *metav1.ListOptions) {
6464
selector := &metav1.LabelSelector{
@@ -112,9 +112,7 @@ func RunControllerManagerWithInformers(
112112

113113
err = addonInformers.Addon().V1alpha1().ManagedClusterAddOns().Informer().AddIndexers(
114114
cache.Indexers{
115-
index.ManagedClusterAddonByNamespace: index.IndexManagedClusterAddonByNamespace, // addonDeployController
116-
index.ManagedClusterAddonByName: index.IndexManagedClusterAddonByName, // addonConfigController
117-
index.AddonByConfig: index.IndexAddonByConfig, // addonConfigController
115+
index.ManagedClusterAddonByName: index.IndexManagedClusterAddonByName, // addonConfigurationController, addonManagementController
118116
},
119117
)
120118
if err != nil {
@@ -124,8 +122,7 @@ func RunControllerManagerWithInformers(
124122
// managementAddonConfigController
125123
err = addonInformers.Addon().V1alpha1().ClusterManagementAddOns().Informer().AddIndexers(
126124
cache.Indexers{
127-
index.ClusterManagementAddonByConfig: index.IndexClusterManagementAddonByConfig,
128-
index.ClusterManagementAddonByPlacement: index.IndexClusterManagementAddonByPlacement,
125+
index.ClusterManagementAddonByPlacement: index.IndexClusterManagementAddonByPlacement, // addonConfigurationController, addonManagementController
129126
})
130127
if err != nil {
131128
return err

pkg/addon/templateagent/registration.go

+26-33
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import (
1010
"time"
1111

1212
openshiftcrypto "github.com/openshift/library-go/pkg/crypto"
13+
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
1314
"github.com/pkg/errors"
1415
certificatesv1 "k8s.io/api/certificates/v1"
1516
corev1 "k8s.io/api/core/v1"
1617
rbacv1 "k8s.io/api/rbac/v1"
17-
apierrors "k8s.io/apimachinery/pkg/api/errors"
1818
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1919
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2020
"k8s.io/client-go/kubernetes"
@@ -357,7 +357,7 @@ func (a *CRDTemplateAgentAddon) TemplatePermissionConfigFunc() agent.PermissionC
357357
continue
358358
}
359359

360-
err := a.createKubeClientPermissions(template.Name, kcrc, cluster, addon)
360+
err := a.createKubeClientPermissions(kcrc, cluster, addon)
361361
if err != nil {
362362
return err
363363
}
@@ -376,7 +376,6 @@ func (a *CRDTemplateAgentAddon) TemplatePermissionConfigFunc() agent.PermissionC
376376
}
377377

378378
func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
379-
templateName string,
380379
kcrc *addonapiv1alpha1.KubeClientRegistrationConfig,
381380
cluster *clusterv1.ManagedCluster,
382381
addon *addonapiv1alpha1.ManagedClusterAddOn,
@@ -409,8 +408,7 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
409408
APIGroup: rbacv1.GroupName,
410409
Name: pc.CurrentCluster.ClusterRoleName,
411410
}
412-
err := a.createPermissionBinding(templateName,
413-
cluster.Name, addon.Name, cluster.Name, roleRef, &owner)
411+
err := a.createPermissionBinding(cluster.Name, addon.Name, cluster.Name, roleRef, &owner)
414412
if err != nil {
415413
return err
416414
}
@@ -421,8 +419,8 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
421419

422420
// set owner reference nil since the rolebinding has different namespace with the ManagedClusterAddon
423421
// TODO: cleanup the rolebinding when the addon is deleted
424-
err := a.createPermissionBinding(templateName,
425-
cluster.Name, addon.Name, pc.SingleNamespace.Namespace, pc.SingleNamespace.RoleRef, nil)
422+
err := a.createPermissionBinding(cluster.Name, addon.Name,
423+
pc.SingleNamespace.Namespace, pc.SingleNamespace.RoleRef, nil)
426424
if err != nil {
427425
return err
428426
}
@@ -431,16 +429,9 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
431429
return nil
432430
}
433431

434-
func (a *CRDTemplateAgentAddon) createPermissionBinding(templateName, clusterName, addonName, namespace string,
432+
func (a *CRDTemplateAgentAddon) createPermissionBinding(clusterName, addonName, namespace string,
435433
roleRef rbacv1.RoleRef, owner *metav1.OwnerReference) error {
436-
// TODO: confirm the group
437-
groups := agent.DefaultGroups(clusterName, addonName)
438-
subject := []rbacv1.Subject{}
439-
for _, group := range groups {
440-
subject = append(subject, rbacv1.Subject{
441-
Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: group,
442-
})
443-
}
434+
444435
binding := &rbacv1.RoleBinding{
445436
ObjectMeta: metav1.ObjectMeta{
446437
Name: fmt.Sprintf("open-cluster-management:%s:%s:agent",
@@ -451,27 +442,29 @@ func (a *CRDTemplateAgentAddon) createPermissionBinding(templateName, clusterNam
451442
AddonTemplateLabelKey: "",
452443
},
453444
},
454-
RoleRef: roleRef,
455-
Subjects: subject,
445+
RoleRef: roleRef,
446+
Subjects: []rbacv1.Subject{
447+
{
448+
Kind: rbacv1.GroupKind,
449+
APIGroup: rbacv1.GroupName,
450+
Name: clusterAddonGroup(clusterName, addonName),
451+
},
452+
},
456453
}
457454
if owner != nil {
458455
binding.OwnerReferences = []metav1.OwnerReference{*owner}
459456
}
460-
_, err := a.rolebindingLister.RoleBindings(namespace).Get(binding.Name)
461-
switch {
462-
case err == nil:
463-
// TODO: update the rolebinding if it is not the same
464-
a.logger.Info("Rolebinding already exists", "rolebindingName", binding.Name)
465-
return nil
466-
case apierrors.IsNotFound(err):
467-
_, createErr := a.hubKubeClient.RbacV1().RoleBindings(namespace).Create(
468-
context.TODO(), binding, metav1.CreateOptions{})
469-
if createErr != nil && !apierrors.IsAlreadyExists(createErr) {
470-
return createErr
471-
}
472-
case err != nil:
473-
return err
457+
458+
_, modified, err := resourceapply.ApplyRoleBinding(context.TODO(),
459+
a.hubKubeClient.RbacV1(), a.eventRecorder, binding)
460+
if err == nil && modified {
461+
a.logger.Info("Rolebinding for addon updated", "namespace", binding.Namespace, "name", binding.Name,
462+
"clusterName", clusterName, "addonName", addonName)
474463
}
464+
return err
465+
}
475466

476-
return nil
467+
// clusterAddonGroup returns the group that represents the addon for the cluster
468+
func clusterAddonGroup(clusterName, addonName string) string {
469+
return fmt.Sprintf("system:open-cluster-management:cluster:%s:addon:%s", clusterName, addonName)
477470
}

pkg/addon/templateagent/registration_test.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"testing"
1010
"time"
1111

12+
"github.com/openshift/library-go/pkg/operator/events/eventstesting"
1213
"github.com/stretchr/testify/assert"
1314
certificatesv1 "k8s.io/api/certificates/v1"
1415
certificates "k8s.io/api/certificates/v1beta1"
@@ -586,6 +587,13 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
586587
if len(rb.OwnerReferences) != 0 {
587588
t.Errorf("expected rolebinding to have 0 owner reference, got %d", len(rb.OwnerReferences))
588589
}
590+
if len(rb.Subjects) != 1 {
591+
t.Errorf("expected rolebinding to have 1 subject, got %d", len(rb.Subjects))
592+
}
593+
if rb.Subjects[0].Name != "system:open-cluster-management:cluster:cluster1:addon:addon1" {
594+
t.Errorf("expected rolebinding subject name to be system:open-cluster-management:cluster:cluster1:addon:addon1, got %s",
595+
rb.Subjects[0].Name)
596+
}
589597
},
590598
},
591599
{
@@ -640,7 +648,7 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
640648
}
641649

642650
agent := NewCRDTemplateAgentAddon(ctx, c.addon.Name, hubKubeClient, addonClient, addonInformerFactory,
643-
kubeInformers.Rbac().V1().RoleBindings().Lister(), nil)
651+
kubeInformers.Rbac().V1().RoleBindings().Lister(), eventstesting.NewTestingEventRecorder(t))
644652
f := agent.TemplatePermissionConfigFunc()
645653
err := f(c.cluster, c.addon)
646654
if err != c.expectedErr {

pkg/addon/templateagent/template_agent.go

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66

7+
"github.com/openshift/library-go/pkg/operator/events"
78
"github.com/valyala/fasttemplate"
89
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
910
"k8s.io/apimachinery/pkg/runtime"
@@ -61,6 +62,7 @@ type CRDTemplateAgentAddon struct {
6162
rolebindingLister rbacv1lister.RoleBindingLister
6263
addonName string
6364
agentName string
65+
eventRecorder events.Recorder
6466
}
6567

6668
// NewCRDTemplateAgentAddon creates a CRDTemplateAgentAddon instance
@@ -71,6 +73,7 @@ func NewCRDTemplateAgentAddon(
7173
addonClient addonv1alpha1client.Interface,
7274
addonInformers addoninformers.SharedInformerFactory,
7375
rolebindingLister rbacv1lister.RoleBindingLister,
76+
recorder events.Recorder,
7477
getValuesFuncs ...addonfactory.GetValuesFunc,
7578
) *CRDTemplateAgentAddon {
7679

@@ -87,6 +90,7 @@ func NewCRDTemplateAgentAddon(
8790
rolebindingLister: rolebindingLister,
8891
addonName: addonName,
8992
agentName: fmt.Sprintf("%s-agent", addonName),
93+
eventRecorder: recorder,
9094
}
9195

9296
return a

pkg/addon/templateagent/template_agent_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77
"time"
88

9+
"github.com/openshift/library-go/pkg/operator/events/eventstesting"
910
"github.com/stretchr/testify/assert"
1011
corev1 "k8s.io/api/core/v1"
1112
rbacv1 "k8s.io/api/rbac/v1"
@@ -518,6 +519,7 @@ func TestAddonTemplateAgentManifests(t *testing.T) {
518519
addonClient,
519520
addonInformerFactory,
520521
kubeInformers.Rbac().V1().RoleBindings().Lister(),
522+
eventstesting.NewTestingEventRecorder(t),
521523
addonfactory.GetAddOnDeploymentConfigValues(
522524
utils.NewAddOnDeploymentConfigGetter(addonClient),
523525
addonfactory.ToAddOnCustomizedVariableValues,
@@ -744,6 +746,7 @@ func TestAgentInstallNamespace(t *testing.T) {
744746
addonClient,
745747
addonInformerFactory,
746748
kubeInformers.Rbac().V1().RoleBindings().Lister(),
749+
eventstesting.NewTestingEventRecorder(t),
747750
addonfactory.GetAddOnDeploymentConfigValues(
748751
utils.NewAddOnDeploymentConfigGetter(addonClient),
749752
addonfactory.ToAddOnCustomizedVariableValues,
@@ -913,6 +916,7 @@ func TestAgentManifestConfigs(t *testing.T) {
913916
addonClient,
914917
addonInformerFactory,
915918
kubeInformers.Rbac().V1().RoleBindings().Lister(),
919+
eventstesting.NewTestingEventRecorder(t),
916920
addonfactory.GetAddOnDeploymentConfigValues(
917921
utils.NewAddOnDeploymentConfigGetter(addonClient),
918922
addonfactory.ToAddOnCustomizedVariableValues,

0 commit comments

Comments
 (0)