From 7dd2ff1b1b52f9af1f4dbcf4b1c4de327713e474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20S=C4=99k?= Date: Sat, 11 Jan 2020 10:31:18 +0100 Subject: [PATCH] #190 Allow set Jenkins master service account annotations --- pkg/apis/jenkins/v1alpha2/jenkins_types.go | 14 ++++++++ .../jenkins/v1alpha2/zz_generated.deepcopy.go | 24 +++++++++++++ .../jenkins/configuration/base/reconcile.go | 35 +++++++++++++++---- .../configuration/base/reconcile_test.go | 12 +++---- .../base/resources/service_account.go | 5 +-- 5 files changed, 76 insertions(+), 14 deletions(-) diff --git a/pkg/apis/jenkins/v1alpha2/jenkins_types.go b/pkg/apis/jenkins/v1alpha2/jenkins_types.go index 59c3767c..c449e20c 100644 --- a/pkg/apis/jenkins/v1alpha2/jenkins_types.go +++ b/pkg/apis/jenkins/v1alpha2/jenkins_types.go @@ -57,6 +57,20 @@ type JenkinsSpec struct { // Roles defines list of extra RBAC roles for the Jenkins Master pod service account // +optional Roles []rbacv1.RoleRef `json:"roles,omitempty"` + + // ServiceAccount defines Jenkins master service account attributes + // +optional + ServiceAccount ServiceAccount `json:"serviceAccount,omitempty"` +} + +// ServiceAccount defines Kubernetes service account attributes +type ServiceAccount struct { + // Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + // More info: http://kubernetes.io/docs/user-guide/annotations + // +optional + Annotations map[string]string `json:"annotations,omitempty"` } // NotificationLevel defines the level of a Notification diff --git a/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go index 5a34d171..e9df2938 100644 --- a/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go @@ -375,6 +375,7 @@ func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) { *out = make([]rbacv1.RoleRef, len(*in)) copy(*out, *in) } + in.ServiceAccount.DeepCopyInto(&out.ServiceAccount) return } @@ -631,6 +632,29 @@ func (in *Service) DeepCopy() *Service { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccount) DeepCopyInto(out *ServiceAccount) { + *out = *in + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccount. +func (in *ServiceAccount) DeepCopy() *ServiceAccount { + if in == nil { + return nil + } + out := new(ServiceAccount) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Slack) DeepCopyInto(out *Slack) { *out = *in diff --git a/pkg/controller/jenkins/configuration/base/reconcile.go b/pkg/controller/jenkins/configuration/base/reconcile.go index 70b40905..abd8ba9f 100644 --- a/pkg/controller/jenkins/configuration/base/reconcile.go +++ b/pkg/controller/jenkins/configuration/base/reconcile.go @@ -340,13 +340,36 @@ func (r *ReconcileJenkinsBaseConfiguration) addLabelForWatchesResources(customiz return nil } -func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) error { - serviceAccount := resources.NewServiceAccount(meta) - err := r.CreateResource(serviceAccount) - if err != nil && !apierrors.IsAlreadyExists(err) { +func (r *ReconcileJenkinsBaseConfiguration) createServiceAccount(meta metav1.ObjectMeta) error { + serviceAccount := &corev1.ServiceAccount{} + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: meta.Name, Namespace: meta.Namespace}, serviceAccount) + if err != nil && apierrors.IsNotFound(err) { + serviceAccount = resources.NewServiceAccount(meta, r.Configuration.Jenkins.Spec.ServiceAccount.Annotations) + if err = r.CreateResource(serviceAccount); err != nil { + return stackerr.WithStack(err) + } + } else if err != nil { return stackerr.WithStack(err) } + if !compareAnnotations(r.Configuration.Jenkins.Spec.ServiceAccount.Annotations, serviceAccount.Annotations) { + for key, value := range r.Configuration.Jenkins.Spec.ServiceAccount.Annotations { + serviceAccount.Annotations[key] = value + } + if err = r.UpdateResource(serviceAccount); err != nil { + return stackerr.WithStack(err) + } + } + + return nil +} + +func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) error { + err := r.createServiceAccount(meta) + if err != nil { + return err + } + role := resources.NewRole(meta) err = r.CreateOrUpdateResource(role) if err != nil { @@ -603,7 +626,7 @@ func (r *ReconcileJenkinsBaseConfiguration) checkForPodRecreation(currentJenkins } if len(r.Configuration.Jenkins.Spec.Master.Annotations) > 0 && - !comparePodAnnotations(r.Configuration.Jenkins.Spec.Master.Annotations, currentJenkinsMasterPod.ObjectMeta.Annotations) { + !compareAnnotations(r.Configuration.Jenkins.Spec.Master.Annotations, currentJenkinsMasterPod.ObjectMeta.Annotations) { messages = append(messages, "Jenkins pod annotations have changed") verbose = append(verbose, fmt.Sprintf("Jenkins pod annotations have changed, actual '%+v' required '%+v'", currentJenkinsMasterPod.ObjectMeta.Annotations, r.Configuration.Jenkins.Spec.Master.Annotations)) @@ -738,7 +761,7 @@ func compareImagePullSecrets(expected, actual []corev1.LocalObjectReference) boo return true } -func comparePodAnnotations(expected, actual map[string]string) bool { +func compareAnnotations(expected, actual map[string]string) bool { for expectedKey, expectedValue := range expected { actualValue, found := actual[expectedKey] if !found { diff --git a/pkg/controller/jenkins/configuration/base/reconcile_test.go b/pkg/controller/jenkins/configuration/base/reconcile_test.go index 0b3dd066..2b60d09f 100644 --- a/pkg/controller/jenkins/configuration/base/reconcile_test.go +++ b/pkg/controller/jenkins/configuration/base/reconcile_test.go @@ -659,7 +659,7 @@ func TestComparePodAnnotations(t *testing.T) { expectedAnnotations := map[string]string{} actualAnnotations := map[string]string{} - got := comparePodAnnotations(expectedAnnotations, actualAnnotations) + got := compareAnnotations(expectedAnnotations, actualAnnotations) assert.True(t, got) }) @@ -667,7 +667,7 @@ func TestComparePodAnnotations(t *testing.T) { expectedAnnotations := map[string]string{"one": "two"} actualAnnotations := expectedAnnotations - got := comparePodAnnotations(expectedAnnotations, actualAnnotations) + got := compareAnnotations(expectedAnnotations, actualAnnotations) assert.True(t, got) }) @@ -675,7 +675,7 @@ func TestComparePodAnnotations(t *testing.T) { expectedAnnotations := map[string]string{"one": "two"} actualAnnotations := map[string]string{"one": "two", "three": "four"} - got := comparePodAnnotations(expectedAnnotations, actualAnnotations) + got := compareAnnotations(expectedAnnotations, actualAnnotations) assert.True(t, got) }) @@ -683,7 +683,7 @@ func TestComparePodAnnotations(t *testing.T) { expectedAnnotations := map[string]string{"one": "two"} actualAnnotations := map[string]string{"three": "four"} - got := comparePodAnnotations(expectedAnnotations, actualAnnotations) + got := compareAnnotations(expectedAnnotations, actualAnnotations) assert.False(t, got) }) @@ -691,7 +691,7 @@ func TestComparePodAnnotations(t *testing.T) { expectedAnnotations := map[string]string{"one": "two"} actualAnnotations := map[string]string{"one": "three"} - got := comparePodAnnotations(expectedAnnotations, actualAnnotations) + got := compareAnnotations(expectedAnnotations, actualAnnotations) assert.False(t, got) }) @@ -699,7 +699,7 @@ func TestComparePodAnnotations(t *testing.T) { expectedAnnotations := map[string]string{"one": "two", "missing": "something"} actualAnnotations := map[string]string{"one": "three"} - got := comparePodAnnotations(expectedAnnotations, actualAnnotations) + got := compareAnnotations(expectedAnnotations, actualAnnotations) assert.False(t, got) }) diff --git a/pkg/controller/jenkins/configuration/base/resources/service_account.go b/pkg/controller/jenkins/configuration/base/resources/service_account.go index 5fc45c19..c6d0b9e1 100644 --- a/pkg/controller/jenkins/configuration/base/resources/service_account.go +++ b/pkg/controller/jenkins/configuration/base/resources/service_account.go @@ -5,8 +5,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// NewServiceAccount return kubernetes service account -func NewServiceAccount(meta metav1.ObjectMeta) *v1.ServiceAccount { +// NewServiceAccount return Kubernetes service account +func NewServiceAccount(meta metav1.ObjectMeta, annotations map[string]string) *v1.ServiceAccount { + meta.Annotations = annotations return &v1.ServiceAccount{ TypeMeta: metav1.TypeMeta{ Kind: "ServiceAccount",