Skip to content

Commit

Permalink
Add a func to filter managed cluster when deploying agent
Browse files Browse the repository at this point in the history
Signed-off-by: zhujian <jiazhu@redhat.com>
  • Loading branch information
zhujian7 committed Aug 1, 2023
1 parent df88188 commit 03db4ac
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 35 deletions.
5 changes: 5 additions & 0 deletions cmd/example/helloworld_helm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/runtime/schema"
utilrand "k8s.io/apimachinery/pkg/util/rand"
"k8s.io/client-go/kubernetes"
Expand All @@ -18,6 +19,7 @@ import (
logs "k8s.io/component-base/logs/api/v1"
"k8s.io/klog/v2"
addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned"
clusterv1 "open-cluster-management.io/api/cluster/v1"

"open-cluster-management.io/addon-framework/examples/helloworld"
"open-cluster-management.io/addon-framework/examples/helloworld_agent"
Expand Down Expand Up @@ -105,6 +107,9 @@ func runController(ctx context.Context, kubeConfig *rest.Config) error {
schema.GroupVersionResource{Version: "v1", Resource: "configmaps"},
utils.AddOnDeploymentConfigGVR,
).
WithAgentDeployClusterTriggerFilter(func(old, new *clusterv1.ManagedCluster) bool {
return !equality.Semantic.DeepEqual(old.Annotations, new.Annotations)
}).
WithGetValuesFuncs(
helloworld_helm.GetDefaultValues,
addonfactory.GetAddOnDeploymentConfigValues(
Expand Down
18 changes: 18 additions & 0 deletions pkg/addonfactory/addonfactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,24 @@ func (f *AgentAddonFactory) WithHostingCluster(cluster *clusterv1.ManagedCluster
return f
}

// WithAgentDeployClusterTriggerFilter defines the filter function for the cluster informer when deploying the addon
// agent. Addons that need information from the ManagedCluster resource when deploying the agent should use this
// function to set what information they need, otherwise the expected/up-to-date agent may be deployed delayed since the
// default filter func returns false when the ManagedCluster resource is updated.
//
// For example, the agentAddon needs information from the ManagedCluster annotation, it can set the filter function
// like:
//
// WithAgentDeployClusterTriggerFilter(func(old, new *clusterv1.ManagedCluster) bool {
// return !equality.Semantic.DeepEqual(old.Annotations, new.Annotations)
// })
func (f *AgentAddonFactory) WithAgentDeployClusterTriggerFilter(
filter func(old, new *clusterv1.ManagedCluster) bool,
) *AgentAddonFactory {
f.agentAddonOptions.AgentDeployClusterInformerFilter = filter
return f
}

// BuildHelmAgentAddon builds a helm agentAddon instance.
func (f *AgentAddonFactory) BuildHelmAgentAddon() (agent.AgentAddon, error) {
if err := validateSupportedConfigGVRs(f.agentAddonOptions.SupportedConfigGVRs); err != nil {
Expand Down
91 changes: 56 additions & 35 deletions pkg/addonmanager/controllers/agentdeploy/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,42 +78,21 @@ func NewAddonDeployController(
agentAddons: agentAddons,
}

_, err := clusterInformers.Informer().AddEventHandler(
cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {},
UpdateFunc: func(oldObj, newObj interface{}) {
oldCluster, ook := oldObj.(*clusterv1.ManagedCluster)
newCluster, nok := newObj.(*clusterv1.ManagedCluster)
if !ook || !nok {
return
f := factory.New().WithSyncContext(syncCtx).
WithFilteredEventsInformersQueueKeysFunc(
func(obj runtime.Object) []string {
key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
return []string{key}
},
func(obj interface{}) bool {
accessor, _ := meta.Accessor(obj)
if _, ok := c.agentAddons[accessor.GetName()]; !ok {
return false
}

// Only enqueue addons if the cluster annotation is changed.
if !equality.Semantic.DeepEqual(oldCluster.Annotations, newCluster.Annotations) {
c.enqueueAddOnsByCluster()(newObj)
}
return true
},
DeleteFunc: func(obj interface{}) {},
},
)
if err != nil {
utilruntime.HandleError(err)
}

return factory.New().WithFilteredEventsInformersQueueKeysFunc(
func(obj runtime.Object) []string {
key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
return []string{key}
},
func(obj interface{}) bool {
accessor, _ := meta.Accessor(obj)
if _, ok := c.agentAddons[accessor.GetName()]; !ok {
return false
}

return true
},
addonInformers.Informer()).
addonInformers.Informer()).
WithFilteredEventsInformersQueueKeysFunc(
func(obj runtime.Object) []string {
accessor, _ := meta.Accessor(obj)
Expand Down Expand Up @@ -149,10 +128,51 @@ func NewAddonDeployController(
},
workInformers.Informer(),
).
WithBareInformers(clusterInformers.Informer()).
WithSync(c.sync).ToController(controllerName)
WithSync(c.sync)

if c.watchManagedCluster(clusterInformers) {
f.WithBareInformers(clusterInformers.Informer())
}
return f.ToController(controllerName)
}

func (c addonDeployController) watchManagedCluster(clusterInformers clusterinformers.ManagedClusterInformer) bool {
var filters []func(old, new *clusterv1.ManagedCluster) bool
for _, addon := range c.agentAddons {
if addon.GetAgentAddonOptions().AgentDeployClusterInformerFilter != nil {
filters = append(filters, addon.GetAgentAddonOptions().AgentDeployClusterInformerFilter)
}
}
if len(filters) == 0 {
return false
}

_, err := clusterInformers.Informer().AddEventHandler(
cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {},
UpdateFunc: func(oldObj, newObj interface{}) {
oldCluster, ook := oldObj.(*clusterv1.ManagedCluster)
newCluster, nok := newObj.(*clusterv1.ManagedCluster)
if !ook || !nok {
return
}

// enqueue the addon if one of cluster filters is matched.
for _, filter := range filters {
if filter(oldCluster, newCluster) {
c.enqueueAddOnsByCluster()(newObj)
break
}
}
},
DeleteFunc: func(obj interface{}) {},
},
)
if err != nil {
utilruntime.HandleError(err)
}
return true
}
func (c *addonDeployController) enqueueAddOnsByCluster() func(obj interface{}) {
return func(obj interface{}) {
accessor, _ := meta.Accessor(obj)
Expand Down Expand Up @@ -196,6 +216,7 @@ func (c *addonDeployController) getWorksByAddonFn(index string) func(addonName,
}

func (c *addonDeployController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error {
klog.V(4).Infof("%s sync addon key %s", controllerName, key)
clusterName, addonName, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
// ignore addon whose key is not in format: namespace/name
Expand Down
13 changes: 13 additions & 0 deletions pkg/agent/inteface.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ type AgentAddonOptions struct {
// SupportedConfigGVRs is a list of addon supported configuration GroupVersionResource
// each configuration GroupVersionResource should be unique
SupportedConfigGVRs []schema.GroupVersionResource

// AgentDeployClusterInformerFilter defines the filter function for the cluster informer when deploying the addon
// agent. Addons that need information from the ManagedCluster resource when deploying the agent should use this
// field to set what information they need, otherwise the expected/up-to-date agent may be deployed delayed since
// the default filter func returns false when the ManagedCluster resource is updated.
//
// For example, the agentAddon needs information from the ManagedCluster annotation, it can set the filter function
// like:
//
// AgentDeployClusterInformerFilter: func(old, new *clusterv1.ManagedCluster) bool {
// return !equality.Semantic.DeepEqual(old.Annotations, new.Annotations)
// }
AgentDeployClusterInformerFilter func(old, new *clusterv1.ManagedCluster) bool
}

type CSRSignerFunc func(csr *certificatesv1.CertificateSigningRequest) []byte
Expand Down

0 comments on commit 03db4ac

Please sign in to comment.