Skip to content

Commit

Permalink
🐛 [mce-2.7] Only bind the agent role for the addon group (open-cluste…
Browse files Browse the repository at this point in the history
…r-management-io#157) (open-cluster-management-io#167)

* 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>
  • Loading branch information
zhujian7 authored Dec 3, 2024
1 parent a79ab03 commit 959fbff
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ rules:
verbs: ["approve", "sign"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["get", "list", "watch", "create", "delete"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
37 changes: 33 additions & 4 deletions pkg/addon/controllers/addontemplate/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

"open-cluster-management.io/addon-framework/pkg/addonfactory"
"open-cluster-management.io/addon-framework/pkg/addonmanager"
addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
"open-cluster-management.io/addon-framework/pkg/index"
addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned"
addoninformers "open-cluster-management.io/api/client/addon/informers/externalversions"
Expand Down Expand Up @@ -48,6 +48,7 @@ type addonTemplateController struct {
dynamicInformers dynamicinformer.DynamicSharedInformerFactory
workInformers workv1informers.SharedInformerFactory
runControllerFunc runController
eventRecorder events.Recorder
}

type runController func(ctx context.Context, addonName string) error
Expand All @@ -74,6 +75,7 @@ func NewAddonTemplateController(
clusterInformers: clusterInformers,
dynamicInformers: dynamicInformers,
workInformers: workInformers,
eventRecorder: recorder,
}

if len(runController) > 0 {
Expand All @@ -85,6 +87,11 @@ func NewAddonTemplateController(
return factory.New().WithInformersQueueKeysFunc(
queue.QueueKeyByMetaNamespaceName,
addonInformers.Addon().V1alpha1().ClusterManagementAddOns().Informer()).
WithBareInformers(
// do not need to queue, just make sure the controller reconciles after the addonTemplate cache is synced
// otherwise, there will be "xx-addon-template" not found" errors in the log as the controller uses the
// addonTemplate lister to get the template object
addonInformers.Addon().V1alpha1().AddOnTemplates().Informer()).
WithSync(c.sync).
ToController("addon-template-controller", recorder)
}
Expand Down Expand Up @@ -182,7 +189,7 @@ func (c *addonTemplateController) runController(
listOptions.LabelSelector = metav1.FormatLabelSelector(selector)
}),
)
getValuesClosure := func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (addonfactory.Values, error) {
getValuesClosure := func(cluster *clusterv1.ManagedCluster, addon *addonv1alpha1.ManagedClusterAddOn) (addonfactory.Values, error) {
return templateagent.GetAddOnRegistriesPrivateValuesFromClusterAnnotation(klog.FromContext(ctx), cluster, addon)
}
agentAddon := templateagent.NewCRDTemplateAgentAddon(
Expand All @@ -192,8 +199,9 @@ func (c *addonTemplateController) runController(
utilrand.String(5),
c.kubeClient,
c.addonClient,
c.addonInformers,
c.addonInformers, // use the shared informers, whose cache is synced already
kubeInformers.Rbac().V1().RoleBindings().Lister(),
c.eventRecorder,
// image overrides from cluster annotation has lower priority than from the addonDeploymentConfig
getValuesClosure,
addonfactory.GetAddOnDeploymentConfigValues(
Expand All @@ -208,12 +216,33 @@ func (c *addonTemplateController) runController(
return err
}

err = mgr.StartWithInformers(ctx, kubeInformers, c.workInformers, c.addonInformers, c.clusterInformers, c.dynamicInformers)
// not share the addon informers
addonInformerFactory := addoninformers.NewSharedInformerFactory(c.addonClient, 10*time.Minute)
err = addonInformerFactory.Addon().V1alpha1().ManagedClusterAddOns().Informer().AddIndexers(
cache.Indexers{
index.ManagedClusterAddonByNamespace: index.IndexManagedClusterAddonByNamespace, // agentDeployController
index.AddonByConfig: index.IndexAddonByConfig, // addonConfigController
},
)
if err != nil {
return err
}

// managementAddonConfigController
err = addonInformerFactory.Addon().V1alpha1().ClusterManagementAddOns().Informer().AddIndexers(
cache.Indexers{
index.ClusterManagementAddonByConfig: index.IndexClusterManagementAddonByConfig, // cmaConfigController
})
if err != nil {
return err
}
err = mgr.StartWithInformers(ctx, kubeInformers, c.workInformers, addonInformerFactory, c.clusterInformers, c.dynamicInformers)
if err != nil {
return err
}

kubeInformers.Start(ctx.Done())
addonInformerFactory.Start(ctx.Done())

return nil
}
9 changes: 3 additions & 6 deletions pkg/addon/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func RunManager(ctx context.Context, controllerContext *controllercmd.Controller
}

clusterInformerFactory := clusterinformers.NewSharedInformerFactory(hubClusterClient, 30*time.Minute)
addonInformerFactory := addoninformers.NewSharedInformerFactory(addonClient, 30*time.Minute)
addonInformerFactory := addoninformers.NewSharedInformerFactory(addonClient, 10*time.Minute)
workInformers := workv1informers.NewSharedInformerFactoryWithOptions(workClient, 10*time.Minute,
workv1informers.WithTweakListOptions(func(listOptions *metav1.ListOptions) {
selector := &metav1.LabelSelector{
Expand Down Expand Up @@ -109,9 +109,7 @@ func RunControllerManagerWithInformers(

err = addonInformers.Addon().V1alpha1().ManagedClusterAddOns().Informer().AddIndexers(
cache.Indexers{
index.ManagedClusterAddonByNamespace: index.IndexManagedClusterAddonByNamespace, // addonDeployController
index.ManagedClusterAddonByName: index.IndexManagedClusterAddonByName, // addonConfigController
index.AddonByConfig: index.IndexAddonByConfig, // addonConfigController
index.ManagedClusterAddonByName: index.IndexManagedClusterAddonByName, // addonConfigurationController, addonManagementController
},
)
if err != nil {
Expand All @@ -121,8 +119,7 @@ func RunControllerManagerWithInformers(
// managementAddonConfigController
err = addonInformers.Addon().V1alpha1().ClusterManagementAddOns().Informer().AddIndexers(
cache.Indexers{
index.ClusterManagementAddonByConfig: index.IndexClusterManagementAddonByConfig,
index.ClusterManagementAddonByPlacement: index.IndexClusterManagementAddonByPlacement,
index.ClusterManagementAddonByPlacement: index.IndexClusterManagementAddonByPlacement, // addonConfigurationController, addonManagementController
})
if err != nil {
return err
Expand Down
59 changes: 26 additions & 33 deletions pkg/addon/templateagent/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
"time"

openshiftcrypto "github.com/openshift/library-go/pkg/crypto"
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
"github.com/pkg/errors"
certificatesv1 "k8s.io/api/certificates/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -353,7 +353,7 @@ func (a *CRDTemplateAgentAddon) TemplatePermissionConfigFunc() agent.PermissionC
continue
}

err := a.createKubeClientPermissions(template.Name, kcrc, cluster, addon)
err := a.createKubeClientPermissions(kcrc, cluster, addon)
if err != nil {
return err
}
Expand All @@ -372,7 +372,6 @@ func (a *CRDTemplateAgentAddon) TemplatePermissionConfigFunc() agent.PermissionC
}

func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
templateName string,
kcrc *addonapiv1alpha1.KubeClientRegistrationConfig,
cluster *clusterv1.ManagedCluster,
addon *addonapiv1alpha1.ManagedClusterAddOn,
Expand Down Expand Up @@ -405,8 +404,7 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
APIGroup: rbacv1.GroupName,
Name: pc.CurrentCluster.ClusterRoleName,
}
err := a.createPermissionBinding(templateName,
cluster.Name, addon.Name, cluster.Name, roleRef, &owner)
err := a.createPermissionBinding(cluster.Name, addon.Name, cluster.Name, roleRef, &owner)
if err != nil {
return err
}
Expand All @@ -417,8 +415,8 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(

// set owner reference nil since the rolebinding has different namespace with the ManagedClusterAddon
// TODO: cleanup the rolebinding when the addon is deleted
err := a.createPermissionBinding(templateName,
cluster.Name, addon.Name, pc.SingleNamespace.Namespace, pc.SingleNamespace.RoleRef, nil)
err := a.createPermissionBinding(cluster.Name, addon.Name,
pc.SingleNamespace.Namespace, pc.SingleNamespace.RoleRef, nil)
if err != nil {
return err
}
Expand All @@ -427,16 +425,9 @@ func (a *CRDTemplateAgentAddon) createKubeClientPermissions(
return nil
}

func (a *CRDTemplateAgentAddon) createPermissionBinding(templateName, clusterName, addonName, namespace string,
func (a *CRDTemplateAgentAddon) createPermissionBinding(clusterName, addonName, namespace string,
roleRef rbacv1.RoleRef, owner *metav1.OwnerReference) error {
// TODO: confirm the group
groups := agent.DefaultGroups(clusterName, addonName)
subject := []rbacv1.Subject{}
for _, group := range groups {
subject = append(subject, rbacv1.Subject{
Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: group,
})
}

binding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("open-cluster-management:%s:%s:agent",
Expand All @@ -447,27 +438,29 @@ func (a *CRDTemplateAgentAddon) createPermissionBinding(templateName, clusterNam
AddonTemplateLabelKey: "",
},
},
RoleRef: roleRef,
Subjects: subject,
RoleRef: roleRef,
Subjects: []rbacv1.Subject{
{
Kind: rbacv1.GroupKind,
APIGroup: rbacv1.GroupName,
Name: clusterAddonGroup(clusterName, addonName),
},
},
}
if owner != nil {
binding.OwnerReferences = []metav1.OwnerReference{*owner}
}
_, err := a.rolebindingLister.RoleBindings(namespace).Get(binding.Name)
switch {
case err == nil:
// TODO: update the rolebinding if it is not the same
a.logger.Info("Rolebinding already exists", "rolebindingName", binding.Name)
return nil
case apierrors.IsNotFound(err):
_, createErr := a.hubKubeClient.RbacV1().RoleBindings(namespace).Create(
context.TODO(), binding, metav1.CreateOptions{})
if createErr != nil && !apierrors.IsAlreadyExists(createErr) {
return createErr
}
case err != nil:
return err

_, modified, err := resourceapply.ApplyRoleBinding(context.TODO(),
a.hubKubeClient.RbacV1(), a.eventRecorder, binding)
if err == nil && modified {
a.logger.Info("Rolebinding for addon updated", "namespace", binding.Namespace, "name", binding.Name,
"clusterName", clusterName, "addonName", addonName)
}
return err
}

return nil
// clusterAddonGroup returns the group that represents the addon for the cluster
func clusterAddonGroup(clusterName, addonName string) string {
return fmt.Sprintf("system:open-cluster-management:cluster:%s:addon:%s", clusterName, addonName)
}
10 changes: 9 additions & 1 deletion pkg/addon/templateagent/registration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"
"time"

"github.com/openshift/library-go/pkg/operator/events/eventstesting"
"github.com/stretchr/testify/assert"
certificatesv1 "k8s.io/api/certificates/v1"
certificates "k8s.io/api/certificates/v1beta1"
Expand Down Expand Up @@ -601,6 +602,13 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
if len(rb.OwnerReferences) != 0 {
t.Errorf("expected rolebinding to have 0 owner reference, got %d", len(rb.OwnerReferences))
}
if len(rb.Subjects) != 1 {
t.Errorf("expected rolebinding to have 1 subject, got %d", len(rb.Subjects))
}
if rb.Subjects[0].Name != "system:open-cluster-management:cluster:cluster1:addon:addon1" {
t.Errorf("expected rolebinding subject name to be system:open-cluster-management:cluster:cluster1:addon:addon1, got %s",
rb.Subjects[0].Name)
}
},
},
{
Expand Down Expand Up @@ -656,7 +664,7 @@ func TestTemplatePermissionConfigFunc(t *testing.T) {
}

agent := NewCRDTemplateAgentAddon(ctx, c.addon.Name, c.agentName, hubKubeClient, addonClient, addonInformerFactory,
kubeInformers.Rbac().V1().RoleBindings().Lister(), nil)
kubeInformers.Rbac().V1().RoleBindings().Lister(), eventstesting.NewTestingEventRecorder(t))
f := agent.TemplatePermissionConfigFunc()
err := f(c.cluster, c.addon)
if err != c.expectedErr {
Expand Down
4 changes: 4 additions & 0 deletions pkg/addon/templateagent/template_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/openshift/library-go/pkg/operator/events"
"github.com/valyala/fasttemplate"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -59,6 +60,7 @@ type CRDTemplateAgentAddon struct {
rolebindingLister rbacv1lister.RoleBindingLister
addonName string
agentName string
eventRecorder events.Recorder
}

// NewCRDTemplateAgentAddon creates a CRDTemplateAgentAddon instance
Expand All @@ -69,6 +71,7 @@ func NewCRDTemplateAgentAddon(
addonClient addonv1alpha1client.Interface,
addonInformers addoninformers.SharedInformerFactory,
rolebindingLister rbacv1lister.RoleBindingLister,
recorder events.Recorder,
getValuesFuncs ...addonfactory.GetValuesFunc,
) *CRDTemplateAgentAddon {

Expand All @@ -85,6 +88,7 @@ func NewCRDTemplateAgentAddon(
rolebindingLister: rolebindingLister,
addonName: addonName,
agentName: agentName,
eventRecorder: recorder,
}

return a
Expand Down
4 changes: 4 additions & 0 deletions pkg/addon/templateagent/template_agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

"github.com/openshift/library-go/pkg/operator/events/eventstesting"
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -258,6 +259,7 @@ func TestAddonTemplateAgentManifests(t *testing.T) {
addonClient,
addonInformerFactory,
kubeInformers.Rbac().V1().RoleBindings().Lister(),
eventstesting.NewTestingEventRecorder(t),
addonfactory.GetAddOnDeploymentConfigValues(
addonfactory.NewAddOnDeploymentConfigGetter(addonClient),
addonfactory.ToAddOnCustomizedVariableValues,
Expand Down Expand Up @@ -374,6 +376,7 @@ func TestAgentInstallNamespace(t *testing.T) {
addonClient,
addonInformerFactory,
kubeInformers.Rbac().V1().RoleBindings().Lister(),
eventstesting.NewTestingEventRecorder(t),
addonfactory.GetAddOnDeploymentConfigValues(
addonfactory.NewAddOnDeploymentConfigGetter(addonClient),
addonfactory.ToAddOnCustomizedVariableValues,
Expand Down Expand Up @@ -538,6 +541,7 @@ func TestAgentManifestConfigs(t *testing.T) {
addonClient,
addonInformerFactory,
kubeInformers.Rbac().V1().RoleBindings().Lister(),
eventstesting.NewTestingEventRecorder(t),
addonfactory.GetAddOnDeploymentConfigValues(
addonfactory.NewAddOnDeploymentConfigGetter(addonClient),
addonfactory.ToAddOnCustomizedVariableValues,
Expand Down

0 comments on commit 959fbff

Please sign in to comment.