From a2a90a379e90888a7fdda7dc4bba29195f387445 Mon Sep 17 00:00:00 2001 From: Jian Zhu Date: Thu, 21 Mar 2024 11:06:09 +0800 Subject: [PATCH] :sparkles: refactor setting the helm default variable of hostingClusterCapabilities (#251) * refactor setting the helm default variable of hostingClusterCapabilities Signed-off-by: zhujian * add deprecated marks Signed-off-by: zhujian * ignore not found error for getting hosting cluster Signed-off-by: zhujian --------- Signed-off-by: zhujian Signed-off-by: xuezhaojun --- cmd/example/helloworld_hosted/main.go | 6 ++++ pkg/addonfactory/addonfactory.go | 13 +++++++- pkg/addonfactory/helm_agentaddon.go | 39 +++++++++++++++++++++--- pkg/addonfactory/helm_agentaddon_test.go | 30 +++++++++++++++--- 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/cmd/example/helloworld_hosted/main.go b/cmd/example/helloworld_hosted/main.go index 93870981a..5a4376f31 100644 --- a/cmd/example/helloworld_hosted/main.go +++ b/cmd/example/helloworld_hosted/main.go @@ -23,6 +23,7 @@ import ( "open-cluster-management.io/addon-framework/pkg/addonmanager" cmdfactory "open-cluster-management.io/addon-framework/pkg/cmd/factory" "open-cluster-management.io/addon-framework/pkg/version" + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" ) func main() { @@ -85,11 +86,16 @@ func runController(ctx context.Context, kubeConfig *rest.Config) error { helloworld_hosted.AddonName, utilrand.String(5)) + clusterClient, err := clusterclientset.NewForConfig(kubeConfig) + if err != nil { + return err + } agentAddon, err := addonfactory.NewAgentAddonFactory( helloworld_hosted.AddonName, helloworld_hosted.FS, "manifests/templates"). WithGetValuesFuncs(helloworld.GetDefaultValues, addonfactory.GetValuesFromAddonAnnotation). WithAgentRegistrationOption(registrationOption). WithAgentHostedModeEnabledOption(). + WithManagedClusterClient(clusterClient). BuildTemplateAgentAddon() if err != nil { klog.Errorf("failed to build agent %v", err) diff --git a/pkg/addonfactory/addonfactory.go b/pkg/addonfactory/addonfactory.go index e806be6a0..3ef383d1d 100644 --- a/pkg/addonfactory/addonfactory.go +++ b/pkg/addonfactory/addonfactory.go @@ -11,6 +11,7 @@ import ( "k8s.io/client-go/kubernetes/scheme" "k8s.io/klog/v2" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterv1 "open-cluster-management.io/api/cluster/v1" "open-cluster-management.io/addon-framework/pkg/agent" @@ -34,9 +35,12 @@ type AgentAddonFactory struct { getValuesFuncs []GetValuesFunc agentAddonOptions agent.AgentAddonOptions // trimCRDDescription flag is used to trim the description of CRDs in manifestWork. disabled by default. - trimCRDDescription bool + trimCRDDescription bool + // Deprecated: use clusterClient to get the hosting cluster. hostingCluster *clusterv1.ManagedCluster + clusterClient clusterclientset.Interface agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) + helmEngineStrict bool } // NewAgentAddonFactory builds an addonAgentFactory instance with addon name and fs. @@ -123,11 +127,18 @@ func (f *AgentAddonFactory) WithConfigGVRs(gvrs ...schema.GroupVersionResource) // WithHostingCluster defines the hosting cluster used in hosted mode. An AgentAddon may use this to provide // additional metadata. +// Deprecated: use WithManagedClusterClient to set a cluster client that can get the hosting cluster. func (f *AgentAddonFactory) WithHostingCluster(cluster *clusterv1.ManagedCluster) *AgentAddonFactory { f.hostingCluster = cluster return f } +// WithManagedClusterClient defines the cluster client that can get the hosting cluster used in hosted mode. +func (f *AgentAddonFactory) WithManagedClusterClient(c clusterclientset.Interface) *AgentAddonFactory { + f.clusterClient = c + return f +} + // WithAgentDeployTriggerClusterFilter defines the filter func to trigger the agent deploy/redploy when cluster info is // changed. 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 diff --git a/pkg/addonfactory/helm_agentaddon.go b/pkg/addonfactory/helm_agentaddon.go index fbb9b8c5e..5af2397fa 100644 --- a/pkg/addonfactory/helm_agentaddon.go +++ b/pkg/addonfactory/helm_agentaddon.go @@ -2,6 +2,7 @@ package addonfactory import ( "bufio" + "context" "fmt" "io" "sort" @@ -10,11 +11,14 @@ import ( "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/engine" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/klog/v2" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterv1 "open-cluster-management.io/api/cluster/v1" "open-cluster-management.io/addon-framework/pkg/addonmanager/constants" @@ -42,13 +46,16 @@ type helmDefaultValues struct { } type HelmAgentAddon struct { - decoder runtime.Decoder - chart *chart.Chart - getValuesFuncs []GetValuesFunc - agentAddonOptions agent.AgentAddonOptions - trimCRDDescription bool + decoder runtime.Decoder + chart *chart.Chart + getValuesFuncs []GetValuesFunc + agentAddonOptions agent.AgentAddonOptions + trimCRDDescription bool + // Deprecated: use clusterClient to get the hosting cluster. hostingCluster *clusterv1.ManagedCluster + clusterClient clusterclientset.Interface agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) + helmEngineStrict bool } func newHelmAgentAddon(factory *AgentAddonFactory, chart *chart.Chart) *HelmAgentAddon { @@ -59,6 +66,7 @@ func newHelmAgentAddon(factory *AgentAddonFactory, chart *chart.Chart) *HelmAgen agentAddonOptions: factory.agentAddonOptions, trimCRDDescription: factory.trimCRDDescription, hostingCluster: factory.hostingCluster, + clusterClient: factory.clusterClient, agentInstallNamespace: factory.agentInstallNamespace, } } @@ -234,6 +242,12 @@ func (a *HelmAgentAddon) getBuiltinValues( return helmBuiltinValues, nil } +// Deprecated: use "WithManagedClusterClient" in AgentAddonFactory to set a cluster client that +// can be used to get the hosting cluster. +func (a *HelmAgentAddon) SetHostingCluster(hostingCluster *clusterv1.ManagedCluster) { + a.hostingCluster = hostingCluster +} + func (a *HelmAgentAddon) getDefaultValues( cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (Values, error) { @@ -248,6 +262,21 @@ func (a *HelmAgentAddon) getDefaultValues( if a.hostingCluster != nil { defaultValues.HostingClusterCapabilities = *a.capabilities(a.hostingCluster, addon) + } else if a.clusterClient != nil { + hostingClusterName := addon.GetAnnotations()[addonapiv1alpha1.HostingClusterNameAnnotationKey] + if len(hostingClusterName) > 0 { + hostingCluster, err := a.clusterClient.ClusterV1().ManagedClusters(). + Get(context.TODO(), hostingClusterName, metav1.GetOptions{}) + if err == nil { + defaultValues.HostingClusterCapabilities = *a.capabilities(hostingCluster, addon) + } else if errors.IsNotFound(err) { + klog.Infof("hostingCluster %s not found, skip providing default value hostingClusterCapabilities", + hostingClusterName) + } else { + klog.Errorf("failed to get hostingCluster %s. err:%v", hostingClusterName, err) + return nil, err + } + } } helmDefaultValues, err := JsonStructToValues(defaultValues) diff --git a/pkg/addonfactory/helm_agentaddon_test.go b/pkg/addonfactory/helm_agentaddon_test.go index 84ae53f65..4888e281b 100644 --- a/pkg/addonfactory/helm_agentaddon_test.go +++ b/pkg/addonfactory/helm_agentaddon_test.go @@ -13,6 +13,7 @@ import ( "k8s.io/client-go/kubernetes/scheme" "open-cluster-management.io/addon-framework/pkg/agent" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned/fake" clusterv1 "open-cluster-management.io/api/cluster/v1" clusterv1apha1 "open-cluster-management.io/api/cluster/v1alpha1" ) @@ -66,6 +67,7 @@ func TestChartAgentAddon_Manifests(t *testing.T) { scheme *runtime.Scheme clusterName string hostingCluster *clusterv1.ManagedCluster + getHostingClusterWithClient bool addonName string installNamespace string annotationValues string @@ -146,6 +148,19 @@ func TestChartAgentAddon_Manifests(t *testing.T) { expectedObjCnt: 5, expectedNamespace: true, }, + { + name: "template render ok, getting hosting cluster with client", + scheme: testScheme, + clusterName: "cluster1", + hostingCluster: NewFakeManagedCluster("hosting-cluster", "1.25.0"), + getHostingClusterWithClient: true, + addonName: "helloworld", + installNamespace: "myNs", + expectedInstallNamespace: "myNs", + expectedImage: "quay.io/testimage:test", + expectedObjCnt: 5, + expectedNamespace: true, + }, } for _, c := range cases { @@ -166,13 +181,20 @@ func TestChartAgentAddon_Manifests(t *testing.T) { cluster := NewFakeManagedCluster(c.clusterName, "1.10.1") clusterAddon := NewFakeManagedClusterAddon(c.addonName, c.clusterName, c.installNamespace, c.annotationValues) - agentAddon, err := NewAgentAddonFactory(c.addonName, chartFS, "testmanifests/chart"). + factory := NewAgentAddonFactory(c.addonName, chartFS, "testmanifests/chart"). WithGetValuesFuncs(getValuesFuncs...). WithScheme(c.scheme). WithTrimCRDDescription(). - WithAgentRegistrationOption(&agent.RegistrationOption{}). - WithHostingCluster(c.hostingCluster). - BuildHelmAgentAddon() + WithAgentRegistrationOption(&agent.RegistrationOption{}) + if c.getHostingClusterWithClient && c.hostingCluster != nil { + clusterClient := clusterclientset.NewSimpleClientset(c.hostingCluster) + factory = factory.WithManagedClusterClient(clusterClient) + clusterAddon.Annotations[addonapiv1alpha1.HostingClusterNameAnnotationKey] = c.hostingCluster.Name + } + if !c.getHostingClusterWithClient && c.hostingCluster != nil { + factory = factory.WithHostingCluster(c.hostingCluster) + } + agentAddon, err := factory.BuildHelmAgentAddon() if err != nil { t.Errorf("expected no error, got err %v", err) }