diff --git a/go.mod b/go.mod index 0beb09310..49e0b8ae2 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module open-cluster-management.io/ocm go 1.21 +replace open-cluster-management.io/addon-framework => github.com/haoqing0110/addon-framework v0.2.1-0.20240314095719-7caafd5cf2fc + require ( github.com/cloudevents/sdk-go/v2 v2.14.0 github.com/davecgh/go-spew v1.1.1 diff --git a/go.sum b/go.sum index 3871bd86c..cb58aa3ad 100644 --- a/go.sum +++ b/go.sum @@ -129,6 +129,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/haoqing0110/addon-framework v0.2.1-0.20240314095719-7caafd5cf2fc h1:4Qy2cC2yFC+oQZMrTLhR/2F2lRb+DRRCvSh9veIhoDM= +github.com/haoqing0110/addon-framework v0.2.1-0.20240314095719-7caafd5cf2fc/go.mod h1:nQMHHshMfMNj4qdwg/4oMqRf42FQU6EYy68o2HsLgn4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -423,8 +425,6 @@ k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/A k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -open-cluster-management.io/addon-framework v0.9.1-0.20240311065811-974d3377ecbd h1:wKAzvMuzSuaheaLw6iiDx7sl5vsPiGm8+ZvZEHrPIDU= -open-cluster-management.io/addon-framework v0.9.1-0.20240311065811-974d3377ecbd/go.mod h1:ZZvGRA/zmIjIww0reatmOxcXy0Eoghnat/Opszgo2NA= open-cluster-management.io/api v0.13.0 h1:dlcJEZlNlE0DmSDctK2s7iWKg9l+Tgb0V78Z040nMuk= open-cluster-management.io/api v0.13.0/go.mod h1:CuCPEzXDvOyxBB0H1d1eSeajbHqaeGEKq9c63vQc63w= open-cluster-management.io/sdk-go v0.13.1-0.20240312062935-0163292c290b h1:pqW+eqzQmnpgZdZid6EeH/+Mkz9ei5ko+ubb3guEWQE= diff --git a/manifests/cluster-manager/hub/cluster-manager-addon-manager-clusterrole.yaml b/manifests/cluster-manager/hub/cluster-manager-addon-manager-clusterrole.yaml index e26254a94..49dbcd51c 100644 --- a/manifests/cluster-manager/hub/cluster-manager-addon-manager-clusterrole.yaml +++ b/manifests/cluster-manager/hub/cluster-manager-addon-manager-clusterrole.yaml @@ -35,7 +35,7 @@ rules: verbs: ["update", "patch"] - apiGroups: ["addon.open-cluster-management.io"] resources: ["clustermanagementaddons"] - verbs: ["get", "list", "watch"] + verbs: ["patch", "get", "list", "watch"] - apiGroups: ["addon.open-cluster-management.io"] resources: ["managedclusteraddons"] verbs: ["get", "list", "watch", "create", "update", "delete"] diff --git a/pkg/addon/controllers/managementaddon/controller.go b/pkg/addon/controllers/managementaddon/controller.go index 0b5668379..788eb9ecc 100644 --- a/pkg/addon/controllers/managementaddon/controller.go +++ b/pkg/addon/controllers/managementaddon/controller.go @@ -3,17 +3,18 @@ package managementaddon import ( "context" + "github.com/openshift/library-go/pkg/controller/factory" + "github.com/openshift/library-go/pkg/operator/events" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/klog/v2" + addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - "open-cluster-management.io/ocm/pkg/common/queue" "open-cluster-management.io/sdk-go/pkg/patcher" - "github.com/openshift/library-go/pkg/controller/factory" - "github.com/openshift/library-go/pkg/operator/events" + "open-cluster-management.io/ocm/pkg/common/queue" ) // clusterManagementAddonController reconciles cma on the hub. diff --git a/pkg/addon/controllers/managementaddon/controller_test.go b/pkg/addon/controllers/managementaddon/controller_test.go index d556ad092..536e51c92 100644 --- a/pkg/addon/controllers/managementaddon/controller_test.go +++ b/pkg/addon/controllers/managementaddon/controller_test.go @@ -8,12 +8,14 @@ import ( "k8s.io/apimachinery/pkg/runtime" clienttesting "k8s.io/client-go/testing" + "open-cluster-management.io/addon-framework/pkg/addonmanager/addontesting" "open-cluster-management.io/addon-framework/pkg/agent" addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" fakeaddon "open-cluster-management.io/api/client/addon/clientset/versioned/fake" addoninformers "open-cluster-management.io/api/client/addon/informers/externalversions" clusterv1 "open-cluster-management.io/api/cluster/v1" + testingcommon "open-cluster-management.io/ocm/pkg/common/testing" ) diff --git a/pkg/addon/templateagent/template_agent.go b/pkg/addon/templateagent/template_agent.go index f0d151eb9..46acd92ba 100644 --- a/pkg/addon/templateagent/template_agent.go +++ b/pkg/addon/templateagent/template_agent.go @@ -113,7 +113,6 @@ func (a *CRDTemplateAgentAddon) GetAgentAddonOptions() agent.AgentAddonOptions { agentAddonOptions := agent.AgentAddonOptions{ AddonName: a.addonName, - // InstallStrategy: nil, HealthProber: &agent.HealthProber{ Type: agent.HealthProberTypeDeploymentAvailability, }, diff --git a/test/integration/addon/addon_configs_test.go b/test/integration/addon/addon_configs_test.go index c81bab77a..83a9bb8af 100644 --- a/test/integration/addon/addon_configs_test.go +++ b/test/integration/addon/addon_configs_test.go @@ -132,9 +132,6 @@ var _ = ginkgo.Describe("AddConfigs", func() { cma, err := hubAddonClient.AddonV1alpha1().ClusterManagementAddOns().Get(context.Background(), testAddOnConfigsImpl.name, metav1.GetOptions{}) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - // cma.Annotations = map[string]string{ - // addonapiv1alpha1.AddonLifecycleAnnotationKey: addonapiv1alpha1.AddonLifecycleAddonManagerAnnotationValue, - // } cma.Spec.InstallStrategy = addonapiv1alpha1.InstallStrategy{ Type: addonapiv1alpha1.AddonInstallStrategyPlacements, Placements: []addonapiv1alpha1.PlacementStrategy{ diff --git a/test/integration/addon/addon_manager_install_test.go b/test/integration/addon/addon_manager_install_test.go index 235e8f81e..3efa7ab99 100644 --- a/test/integration/addon/addon_manager_install_test.go +++ b/test/integration/addon/addon_manager_install_test.go @@ -28,9 +28,6 @@ var _ = ginkgo.Describe("Agent deploy", func() { cma = &addonapiv1alpha1.ClusterManagementAddOn{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("test-%s", suffix), - // Annotations: map[string]string{ - // addonapiv1alpha1.AddonLifecycleAnnotationKey: addonapiv1alpha1.AddonLifecycleAddonManagerAnnotationValue, - // }, }, Spec: addonapiv1alpha1.ClusterManagementAddOnSpec{ InstallStrategy: addonapiv1alpha1.InstallStrategy{ diff --git a/test/integration/addon/addon_manager_upgrade_test.go b/test/integration/addon/addon_manager_upgrade_test.go index 13c735a7c..1064e3674 100644 --- a/test/integration/addon/addon_manager_upgrade_test.go +++ b/test/integration/addon/addon_manager_upgrade_test.go @@ -86,9 +86,6 @@ var _ = ginkgo.Describe("Addon upgrade", func() { cma = &addonapiv1alpha1.ClusterManagementAddOn{ ObjectMeta: metav1.ObjectMeta{ Name: testAddOnConfigsImpl.name, - // Annotations: map[string]string{ - // addonapiv1alpha1.AddonLifecycleAnnotationKey: addonapiv1alpha1.AddonLifecycleAddonManagerAnnotationValue, - // }, }, Spec: addonapiv1alpha1.ClusterManagementAddOnSpec{ InstallStrategy: addonapiv1alpha1.InstallStrategy{ diff --git a/test/integration/addon/agent_deploy_test.go b/test/integration/addon/agent_deploy_test.go index 092b7cbe9..44809eeaf 100644 --- a/test/integration/addon/agent_deploy_test.go +++ b/test/integration/addon/agent_deploy_test.go @@ -113,13 +113,6 @@ var _ = ginkgo.Describe("Agent deploy", func() { Type: agent.HealthProberTypeWork, } - // Update clustermanagement addon annotattion - // cma, err := hubAddonClient.AddonV1alpha1().ClusterManagementAddOns().Get(context.Background(), testAddonImpl.name, metav1.GetOptions{}) - // gomega.Expect(err).ToNot(gomega.HaveOccurred()) - // cma.SetAnnotations(map[string]string{addonapiv1alpha1.AddonLifecycleAnnotationKey: addonapiv1alpha1.AddonLifecycleAddonManagerAnnotationValue}) - // _, err = hubAddonClient.AddonV1alpha1().ClusterManagementAddOns().Update(context.Background(), cma, metav1.UpdateOptions{}) - // gomega.Expect(err).ToNot(gomega.HaveOccurred()) - // Create ManagedClusterAddOn addon := &addonapiv1alpha1.ManagedClusterAddOn{ ObjectMeta: metav1.ObjectMeta{ diff --git a/test/integration/addon/assertion_test.go b/test/integration/addon/assertion_test.go index 900fe674d..5a0c01fe0 100644 --- a/test/integration/addon/assertion_test.go +++ b/test/integration/addon/assertion_test.go @@ -72,9 +72,6 @@ func createClusterManagementAddOn(name, defaultConfigNamespace, defaultConfigNam &addonapiv1alpha1.ClusterManagementAddOn{ ObjectMeta: metav1.ObjectMeta{ Name: name, - // Annotations: map[string]string{ - // addonapiv1alpha1.AddonLifecycleAnnotationKey: addonapiv1alpha1.AddonLifecycleAddonManagerAnnotationValue, - // }, }, Spec: addonapiv1alpha1.ClusterManagementAddOnSpec{ SupportedConfigs: []addonapiv1alpha1.ConfigMeta{ diff --git a/test/integration/addon/suite_test.go b/test/integration/addon/suite_test.go index 0560916fe..efaaf7edd 100644 --- a/test/integration/addon/suite_test.go +++ b/test/integration/addon/suite_test.go @@ -127,13 +127,12 @@ var _ = ginkgo.AfterSuite(func() { }) type testAddon struct { - name string - manifests map[string][]runtime.Object - registrations map[string][]addonapiv1alpha1.RegistrationConfig - approveCSR bool - cert []byte - prober *agent.HealthProber - // installStrategy *agent.InstallStrategy + name string + manifests map[string][]runtime.Object + registrations map[string][]addonapiv1alpha1.RegistrationConfig + approveCSR bool + cert []byte + prober *agent.HealthProber hostedModeEnabled bool supportedConfigGVRs []schema.GroupVersionResource } @@ -144,9 +143,8 @@ func (t *testAddon) Manifests(cluster *clusterv1.ManagedCluster, addon *addonapi func (t *testAddon) GetAgentAddonOptions() agent.AgentAddonOptions { option := agent.AgentAddonOptions{ - AddonName: t.name, - HealthProber: t.prober, - // InstallStrategy: t.installStrategy, + AddonName: t.name, + HealthProber: t.prober, HostedModeEnabled: t.hostedModeEnabled, SupportedConfigGVRs: t.supportedConfigGVRs, } diff --git a/vendor/modules.txt b/vendor/modules.txt index 20da9d8c5..83aa538a1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1485,17 +1485,15 @@ k8s.io/utils/pointer k8s.io/utils/ptr k8s.io/utils/strings/slices k8s.io/utils/trace -# open-cluster-management.io/addon-framework v0.9.1-0.20240311065811-974d3377ecbd +# open-cluster-management.io/addon-framework v0.9.1-0.20240311065811-974d3377ecbd => github.com/haoqing0110/addon-framework v0.2.1-0.20240314095719-7caafd5cf2fc ## explicit; go 1.21 open-cluster-management.io/addon-framework/pkg/addonfactory open-cluster-management.io/addon-framework/pkg/addonmanager open-cluster-management.io/addon-framework/pkg/addonmanager/addontesting open-cluster-management.io/addon-framework/pkg/addonmanager/constants open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addonconfig -open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate -open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddonconfig open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration open-cluster-management.io/addon-framework/pkg/agent @@ -1503,8 +1501,6 @@ open-cluster-management.io/addon-framework/pkg/assets open-cluster-management.io/addon-framework/pkg/basecontroller/events open-cluster-management.io/addon-framework/pkg/basecontroller/factory open-cluster-management.io/addon-framework/pkg/index -open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration -open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner open-cluster-management.io/addon-framework/pkg/utils # open-cluster-management.io/api v0.13.0 ## explicit; go 1.21 @@ -1686,3 +1682,4 @@ sigs.k8s.io/structured-merge-diff/v4/value ## explicit; go 1.12 sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 +# open-cluster-management.io/addon-framework => github.com/haoqing0110/addon-framework v0.2.1-0.20240314095719-7caafd5cf2fc diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go index 91e8df4e1..32caa9ba8 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go @@ -53,7 +53,6 @@ func NewAgentAddonFactory(addonName string, fs embed.FS, dir string) *AgentAddon agentAddonOptions: agent.AgentAddonOptions{ AddonName: addonName, Registration: nil, - InstallStrategy: nil, HealthProber: nil, SupportedConfigGVRs: []schema.GroupVersionResource{}, }, @@ -78,19 +77,6 @@ func (f *AgentAddonFactory) WithGetValuesFuncs(getValuesFuncs ...GetValuesFunc) return f } -// WithInstallStrategy defines the installation strategy of the manifests prescribed by Manifests(..). -// Deprecated: add annotation "addon.open-cluster-management.io/lifecycle: addon-manager" to ClusterManagementAddon -// and define install strategy in ClusterManagementAddon spec.installStrategy instead. -// The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. -func (f *AgentAddonFactory) WithInstallStrategy(strategy *agent.InstallStrategy) *AgentAddonFactory { - if strategy.InstallNamespace == "" { - strategy.InstallNamespace = AddonDefaultInstallNamespace - } - f.agentAddonOptions.InstallStrategy = strategy - - return f -} - // WithAgentRegistrationOption defines how agent is registered to the hub cluster. func (f *AgentAddonFactory) WithAgentRegistrationOption(option *agent.RegistrationOption) *AgentAddonFactory { f.agentAddonOptions.Registration = option diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall/controller.go deleted file mode 100644 index 4c57759e7..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall/controller.go +++ /dev/null @@ -1,138 +0,0 @@ -package addoninstall - -import ( - "context" - "strings" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - errorsutil "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/klog/v2" - addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" - addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" - addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - clusterinformers "open-cluster-management.io/api/client/cluster/informers/externalversions/cluster/v1" - clusterlister "open-cluster-management.io/api/client/cluster/listers/cluster/v1" - - "open-cluster-management.io/addon-framework/pkg/agent" - "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" -) - -// managedClusterController reconciles instances of ManagedCluster on the hub. -type addonInstallController struct { - addonClient addonv1alpha1client.Interface - managedClusterLister clusterlister.ManagedClusterLister - managedClusterAddonLister addonlisterv1alpha1.ManagedClusterAddOnLister - agentAddons map[string]agent.AgentAddon -} - -func NewAddonInstallController( - addonClient addonv1alpha1client.Interface, - clusterInformers clusterinformers.ManagedClusterInformer, - addonInformers addoninformerv1alpha1.ManagedClusterAddOnInformer, - agentAddons map[string]agent.AgentAddon, -) factory.Controller { - c := &addonInstallController{ - addonClient: addonClient, - managedClusterLister: clusterInformers.Lister(), - managedClusterAddonLister: addonInformers.Lister(), - agentAddons: agentAddons, - } - - return factory.New().WithFilteredEventsInformersQueueKeysFunc( - func(obj runtime.Object) []string { - accessor, _ := meta.Accessor(obj) - return []string{accessor.GetNamespace()} - }, - func(obj interface{}) bool { - accessor, _ := meta.Accessor(obj) - if _, ok := c.agentAddons[accessor.GetName()]; !ok { - return false - } - - return true - }, - addonInformers.Informer()). - WithInformersQueueKeysFunc( - func(obj runtime.Object) []string { - accessor, _ := meta.Accessor(obj) - return []string{accessor.GetName()} - }, - clusterInformers.Informer(), - ). - WithSync(c.sync).ToController("addon-install-controller") -} - -func (c *addonInstallController) sync(ctx context.Context, syncCtx factory.SyncContext, clusterName string) error { - klog.V(4).Infof("Reconciling addon deploy on cluster %q", clusterName) - - cluster, err := c.managedClusterLister.Get(clusterName) - if errors.IsNotFound(err) { - return nil - } - if err != nil { - return err - } - - // if cluster is deleting, do not install addon - if !cluster.DeletionTimestamp.IsZero() { - klog.V(4).Infof("Cluster %q is deleting, skip addon deploy", clusterName) - return nil - } - - if value, ok := cluster.Annotations[addonapiv1alpha1.DisableAddonAutomaticInstallationAnnotationKey]; ok && - strings.EqualFold(value, "true") { - - klog.V(4).Infof("Cluster %q has annotation %q, skip addon deploy", - clusterName, addonapiv1alpha1.DisableAddonAutomaticInstallationAnnotationKey) - return nil - } - - var errs []error - - for addonName, addon := range c.agentAddons { - if addon.GetAgentAddonOptions().InstallStrategy == nil { - continue - } - - managedClusterFilter := addon.GetAgentAddonOptions().InstallStrategy.GetManagedClusterFilter() - if managedClusterFilter == nil { - continue - } - if !managedClusterFilter(cluster) { - klog.V(4).Infof("managed cluster filter is not match for addon %s on %s", addonName, clusterName) - continue - } - - err = c.applyAddon(ctx, addonName, clusterName, addon.GetAgentAddonOptions().InstallStrategy.InstallNamespace) - if err != nil { - errs = append(errs, err) - } - } - - return errorsutil.NewAggregate(errs) -} - -func (c *addonInstallController) applyAddon(ctx context.Context, addonName, clusterName, installNamespace string) error { - _, err := c.managedClusterAddonLister.ManagedClusterAddOns(clusterName).Get(addonName) - - // only create addon when it is missing, if user update the addon resource ,it should not be reverted - if errors.IsNotFound(err) { - addon := &addonapiv1alpha1.ManagedClusterAddOn{ - ObjectMeta: metav1.ObjectMeta{ - Name: addonName, - Namespace: clusterName, - }, - Spec: addonapiv1alpha1.ManagedClusterAddOnSpec{ - InstallNamespace: installNamespace, - }, - } - _, err = c.addonClient.AddonV1alpha1().ManagedClusterAddOns(clusterName).Create(ctx, addon, metav1.CreateOptions{}) - return err - } - - return err -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon/controller.go deleted file mode 100644 index 47ef7b862..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon/controller.go +++ /dev/null @@ -1,95 +0,0 @@ -package managementaddon - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" - addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" - addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - "open-cluster-management.io/sdk-go/pkg/patcher" - - "open-cluster-management.io/addon-framework/pkg/agent" - "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" -) - -const ( - controllerName = "management-addon-controller" -) - -// clusterManagementAddonController reconciles cma on the hub. -type clusterManagementAddonController struct { - addonClient addonv1alpha1client.Interface - clusterManagementAddonLister addonlisterv1alpha1.ClusterManagementAddOnLister - agentAddons map[string]agent.AgentAddon - addonFilterFunc factory.EventFilterFunc - addonPatcher patcher.Patcher[*addonapiv1alpha1.ClusterManagementAddOn, - addonapiv1alpha1.ClusterManagementAddOnSpec, - addonapiv1alpha1.ClusterManagementAddOnStatus] -} - -func NewManagementAddonController( - addonClient addonv1alpha1client.Interface, - clusterManagementAddonInformers addoninformerv1alpha1.ClusterManagementAddOnInformer, - agentAddons map[string]agent.AgentAddon, - addonFilterFunc factory.EventFilterFunc, -) factory.Controller { - syncCtx := factory.NewSyncContext(controllerName) - - c := &clusterManagementAddonController{ - addonClient: addonClient, - clusterManagementAddonLister: clusterManagementAddonInformers.Lister(), - agentAddons: agentAddons, - addonFilterFunc: addonFilterFunc, - addonPatcher: patcher.NewPatcher[*addonapiv1alpha1.ClusterManagementAddOn, - addonapiv1alpha1.ClusterManagementAddOnSpec, - addonapiv1alpha1.ClusterManagementAddOnStatus](addonClient.AddonV1alpha1().ClusterManagementAddOns()), - } - - return factory.New(). - WithSyncContext(syncCtx). - WithFilteredEventsInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - c.addonFilterFunc, clusterManagementAddonInformers.Informer()). - WithSync(c.sync).ToController(controllerName) -} - -func (c *clusterManagementAddonController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { - _, addonName, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - // ignore addon whose key is invalid - return nil - } - - cma, err := c.clusterManagementAddonLister.Get(addonName) - if errors.IsNotFound(err) { - // addon cloud be deleted, ignore - return nil - } - if err != nil { - return err - } - - addon := c.agentAddons[cma.GetName()] - if addon.GetAgentAddonOptions().InstallStrategy == nil { - return nil - } - - // If the addon defines install strategy via WithInstallStrategy(), force add annotation "addon.open-cluster-management.io/lifecycle: self" to cma. - // The annotation with value "self" will be removed when remove WithInstallStrategy() in addon-framework. - // The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. - cmaCopy := cma.DeepCopy() - if cmaCopy.Annotations == nil { - cmaCopy.Annotations = map[string]string{} - } - cmaCopy.Annotations[addonapiv1alpha1.AddonLifecycleAnnotationKey] = addonapiv1alpha1.AddonLifecycleSelfManageAnnotationValue - - _, err = c.addonPatcher.PatchLabelAnnotations(ctx, cmaCopy, cmaCopy.ObjectMeta, cma.ObjectMeta) - return err -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go index b2f3575e5..a6a121d2e 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go @@ -22,17 +22,13 @@ import ( workv1informers "open-cluster-management.io/api/client/work/informers/externalversions" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addonconfig" - "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate" - "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddonconfig" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration" "open-cluster-management.io/addon-framework/pkg/agent" "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" "open-cluster-management.io/addon-framework/pkg/index" - "open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration" - "open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner" "open-cluster-management.io/addon-framework/pkg/utils" ) @@ -241,33 +237,7 @@ func (a *addonManager) StartWithInformers(ctx context.Context, a.addonAgents, ) - addonInstallController := addoninstall.NewAddonInstallController( - addonClient, - clusterInformers.Cluster().V1().ManagedClusters(), - addonInformers.Addon().V1alpha1().ManagedClusterAddOns(), - a.addonAgents, - ) - - // This controller is used during migrating addons to be managed by addon-manager. - // This should be removed when the migration is done. - // The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. - managementAddonController := managementaddon.NewManagementAddonController( - addonClient, - addonInformers.Addon().V1alpha1().ClusterManagementAddOns(), - a.addonAgents, - utils.FilterByAddonName(a.addonAgents), - ) - - // This is a duplicate controller in general addon-manager. This should be removed when we - // alway enable the addon-manager - addonOwnerController := addonowner.NewAddonOwnerController( - addonClient, - addonInformers.Addon().V1alpha1().ManagedClusterAddOns(), - addonInformers.Addon().V1alpha1().ClusterManagementAddOns(), - utils.ManagedBySelf(a.addonAgents), - ) - - var addonConfigController, managementAddonConfigController, addonConfigurationController factory.Controller + var addonConfigController, managementAddonConfigController factory.Controller if len(a.addonConfigs) != 0 { addonConfigController = addonconfig.NewAddonConfigController( addonClient, @@ -284,17 +254,6 @@ func (a *addonManager) StartWithInformers(ctx context.Context, a.addonConfigs, utils.FilterByAddonName(a.addonAgents), ) - - // start addonConfiguration controller, note this is to handle the case when the general addon-manager - // is not started, we should consider to remove this when the general addon-manager are always started. - // This controller will also ignore the installStrategy part. - addonConfigurationController = addonconfiguration.NewAddonConfigurationController( - addonClient, - addonInformers.Addon().V1alpha1().ManagedClusterAddOns(), - addonInformers.Addon().V1alpha1().ClusterManagementAddOns(), - nil, nil, - utils.ManagedBySelf(a.addonAgents), - ) } var csrApproveController factory.Controller @@ -334,19 +293,13 @@ func (a *addonManager) StartWithInformers(ctx context.Context, go deployController.Run(ctx, 1) go registrationController.Run(ctx, 1) - go addonInstallController.Run(ctx, 1) - go managementAddonController.Run(ctx, 1) - go addonOwnerController.Run(ctx, 1) if addonConfigController != nil { go addonConfigController.Run(ctx, 1) } if managementAddonConfigController != nil { go managementAddonConfigController.Run(ctx, 1) } - if addonConfigurationController != nil { - go addonConfigurationController.Run(ctx, 1) - } if csrApproveController != nil { go csrApproveController.Run(ctx, 1) } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go b/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go index 1dd5d7b00..3229237b0 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go @@ -4,11 +4,8 @@ import ( "fmt" certificatesv1 "k8s.io/api/certificates/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/klog/v2" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" clusterv1 "open-cluster-management.io/api/cluster/v1" workapiv1 "open-cluster-management.io/api/work/v1" @@ -49,14 +46,6 @@ type AgentAddonOptions struct { // +optional Registration *RegistrationOption - // InstallStrategy defines that addon should be created in which clusters. - // Addon will not be installed automatically until a ManagedClusterAddon is applied to the cluster's - // namespace if InstallStrategy is nil. - // Deprecated: use installStrategy config in ClusterManagementAddOn API instead - // The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. - // +optional - InstallStrategy *InstallStrategy - // Updaters select a set of resources and define the strategies to update them. // UpdateStrategy is Update if no Updater is defined for a resource. // +optional @@ -157,23 +146,6 @@ type RegistrationOption struct { CSRSign CSRSignerFunc } -// InstallStrategy is the installation strategy of the manifests prescribed by Manifests(..). -type InstallStrategy struct { - *installStrategy -} - -type installStrategy struct { - // InstallNamespace is target deploying namespace in the managed cluster upon automatic addon installation. - InstallNamespace string - - // managedClusterFilter will filter the clusters to install the addon to. - managedClusterFilter func(cluster *clusterv1.ManagedCluster) bool -} - -func (s *InstallStrategy) GetManagedClusterFilter() func(cluster *clusterv1.ManagedCluster) bool { - return s.managedClusterFilter -} - type Updater struct { // ResourceIdentifier sets what resources the strategy applies to ResourceIdentifier workapiv1.ResourceIdentifier @@ -258,54 +230,6 @@ func DefaultGroups(clusterName, addonName string) []string { } } -// InstallAllStrategy indicate to install addon to all clusters -func InstallAllStrategy(installNamespace string) *InstallStrategy { - return &InstallStrategy{ - &installStrategy{ - InstallNamespace: installNamespace, - managedClusterFilter: func(cluster *clusterv1.ManagedCluster) bool { - return true - }, - }, - } -} - -// InstallByLabelStrategy indicate to install addon based on clusters' label -func InstallByLabelStrategy(installNamespace string, selector metav1.LabelSelector) *InstallStrategy { - return &InstallStrategy{ - &installStrategy{ - InstallNamespace: installNamespace, - managedClusterFilter: func(cluster *clusterv1.ManagedCluster) bool { - selector, err := metav1.LabelSelectorAsSelector(&selector) - if err != nil { - klog.Warningf("labels selector is not correct: %v", err) - return false - } - - if !selector.Matches(labels.Set(cluster.Labels)) { - return false - } - return true - }, - }, - } -} - -// InstallByFilterFunctionStrategy indicate to install addon based on a filter function, and it will also install addons if the filter function is nil. -func InstallByFilterFunctionStrategy(installNamespace string, f func(cluster *clusterv1.ManagedCluster) bool) *InstallStrategy { - if f == nil { - f = func(cluster *clusterv1.ManagedCluster) bool { - return true - } - } - return &InstallStrategy{ - &installStrategy{ - InstallNamespace: installNamespace, - managedClusterFilter: f, - }, - } -} - // ApprovalAllCSRs returns true for all csrs. func ApprovalAllCSRs(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn, csr *certificatesv1.CertificateSigningRequest) bool { return true diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/addon_configuration_reconciler.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/addon_configuration_reconciler.go deleted file mode 100644 index 5e38bfde4..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/addon_configuration_reconciler.go +++ /dev/null @@ -1,114 +0,0 @@ -package addonconfiguration - -import ( - "context" - "encoding/json" - "fmt" - - jsonpatch "github.com/evanphx/json-patch" - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/klog/v2" - - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" -) - -type managedClusterAddonConfigurationReconciler struct { - addonClient addonv1alpha1client.Interface -} - -func (d *managedClusterAddonConfigurationReconciler) reconcile( - ctx context.Context, cma *addonv1alpha1.ClusterManagementAddOn, graph *configurationGraph) (*addonv1alpha1.ClusterManagementAddOn, reconcileState, error) { - var errs []error - - for _, addon := range graph.getAddonsToUpdate() { - mca := d.mergeAddonConfig(addon.mca, addon.desiredConfigs) - err := d.patchAddonStatus(ctx, mca, addon.mca) - if err != nil { - errs = append(errs, err) - } - } - - return cma, reconcileContinue, utilerrors.NewAggregate(errs) -} - -func (d *managedClusterAddonConfigurationReconciler) mergeAddonConfig( - mca *addonv1alpha1.ManagedClusterAddOn, desiredConfigMap addonConfigMap) *addonv1alpha1.ManagedClusterAddOn { - mcaCopy := mca.DeepCopy() - - var mergedConfigs []addonv1alpha1.ConfigReference - // remove configs that are not desired - for _, config := range mcaCopy.Status.ConfigReferences { - if _, ok := desiredConfigMap[config.ConfigGroupResource]; ok { - mergedConfigs = append(mergedConfigs, config) - } - } - - // append or update configs - for _, config := range desiredConfigMap { - var match bool - for i := range mergedConfigs { - if mergedConfigs[i].ConfigGroupResource != config.ConfigGroupResource { - continue - } - - match = true - // set LastObservedGeneration to 0 when config name/namespace changes - if mergedConfigs[i].DesiredConfig != nil && (mergedConfigs[i].DesiredConfig.ConfigReferent != config.DesiredConfig.ConfigReferent) { - mergedConfigs[i].LastObservedGeneration = 0 - } - mergedConfigs[i].ConfigReferent = config.ConfigReferent - mergedConfigs[i].DesiredConfig = config.DesiredConfig.DeepCopy() - } - - if !match { - mergedConfigs = append(mergedConfigs, config) - } - } - - mcaCopy.Status.ConfigReferences = mergedConfigs - return mcaCopy -} - -func (d *managedClusterAddonConfigurationReconciler) patchAddonStatus(ctx context.Context, new, old *addonv1alpha1.ManagedClusterAddOn) error { - if equality.Semantic.DeepEqual(new.Status, old.Status) { - return nil - } - - oldData, err := json.Marshal(&addonv1alpha1.ManagedClusterAddOn{ - Status: addonv1alpha1.ManagedClusterAddOnStatus{ - Namespace: old.Status.Namespace, - ConfigReferences: old.Status.ConfigReferences, - }, - }) - if err != nil { - return err - } - - newData, err := json.Marshal(&addonv1alpha1.ManagedClusterAddOn{ - ObjectMeta: metav1.ObjectMeta{ - UID: new.UID, - ResourceVersion: new.ResourceVersion, - }, - Status: addonv1alpha1.ManagedClusterAddOnStatus{ - Namespace: new.Status.Namespace, - ConfigReferences: new.Status.ConfigReferences, - }, - }) - if err != nil { - return err - } - - patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) - if err != nil { - return fmt.Errorf("failed to create patch for addon %s: %w", new.Name, err) - } - - klog.V(2).Infof("Patching addon %s/%s status with %s", new.Namespace, new.Name, string(patchBytes)) - _, err = d.addonClient.AddonV1alpha1().ManagedClusterAddOns(new.Namespace).Patch( - ctx, new.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}, "status") - return err -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/controller.go deleted file mode 100644 index a51c304c9..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/controller.go +++ /dev/null @@ -1,196 +0,0 @@ -package addonconfiguration - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/client-go/tools/cache" - "k8s.io/klog/v2" - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" - addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" - addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - clusterinformersv1beta1 "open-cluster-management.io/api/client/cluster/informers/externalversions/cluster/v1beta1" - clusterlister "open-cluster-management.io/api/client/cluster/listers/cluster/v1beta1" - clusterlisterv1beta1 "open-cluster-management.io/api/client/cluster/listers/cluster/v1beta1" - clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1" - - "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" - "open-cluster-management.io/addon-framework/pkg/index" -) - -// addonConfigurationController is a controller to update configuration of mca with the following order -// 1. use configuration in mca spec if it is set -// 2. use configuration in install strategy -// 3. use configuration in the default configuration in cma -type addonConfigurationController struct { - addonClient addonv1alpha1client.Interface - clusterManagementAddonLister addonlisterv1alpha1.ClusterManagementAddOnLister - managedClusterAddonIndexer cache.Indexer - addonFilterFunc factory.EventFilterFunc - placementLister clusterlisterv1beta1.PlacementLister - placementDecisionLister clusterlisterv1beta1.PlacementDecisionLister - placementDecisionGetter PlacementDecisionGetter - - reconcilers []addonConfigurationReconcile -} - -type addonConfigurationReconcile interface { - reconcile(ctx context.Context, cma *addonv1alpha1.ClusterManagementAddOn, - graph *configurationGraph) (*addonv1alpha1.ClusterManagementAddOn, reconcileState, error) -} - -type reconcileState int64 - -const ( - reconcileStop reconcileState = iota - reconcileContinue -) - -func NewAddonConfigurationController( - addonClient addonv1alpha1client.Interface, - addonInformers addoninformerv1alpha1.ManagedClusterAddOnInformer, - clusterManagementAddonInformers addoninformerv1alpha1.ClusterManagementAddOnInformer, - placementInformer clusterinformersv1beta1.PlacementInformer, - placementDecisionInformer clusterinformersv1beta1.PlacementDecisionInformer, - addonFilterFunc factory.EventFilterFunc, -) factory.Controller { - c := &addonConfigurationController{ - addonClient: addonClient, - clusterManagementAddonLister: clusterManagementAddonInformers.Lister(), - managedClusterAddonIndexer: addonInformers.Informer().GetIndexer(), - addonFilterFunc: addonFilterFunc, - } - - c.reconcilers = []addonConfigurationReconcile{ - &managedClusterAddonConfigurationReconciler{ - addonClient: addonClient, - }, - &clusterManagementAddonProgressingReconciler{ - addonClient: addonClient, - }, - } - - controllerFactory := factory.New().WithFilteredEventsInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - c.addonFilterFunc, - clusterManagementAddonInformers.Informer()).WithInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - addonInformers.Informer()) - - // This is to handle the case the self managed addon-manager does not have placementInformer/placementDecisionInformer. - // we will not consider installStrategy related placement for self managed addon-manager. - if placementInformer != nil && placementDecisionInformer != nil { - controllerFactory = controllerFactory.WithInformersQueueKeysFunc( - index.ClusterManagementAddonByPlacementDecisionQueueKey(clusterManagementAddonInformers), placementDecisionInformer.Informer()). - WithInformersQueueKeysFunc(index.ClusterManagementAddonByPlacementQueueKey(clusterManagementAddonInformers), placementInformer.Informer()) - c.placementLister = placementInformer.Lister() - c.placementDecisionLister = placementDecisionInformer.Lister() - c.placementDecisionGetter = PlacementDecisionGetter{Client: placementDecisionInformer.Lister()} - } - - return controllerFactory.WithSync(c.sync).ToController("addon-configuration-controller") -} - -func (c *addonConfigurationController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { - _, addonName, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - // ignore addon whose key is invalid - return nil - } - - klog.V(4).Infof("Reconciling addon %q", addonName) - - cma, err := c.clusterManagementAddonLister.Get(addonName) - switch { - case errors.IsNotFound(err): - return nil - case err != nil: - return err - } - - if !c.addonFilterFunc(cma) { - return nil - } - - cma = cma.DeepCopy() - graph, err := c.buildConfigurationGraph(cma) - if err != nil { - return err - } - - // generate the rollout result before calling reconcile() - // so that all the reconcilers are using the same rollout result - err = graph.generateRolloutResult() - if err != nil { - return err - } - - var state reconcileState - var errs []error - for _, reconciler := range c.reconcilers { - cma, state, err = reconciler.reconcile(ctx, cma, graph) - if err != nil { - errs = append(errs, err) - } - if state == reconcileStop { - break - } - } - - return utilerrors.NewAggregate(errs) -} - -func (c *addonConfigurationController) buildConfigurationGraph(cma *addonv1alpha1.ClusterManagementAddOn) (*configurationGraph, error) { - graph := newGraph(cma.Spec.SupportedConfigs, cma.Status.DefaultConfigReferences) - addons, err := c.managedClusterAddonIndexer.ByIndex(index.ManagedClusterAddonByName, cma.Name) - if err != nil { - return graph, err - } - - // add all existing addons to the default at first - for _, addonObject := range addons { - addon := addonObject.(*addonv1alpha1.ManagedClusterAddOn) - graph.addAddonNode(addon) - } - - if cma.Spec.InstallStrategy.Type == "" || cma.Spec.InstallStrategy.Type == addonv1alpha1.AddonInstallStrategyManual { - return graph, nil - } - - // check each install strategy in status - var errs []error - for _, installProgression := range cma.Status.InstallProgressions { - for _, installStrategy := range cma.Spec.InstallStrategy.Placements { - if installStrategy.PlacementRef != installProgression.PlacementRef { - continue - } - - // add placement node - err = graph.addPlacementNode(installStrategy, installProgression, c.placementLister, c.placementDecisionGetter) - if err != nil { - errs = append(errs, err) - continue - } - } - } - - return graph, utilerrors.NewAggregate(errs) -} - -type PlacementDecisionGetter struct { - Client clusterlister.PlacementDecisionLister -} - -func (pdl PlacementDecisionGetter) List(selector labels.Selector, namespace string) ([]*clusterv1beta1.PlacementDecision, error) { - return pdl.Client.PlacementDecisions(namespace).List(selector) -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/graph.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/graph.go deleted file mode 100644 index d0b381e25..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/graph.go +++ /dev/null @@ -1,417 +0,0 @@ -package addonconfiguration - -import ( - "fmt" - "sort" - - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/sets" - - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - clusterlisterv1beta1 "open-cluster-management.io/api/client/cluster/listers/cluster/v1beta1" - clusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1" - clusterv1sdkalpha1 "open-cluster-management.io/sdk-go/pkg/apis/cluster/v1alpha1" - clustersdkv1beta1 "open-cluster-management.io/sdk-go/pkg/apis/cluster/v1beta1" -) - -// configurationTree is a 2 level snapshot tree on the configuration of addons -// the first level is a list of nodes that represents a install strategy and a desired configuration for this install -// strategy. The second level is a list of nodes that represent each mca and its desired configuration -type configurationGraph struct { - // nodes maintains a list between a installStrategy and its related mcas - nodes []*installStrategyNode - // defaults is the nodes with no install strategy - defaults *installStrategyNode -} - -// installStrategyNode is a node in configurationGraph defined by a install strategy -type installStrategyNode struct { - placementRef addonv1alpha1.PlacementRef - pdTracker *clustersdkv1beta1.PlacementDecisionClustersTracker - rolloutStrategy clusterv1alpha1.RolloutStrategy - rolloutResult clusterv1sdkalpha1.RolloutResult - desiredConfigs addonConfigMap - // children keeps a map of addons node as the children of this node - children map[string]*addonNode - clusters sets.Set[string] -} - -// addonNode is node as a child of installStrategy node represting a mca -// addonnode -type addonNode struct { - desiredConfigs addonConfigMap - mca *addonv1alpha1.ManagedClusterAddOn - status *clusterv1sdkalpha1.ClusterRolloutStatus -} - -type addonConfigMap map[addonv1alpha1.ConfigGroupResource]addonv1alpha1.ConfigReference - -// set addon rollout status -func (n *addonNode) setRolloutStatus() { - n.status = &clusterv1sdkalpha1.ClusterRolloutStatus{ClusterName: n.mca.Namespace} - - // desired configs doesn't match actual configs, set to ToApply - if len(n.mca.Status.ConfigReferences) != len(n.desiredConfigs) { - n.status.Status = clusterv1sdkalpha1.ToApply - return - } - - var progressingCond metav1.Condition - for _, cond := range n.mca.Status.Conditions { - if cond.Type == addonv1alpha1.ManagedClusterAddOnConditionProgressing { - progressingCond = cond - break - } - } - - for _, actual := range n.mca.Status.ConfigReferences { - if desired, ok := n.desiredConfigs[actual.ConfigGroupResource]; ok { - // desired config spec hash doesn't match actual, set to ToApply - if !equality.Semantic.DeepEqual(desired.DesiredConfig, actual.DesiredConfig) { - n.status.Status = clusterv1sdkalpha1.ToApply - return - // desired config spec hash matches actual, but last applied config spec hash doesn't match actual - } else if !equality.Semantic.DeepEqual(actual.LastAppliedConfig, actual.DesiredConfig) { - switch progressingCond.Reason { - case addonv1alpha1.ProgressingReasonInstallFailed, addonv1alpha1.ProgressingReasonUpgradeFailed: - n.status.Status = clusterv1sdkalpha1.Failed - n.status.LastTransitionTime = &progressingCond.LastTransitionTime - case addonv1alpha1.ProgressingReasonInstalling, addonv1alpha1.ProgressingReasonUpgrading: - n.status.Status = clusterv1sdkalpha1.Progressing - n.status.LastTransitionTime = &progressingCond.LastTransitionTime - default: - n.status.Status = clusterv1sdkalpha1.Progressing - } - return - } - } else { - n.status.Status = clusterv1sdkalpha1.ToApply - return - } - } - - // succeed - n.status.Status = clusterv1sdkalpha1.Succeeded - if progressingCond.Reason == addonv1alpha1.ProgressingReasonInstallSucceed || progressingCond.Reason == addonv1alpha1.ProgressingReasonUpgradeSucceed { - n.status.LastTransitionTime = &progressingCond.LastTransitionTime - } -} - -func (d addonConfigMap) copy() addonConfigMap { - output := addonConfigMap{} - for k, v := range d { - output[k] = v - } - return output -} - -func newGraph(supportedConfigs []addonv1alpha1.ConfigMeta, defaultConfigReferences []addonv1alpha1.DefaultConfigReference) *configurationGraph { - graph := &configurationGraph{ - nodes: []*installStrategyNode{}, - defaults: &installStrategyNode{ - desiredConfigs: map[addonv1alpha1.ConfigGroupResource]addonv1alpha1.ConfigReference{}, - children: map[string]*addonNode{}, - }, - } - - // init graph.defaults.desiredConfigs with supportedConfigs - for _, config := range supportedConfigs { - if config.DefaultConfig != nil { - graph.defaults.desiredConfigs[config.ConfigGroupResource] = addonv1alpha1.ConfigReference{ - ConfigGroupResource: config.ConfigGroupResource, - ConfigReferent: *config.DefaultConfig, - DesiredConfig: &addonv1alpha1.ConfigSpecHash{ - ConfigReferent: *config.DefaultConfig, - }, - } - } - } - // copy the spechash from cma status defaultConfigReferences - for _, configRef := range defaultConfigReferences { - if configRef.DesiredConfig == nil { - continue - } - defaultsDesiredConfig, ok := graph.defaults.desiredConfigs[configRef.ConfigGroupResource] - if ok && (defaultsDesiredConfig.DesiredConfig.ConfigReferent == configRef.DesiredConfig.ConfigReferent) { - defaultsDesiredConfig.DesiredConfig.SpecHash = configRef.DesiredConfig.SpecHash - } - } - - return graph -} - -// addAddonNode to the graph, starting from placement with the highest order -func (g *configurationGraph) addAddonNode(mca *addonv1alpha1.ManagedClusterAddOn) { - for i := len(g.nodes) - 1; i >= 0; i-- { - if g.nodes[i].clusters.Has(mca.Namespace) { - g.nodes[i].addNode(mca) - return - } - } - - g.defaults.addNode(mca) -} - -// addNode delete clusters on existing graph so the new configuration overrides the previous -func (g *configurationGraph) addPlacementNode( - installStrategy addonv1alpha1.PlacementStrategy, - installProgression addonv1alpha1.InstallProgression, - placementLister clusterlisterv1beta1.PlacementLister, - placementDecisionGetter PlacementDecisionGetter, -) error { - placementRef := installProgression.PlacementRef - installConfigReference := installProgression.ConfigReferences - - // get placement - if placementLister == nil { - return fmt.Errorf("invalid placement lister %v", placementLister) - } - placement, err := placementLister.Placements(placementRef.Namespace).Get(placementRef.Name) - if err != nil { - return err - } - - // new decision tracker - pdTracker := clustersdkv1beta1.NewPlacementDecisionClustersTracker(placement, placementDecisionGetter, nil) - - // refresh and get existing decision clusters - err = pdTracker.Refresh() - if err != nil { - return err - } - clusters := pdTracker.ExistingClusterGroupsBesides().GetClusters() - - node := &installStrategyNode{ - placementRef: placementRef, - pdTracker: pdTracker, - rolloutStrategy: installStrategy.RolloutStrategy, - desiredConfigs: g.defaults.desiredConfigs, - children: map[string]*addonNode{}, - clusters: clusters, - } - - // Set MaxConcurrency - // If progressive strategy is not initialized or MaxConcurrency is not specified, set MaxConcurrency to the default value - if node.rolloutStrategy.Type == clusterv1alpha1.Progressive { - progressiveStrategy := node.rolloutStrategy.Progressive - - if progressiveStrategy == nil { - progressiveStrategy = &clusterv1alpha1.RolloutProgressive{} - } - if progressiveStrategy.MaxConcurrency.StrVal == "" && progressiveStrategy.MaxConcurrency.IntVal == 0 { - progressiveStrategy.MaxConcurrency = placement.Spec.DecisionStrategy.GroupStrategy.ClustersPerDecisionGroup - } - - node.rolloutStrategy.Progressive = progressiveStrategy - } - - // overrides configuration by install strategy - if len(installConfigReference) > 0 { - node.desiredConfigs = node.desiredConfigs.copy() - for _, configRef := range installConfigReference { - if configRef.DesiredConfig == nil { - continue - } - node.desiredConfigs[configRef.ConfigGroupResource] = addonv1alpha1.ConfigReference{ - ConfigGroupResource: configRef.ConfigGroupResource, - ConfigReferent: configRef.DesiredConfig.ConfigReferent, - DesiredConfig: configRef.DesiredConfig.DeepCopy(), - } - } - } - - // remove addon in defaults and other placements. - for _, cluster := range node.clusters.UnsortedList() { - if _, ok := g.defaults.children[cluster]; ok { - node.addNode(g.defaults.children[cluster].mca) - delete(g.defaults.children, cluster) - } - for _, placementNode := range g.nodes { - if _, ok := placementNode.children[cluster]; ok { - node.addNode(placementNode.children[cluster].mca) - delete(placementNode.children, cluster) - } - } - } - g.nodes = append(g.nodes, node) - return nil -} - -func (g *configurationGraph) generateRolloutResult() error { - for _, node := range g.nodes { - if err := node.generateRolloutResult(); err != nil { - return err - } - } - if err := g.defaults.generateRolloutResult(); err != nil { - return err - } - return nil -} - -func (g *configurationGraph) getPlacementNodes() map[addonv1alpha1.PlacementRef]*installStrategyNode { - placementNodeMap := map[addonv1alpha1.PlacementRef]*installStrategyNode{} - for _, node := range g.nodes { - placementNodeMap[node.placementRef] = node - } - - return placementNodeMap -} - -func (g *configurationGraph) getAddonsToUpdate() []*addonNode { - var addons []*addonNode - for _, node := range g.nodes { - addons = append(addons, node.getAddonsToUpdate()...) - } - - addons = append(addons, g.defaults.getAddonsToUpdate()...) - - return addons -} - -func (n *installStrategyNode) addNode(addon *addonv1alpha1.ManagedClusterAddOn) { - n.children[addon.Namespace] = &addonNode{ - mca: addon, - desiredConfigs: n.desiredConfigs, - } - - // override configuration by mca spec - if len(addon.Spec.Configs) > 0 { - n.children[addon.Namespace].desiredConfigs = n.children[addon.Namespace].desiredConfigs.copy() - // TODO we should also filter out the configs which are not supported configs. - for _, config := range addon.Spec.Configs { - n.children[addon.Namespace].desiredConfigs[config.ConfigGroupResource] = addonv1alpha1.ConfigReference{ - ConfigGroupResource: config.ConfigGroupResource, - ConfigReferent: config.ConfigReferent, - DesiredConfig: &addonv1alpha1.ConfigSpecHash{ - ConfigReferent: config.ConfigReferent, - }, - } - // copy the spechash from mca status - for _, configRef := range addon.Status.ConfigReferences { - if configRef.DesiredConfig == nil { - continue - } - nodeDesiredConfig, ok := n.children[addon.Namespace].desiredConfigs[configRef.ConfigGroupResource] - if ok && (nodeDesiredConfig.DesiredConfig.ConfigReferent == configRef.DesiredConfig.ConfigReferent) { - nodeDesiredConfig.DesiredConfig.SpecHash = configRef.DesiredConfig.SpecHash - } - } - } - } - - // set addon node rollout status - n.children[addon.Namespace].setRolloutStatus() -} - -func (n *installStrategyNode) generateRolloutResult() error { - if n.placementRef.Name == "" { - // default addons - rolloutResult := clusterv1sdkalpha1.RolloutResult{} - rolloutResult.ClustersToRollout = []clusterv1sdkalpha1.ClusterRolloutStatus{} - for name, addon := range n.children { - if addon.status == nil { - return fmt.Errorf("failed to get rollout status on cluster %v", name) - } - if addon.status.Status != clusterv1sdkalpha1.Succeeded { - rolloutResult.ClustersToRollout = append(rolloutResult.ClustersToRollout, *addon.status) - } - } - n.rolloutResult = rolloutResult - } else { - // placement addons - rolloutHandler, err := clusterv1sdkalpha1.NewRolloutHandler(n.pdTracker, getClusterRolloutStatus) - if err != nil { - return err - } - - // get existing addons - existingRolloutClusters := []clusterv1sdkalpha1.ClusterRolloutStatus{} - for name, addon := range n.children { - clsRolloutStatus, err := getClusterRolloutStatus(name, addon) - if err != nil { - return err - } - existingRolloutClusters = append(existingRolloutClusters, clsRolloutStatus) - } - - // sort by cluster name - sort.SliceStable(existingRolloutClusters, func(i, j int) bool { - return existingRolloutClusters[i].ClusterName < existingRolloutClusters[j].ClusterName - }) - - _, rolloutResult, err := rolloutHandler.GetRolloutCluster(n.rolloutStrategy, existingRolloutClusters) - if err != nil { - return err - } - n.rolloutResult = rolloutResult - } - - return nil -} - -// addonToUpdate finds the addons to be updated by placement -func (n *installStrategyNode) getAddonsToUpdate() []*addonNode { - var addons []*addonNode - var clusters []string - - // get addon to update from rollout result - for _, c := range n.rolloutResult.ClustersToRollout { - if _, exist := n.children[c.ClusterName]; exist { - clusters = append(clusters, c.ClusterName) - } - } - - // sort addons by name - sort.Strings(clusters) - for _, k := range clusters { - addons = append(addons, n.children[k]) - } - return addons -} - -func (n *installStrategyNode) countAddonUpgradeSucceed() int { - count := 0 - for _, addon := range n.children { - if desiredConfigsEqual(addon.desiredConfigs, n.desiredConfigs) && addon.status.Status == clusterv1sdkalpha1.Succeeded { - count += 1 - } - } - return count -} - -func (n *installStrategyNode) countAddonUpgrading() int { - count := 0 - for _, addon := range n.children { - if desiredConfigsEqual(addon.desiredConfigs, n.desiredConfigs) && addon.status.Status == clusterv1sdkalpha1.Progressing { - count += 1 - } - } - return count -} - -func (n *installStrategyNode) countAddonTimeOut() int { - return len(n.rolloutResult.ClustersTimeOut) -} - -func getClusterRolloutStatus(clusterName string, addonNode *addonNode) (clusterv1sdkalpha1.ClusterRolloutStatus, error) { - if addonNode.status == nil { - return clusterv1sdkalpha1.ClusterRolloutStatus{}, fmt.Errorf("failed to get rollout status on cluster %v", clusterName) - } - return *addonNode.status, nil -} - -func desiredConfigsEqual(a, b addonConfigMap) bool { - if len(a) != len(b) { - return false - } - - for configgrA := range a { - if a[configgrA] != b[configgrA] { - return false - } - } - - return true -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/mgmt_addon_progressing_reconciler.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/mgmt_addon_progressing_reconciler.go deleted file mode 100644 index 36d712383..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/mgmt_addon_progressing_reconciler.go +++ /dev/null @@ -1,143 +0,0 @@ -package addonconfiguration - -import ( - "context" - "encoding/json" - "fmt" - - jsonpatch "github.com/evanphx/json-patch" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/klog/v2" - - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" -) - -type clusterManagementAddonProgressingReconciler struct { - addonClient addonv1alpha1client.Interface -} - -func (d *clusterManagementAddonProgressingReconciler) reconcile( - ctx context.Context, cma *addonv1alpha1.ClusterManagementAddOn, graph *configurationGraph) (*addonv1alpha1.ClusterManagementAddOn, reconcileState, error) { - var errs []error - cmaCopy := cma.DeepCopy() - placementNodes := graph.getPlacementNodes() - - // go through addons and update condition per install progression - for i, installProgression := range cmaCopy.Status.InstallProgressions { - placementNode, exist := placementNodes[installProgression.PlacementRef] - if !exist { - continue - } - - isUpgrade := false - - for _, configReference := range installProgression.ConfigReferences { - if configReference.LastAppliedConfig != nil { - isUpgrade = true - break - } - } - - setAddOnInstallProgressionsAndLastApplied(&cmaCopy.Status.InstallProgressions[i], - isUpgrade, - placementNode.countAddonUpgrading(), - placementNode.countAddonUpgradeSucceed(), - placementNode.countAddonTimeOut(), - len(placementNode.clusters), - ) - } - - err := d.patchMgmtAddonStatus(ctx, cmaCopy, cma) - if err != nil { - errs = append(errs, err) - } - return cmaCopy, reconcileContinue, utilerrors.NewAggregate(errs) -} - -func (d *clusterManagementAddonProgressingReconciler) patchMgmtAddonStatus(ctx context.Context, new, old *addonv1alpha1.ClusterManagementAddOn) error { - if equality.Semantic.DeepEqual(new.Status, old.Status) { - return nil - } - - oldData, err := json.Marshal(&addonv1alpha1.ClusterManagementAddOn{ - Status: addonv1alpha1.ClusterManagementAddOnStatus{ - InstallProgressions: old.Status.InstallProgressions, - }, - }) - if err != nil { - return err - } - - newData, err := json.Marshal(&addonv1alpha1.ClusterManagementAddOn{ - ObjectMeta: metav1.ObjectMeta{ - UID: new.UID, - ResourceVersion: new.ResourceVersion, - }, - Status: addonv1alpha1.ClusterManagementAddOnStatus{ - InstallProgressions: new.Status.InstallProgressions, - }, - }) - if err != nil { - return err - } - - patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) - if err != nil { - return fmt.Errorf("failed to create patch for addon %s: %w", new.Name, err) - } - - klog.V(2).Infof("Patching clustermanagementaddon %s status with %s", new.Name, string(patchBytes)) - _, err = d.addonClient.AddonV1alpha1().ClusterManagementAddOns().Patch( - ctx, new.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}, "status") - return err -} - -func setAddOnInstallProgressionsAndLastApplied( - installProgression *addonv1alpha1.InstallProgression, - isUpgrade bool, - progressing, done, timeout, total int) { - // always update progressing condition when there is no config - // skip update progressing condition when last applied config already the same as desired - skip := len(installProgression.ConfigReferences) > 0 - for _, configReference := range installProgression.ConfigReferences { - if !equality.Semantic.DeepEqual(configReference.LastAppliedConfig, configReference.DesiredConfig) && - !equality.Semantic.DeepEqual(configReference.LastKnownGoodConfig, configReference.DesiredConfig) { - skip = false - } - } - if skip { - return - } - condition := metav1.Condition{ - Type: addonv1alpha1.ManagedClusterAddOnConditionProgressing, - } - if (total == 0 && done == 0) || (done != total) { - condition.Status = metav1.ConditionTrue - if isUpgrade { - condition.Reason = addonv1alpha1.ProgressingReasonUpgrading - condition.Message = fmt.Sprintf("%d/%d upgrading..., %d timeout.", progressing+done, total, timeout) - } else { - condition.Reason = addonv1alpha1.ProgressingReasonInstalling - condition.Message = fmt.Sprintf("%d/%d installing..., %d timeout.", progressing+done, total, timeout) - } - } else { - for i, configRef := range installProgression.ConfigReferences { - installProgression.ConfigReferences[i].LastAppliedConfig = configRef.DesiredConfig.DeepCopy() - installProgression.ConfigReferences[i].LastKnownGoodConfig = configRef.DesiredConfig.DeepCopy() - } - condition.Status = metav1.ConditionFalse - if isUpgrade { - condition.Reason = addonv1alpha1.ProgressingReasonUpgradeSucceed - condition.Message = fmt.Sprintf("%d/%d upgrade completed with no errors, %d timeout.", done, total, timeout) - } else { - condition.Reason = addonv1alpha1.ProgressingReasonInstallSucceed - condition.Message = fmt.Sprintf("%d/%d install completed with no errors, %d timeout.", done, total, timeout) - } - } - meta.SetStatusCondition(&installProgression.Conditions, condition) -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner/controller.go deleted file mode 100644 index beff5b4bd..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner/controller.go +++ /dev/null @@ -1,100 +0,0 @@ -package addonowner - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - "k8s.io/klog/v2" - - addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" - addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" - addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - - "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" - "open-cluster-management.io/addon-framework/pkg/utils" -) - -const UnsupportedConfigurationType = "UnsupportedConfiguration" - -// addonOwnerController reconciles instances of managedclusteradd on the hub -// to add related ClusterManagementAddon as the owner. -type addonOwnerController struct { - addonClient addonv1alpha1client.Interface - managedClusterAddonLister addonlisterv1alpha1.ManagedClusterAddOnLister - clusterManagementAddonLister addonlisterv1alpha1.ClusterManagementAddOnLister - addonFilterFunc factory.EventFilterFunc -} - -func NewAddonOwnerController( - addonClient addonv1alpha1client.Interface, - addonInformers addoninformerv1alpha1.ManagedClusterAddOnInformer, - clusterManagementAddonInformers addoninformerv1alpha1.ClusterManagementAddOnInformer, - addonFilterFunc factory.EventFilterFunc, -) factory.Controller { - c := &addonOwnerController{ - addonClient: addonClient, - managedClusterAddonLister: addonInformers.Lister(), - clusterManagementAddonLister: clusterManagementAddonInformers.Lister(), - addonFilterFunc: addonFilterFunc, - } - - return factory.New().WithFilteredEventsInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - c.addonFilterFunc, clusterManagementAddonInformers.Informer()). - WithInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - addonInformers.Informer()).WithSync(c.sync).ToController("addon-owner-controller") -} - -func (c *addonOwnerController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { - klog.V(4).Infof("Reconciling addon %q", key) - - namespace, addonName, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - // ignore addon whose key is invalid - return nil - } - - addon, err := c.managedClusterAddonLister.ManagedClusterAddOns(namespace).Get(addonName) - switch { - case errors.IsNotFound(err): - return nil - case err != nil: - return err - } - - addonCopy := addon.DeepCopy() - modified := false - - clusterManagementAddon, err := c.clusterManagementAddonLister.Get(addonName) - if errors.IsNotFound(err) { - return nil - } - - if err != nil { - return err - } - - if !c.addonFilterFunc(clusterManagementAddon) { - return nil - } - - owner := metav1.NewControllerRef(clusterManagementAddon, addonapiv1alpha1.GroupVersion.WithKind("ClusterManagementAddOn")) - modified = utils.MergeOwnerRefs(&addonCopy.OwnerReferences, *owner, false) - if modified { - _, err = c.addonClient.AddonV1alpha1().ManagedClusterAddOns(namespace).Update(ctx, addonCopy, metav1.UpdateOptions{}) - return err - } - - return nil -}