Repository: kubean-io/kubean (go)

Issue:
software bug: hardcoding in spray job manifest rendering
**Describe the version**
version about:
1. kubean 
   `all`
3. kubespray
4. kubenetes
5. what CNI and itsversion


**Describe the bug**
  When assgin value to `kubeanOperator.nameOverride` or `kubeanOperator.fullnameOverride` with helm, ServiceAccount name would be changed too. 
  But there is hardcoding which cause job failed to create as that.
  https://github.com/kubean-io/kubean/blob/main/pkg/controllers/clusterops/controller.go#L370

**How To Reproduce**
Steps to reproduce the issue:

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots and log**
If applicable, add screenshots and log to help explain your problem.

**Additional context**
Add any other context about the problem here.

Pull request:
Get serviceaccount name by labelselector
Signed-off-by: tu1h <lihai.tu@daocloud.io>

<!--  

Thanks for sending a pull request!  Here are some tips for you:

* make sure your commit is signed off

-->

**What type of PR is this?**
<!-- 
Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line:

/kind api-change
/kind bug
/kind cleanup
/kind design
/kind documentation
/kind failing-test
/kind feature
/kind flake
-->
/kind bug

**What this PR does / why we need it**:
  Get serviceaccount name by labelselector rather than by hardcoding.

**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #494

**Special notes for your reviewer**:



Patch:
diff --git a/charts/kubean/templates/serviceaccount.yaml b/charts/kubean/templates/serviceaccount.yaml
index fcbafc107..58b30c090 100644
--- a/charts/kubean/templates/serviceaccount.yaml
+++ b/charts/kubean/templates/serviceaccount.yaml
@@ -5,6 +5,7 @@ metadata:
   name: {{ include "kubean.serviceAccountName" . }}
   namespace: {{ include "kubean.namespace" . }}
   labels:
+    kubean.io/kubean-operator: sa
     {{- include "kubean.labels" . | nindent 4 }}
   {{- with .Values.kubeanOperator.serviceAccount.annotations }}
   annotations:
diff --git a/pkg/controllers/clusterops/controller.go b/pkg/controllers/clusterops/controller.go
index dda48c280..cb740c9f8 100644
--- a/pkg/controllers/clusterops/controller.go
+++ b/pkg/controllers/clusterops/controller.go
@@ -3,6 +3,7 @@ package clusterops
 import (
 	"context"
 	"crypto/md5"
+	"errors"
 	"fmt"
 	"reflect"
 	"strconv"
@@ -38,6 +39,7 @@ const (
 	LoopForJobStatus = time.Second * 3
 	RetryInterval    = time.Millisecond * 300
 	RetryCount       = 5
+	ServiceAccount   = "kubean.io/kubean-operator=sa"
 )
 
 type Controller struct {
@@ -347,7 +349,7 @@ func (c *Controller) FetchGlobalManifestImageTag() string {
 	return globalManifest.Spec.KubeanVersion
 }
 
-func (c *Controller) NewKubesprayJob(clusterOps *clusteroperationv1alpha1.ClusterOperation) *batchv1.Job {
+func (c *Controller) NewKubesprayJob(clusterOps *clusteroperationv1alpha1.ClusterOperation, serviceAccountName string) *batchv1.Job {
 	BackoffLimit := int32(clusterOps.Spec.BackoffLimit)
 	DefaultMode := int32(0o700)
 	PrivatekeyMode := int32(0o400)
@@ -367,7 +369,7 @@ func (c *Controller) NewKubesprayJob(clusterOps *clusteroperationv1alpha1.Cluste
 			Template: corev1.PodTemplateSpec{
 				Spec: corev1.PodSpec{
 					RestartPolicy:      corev1.RestartPolicyNever,
-					ServiceAccountName: "kubean",
+					ServiceAccountName: serviceAccountName,
 					Containers: []corev1.Container{
 						{
 							Name:    "kubespray", // do not change this name
@@ -483,8 +485,12 @@ func (c *Controller) CreateKubeSprayJob(clusterOps *clusteroperationv1alpha1.Clu
 	if err != nil {
 		if apierrors.IsNotFound(err) {
 			// the job doest not exist , and will create the job.
+			sa, err := c.GetServiceAccountName(util.GetCurrentNSOrDefault(), ServiceAccount)
+			if err != nil {
+				return false, err
+			}
 			klog.Warningf("create job %s for kuBeanClusterOp %s", jobName, clusterOps.Name)
-			job = c.NewKubesprayJob(clusterOps)
+			job = c.NewKubesprayJob(clusterOps, sa)
 
 			c.SetOwnerReferences(&job.ObjectMeta, clusterOps)
 			job, err = c.ClientSet.BatchV1().Jobs(job.Namespace).Create(context.Background(), job, metav1.CreateOptions{})
@@ -567,6 +573,18 @@ func (c *Controller) CreateEntryPointShellConfigMap(clusterOps *clusteroperation
 	return true, nil
 }
 
+// GetServiceAccountName get serviceaccount name on kubean namespace by labelSelector.
+func (c *Controller) GetServiceAccountName(namespace, labelSelector string) (string, error) {
+	serviceAccounts, err := c.ClientSet.CoreV1().ServiceAccounts(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: labelSelector})
+	if err != nil {
+		return "", err
+	}
+	if len(serviceAccounts.Items) <= 0 {
+		return "", errors.New("no valild serviceaccount")
+	}
+	return serviceAccounts.Items[0].Name, nil
+}
+
 func (c *Controller) SetOwnerReferences(objectMetaData *metav1.ObjectMeta, clusterOps *clusteroperationv1alpha1.ClusterOperation) {
 	objectMetaData.OwnerReferences = []metav1.OwnerReference{*metav1.NewControllerRef(clusterOps, clusteroperationv1alpha1.SchemeGroupVersion.WithKind("ClusterOperation"))}
 }


Test patch:
diff --git a/pkg/controllers/clusterops/controller_test.go b/pkg/controllers/clusterops/controller_test.go
index c82cffd80..795cf5629 100644
--- a/pkg/controllers/clusterops/controller_test.go
+++ b/pkg/controllers/clusterops/controller_test.go
@@ -439,7 +439,7 @@ func TestNewKubesprayJob(t *testing.T) {
 		{
 			name: "no ssh args",
 			args: func() bool {
-				job := controller.NewKubesprayJob(clusterOps)
+				job := controller.NewKubesprayJob(clusterOps, "kubean")
 				return job.Namespace == "mynamespace" && job.Name == "kubean-myops-job" && len(job.Spec.Template.Spec.Containers) == 1 && len(job.Spec.Template.Spec.Containers[0].VolumeMounts) == 3 && len(job.Spec.Template.Spec.Volumes) == 3
 			},
 			want: true,
@@ -451,7 +451,7 @@ func TestNewKubesprayJob(t *testing.T) {
 					NameSpace: "mynamespace",
 					Name:      "secret",
 				}
-				job := controller.NewKubesprayJob(clusterOps)
+				job := controller.NewKubesprayJob(clusterOps, "kubean")
 				return job.Namespace == "mynamespace" && job.Name == "kubean-myops-job" && len(job.Spec.Template.Spec.Containers) == 1 && len(job.Spec.Template.Spec.Containers[0].VolumeMounts) == 4 && len(job.Spec.Template.Spec.Volumes) == 4
 			},
 			want: true,
@@ -461,7 +461,7 @@ func TestNewKubesprayJob(t *testing.T) {
 			args: func() bool {
 				ActiveDeadlineSeconds := int64(10)
 				clusterOps.Spec.ActiveDeadlineSeconds = &ActiveDeadlineSeconds
-				job := controller.NewKubesprayJob(clusterOps)
+				job := controller.NewKubesprayJob(clusterOps, "kubean")
 				return *job.Spec.ActiveDeadlineSeconds == 10
 			},
 			want: true,
@@ -470,7 +470,7 @@ func TestNewKubesprayJob(t *testing.T) {
 			name: "nil activeDeadlineSeconds args",
 			args: func() bool {
 				clusterOps.Spec.ActiveDeadlineSeconds = nil
-				job := controller.NewKubesprayJob(clusterOps)
+				job := controller.NewKubesprayJob(clusterOps, "kubean")
 				return job.Spec.ActiveDeadlineSeconds == nil
 			},
 			want: true,