feat: implement compare annotations
It allows to specify ignores values. Note that additional values are ignored anyways, this ignore annotation only handles different values or additional annotations.
This commit is contained in:
		
							parent
							
								
									94b9a2eaac
								
							
						
					
					
						commit
						a334db7ead
					
				|  | @ -3,14 +3,14 @@ package base | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"reflect" |  | ||||||
| 
 |  | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/backuprestore" | 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/backuprestore" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event" | 	"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/notifications/reason" | 	"github.com/jenkinsci/kubernetes-operator/pkg/notifications/reason" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/version" | 	"github.com/jenkinsci/kubernetes-operator/version" | ||||||
|  | 	"reflect" | ||||||
|  | 	"slices" | ||||||
| 
 | 
 | ||||||
| 	stackerr "github.com/pkg/errors" | 	stackerr "github.com/pkg/errors" | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
|  | @ -82,7 +82,7 @@ func (r *JenkinsBaseConfigurationReconciler) checkForPodRecreation(currentJenkin | ||||||
| 			currentJenkinsMasterPod.Labels, r.Configuration.Jenkins.Spec.Master.Labels)) | 			currentJenkinsMasterPod.Labels, r.Configuration.Jenkins.Spec.Master.Labels)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !compareMap(r.Configuration.Jenkins.Spec.Master.Annotations, currentJenkinsMasterPod.ObjectMeta.Annotations) { | 	if !r.compareAnnotations(currentJenkinsMasterPod) { | ||||||
| 		messages = append(messages, "Jenkins pod annotations have changed") | 		messages = append(messages, "Jenkins pod annotations have changed") | ||||||
| 		verbose = append(verbose, fmt.Sprintf("Jenkins pod annotations have changed, actual '%+v' required '%+v'", | 		verbose = append(verbose, fmt.Sprintf("Jenkins pod annotations have changed, actual '%+v' required '%+v'", | ||||||
| 			currentJenkinsMasterPod.ObjectMeta.Annotations, r.Configuration.Jenkins.Spec.Master.Annotations)) | 			currentJenkinsMasterPod.ObjectMeta.Annotations, r.Configuration.Jenkins.Spec.Master.Annotations)) | ||||||
|  | @ -146,6 +146,20 @@ func (r *JenkinsBaseConfigurationReconciler) checkForPodRecreation(currentJenkin | ||||||
| 	return reason.NewPodRestart(reason.OperatorSource, messages, verbose...) | 	return reason.NewPodRestart(reason.OperatorSource, messages, verbose...) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (r *JenkinsBaseConfigurationReconciler) compareAnnotations(currentJenkinsMasterPod corev1.Pod) bool { | ||||||
|  | 	ignoredAnnotations := r.Jenkins.Spec.Lifecycle.Ignore.IgnoredAnnotations | ||||||
|  | 	annotations := r.Configuration.Jenkins.Spec.Master.Annotations | ||||||
|  | 
 | ||||||
|  | 	res := make(map[string]string) | ||||||
|  | 	for key, val := range annotations { | ||||||
|  | 		if slices.Contains(ignoredAnnotations, key) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		res[key] = val | ||||||
|  | 	} | ||||||
|  | 	return compareMap(res, currentJenkinsMasterPod.ObjectMeta.Annotations) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsMasterPod(meta metav1.ObjectMeta) (reconcile.Result, error) { | func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsMasterPod(meta metav1.ObjectMeta) (reconcile.Result, error) { | ||||||
| 	userAndPasswordHash, err := r.calculateUserAndPasswordHash() | 	userAndPasswordHash, err := r.calculateUserAndPasswordHash() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -97,6 +97,114 @@ func TestCompareContainerVolumeMounts(t *testing.T) { | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestCompareAnnotations(t *testing.T) { | ||||||
|  | 	type testCase struct { | ||||||
|  | 		name                string | ||||||
|  | 		jenkinsAnnotations  map[string]string | ||||||
|  | 		ignoredAnnotations  []string | ||||||
|  | 		podAnnotations      map[string]string | ||||||
|  | 		expectedShouldMatch bool | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	runTest := func(t *testing.T, tc testCase) { | ||||||
|  | 
 | ||||||
|  | 		t.Run(tc.name, func(t *testing.T) { | ||||||
|  | 			jenkins := &v1alpha2.Jenkins{ | ||||||
|  | 				Spec: v1alpha2.JenkinsSpec{ | ||||||
|  | 					Master: v1alpha2.JenkinsMaster{ | ||||||
|  | 						Annotations: tc.jenkinsAnnotations, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if len(tc.ignoredAnnotations) > 0 { | ||||||
|  | 				jenkins.Spec.Lifecycle = v1alpha2.JenkinsLifecycle{ | ||||||
|  | 					Ignore: v1alpha2.JenkinsLifecycleIgnore{ | ||||||
|  | 						IgnoredAnnotations: tc.ignoredAnnotations, | ||||||
|  | 					}, | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			pod := corev1.Pod{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 					Annotations: tc.podAnnotations, | ||||||
|  | 				}, | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			reconciler := New(configuration.Configuration{Jenkins: jenkins}, client.JenkinsAPIConnectionSettings{}) | ||||||
|  | 			result := reconciler.compareAnnotations(pod) | ||||||
|  | 
 | ||||||
|  | 			assert.Equal(t, tc.expectedShouldMatch, result, | ||||||
|  | 				"Expected compareAnnotations to return %v but got %v", tc.expectedShouldMatch, result) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	testCases := []testCase{ | ||||||
|  | 		{ | ||||||
|  | 			name:                "no annotation - additional annotations - not different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{}, | ||||||
|  | 			ignoredAnnotations:  nil, | ||||||
|  | 			podAnnotations:      map[string]string{"one": "two"}, | ||||||
|  | 			expectedShouldMatch: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:                "one additional annotation - change not ignored - not different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{"one": "two"}, | ||||||
|  | 			ignoredAnnotations:  nil, | ||||||
|  | 			podAnnotations:      map[string]string{"one": "two", "additional": "annotation"}, | ||||||
|  | 			expectedShouldMatch: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 
 | ||||||
|  | 			name:                "annotations different - different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{"one": "two"}, | ||||||
|  | 			ignoredAnnotations:  nil, | ||||||
|  | 			podAnnotations:      map[string]string{"two": "three"}, | ||||||
|  | 			expectedShouldMatch: false, | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		{ | ||||||
|  | 			name:                "annotations different - ignored - not different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{"one": "two"}, | ||||||
|  | 			ignoredAnnotations:  []string{"one"}, | ||||||
|  | 			podAnnotations:      map[string]string{"two": "three"}, | ||||||
|  | 			expectedShouldMatch: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:                "one annotation different - change not ignored - different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{"one": "two"}, | ||||||
|  | 			ignoredAnnotations:  nil, | ||||||
|  | 			podAnnotations:      map[string]string{"one": "different"}, | ||||||
|  | 			expectedShouldMatch: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:                "one annotation different - change ignored - not different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{"one": "two"}, | ||||||
|  | 			ignoredAnnotations:  []string{"one"}, | ||||||
|  | 			podAnnotations:      map[string]string{"one": "different"}, | ||||||
|  | 			expectedShouldMatch: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:                "one additional annotation - different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{"one": "two", "ignore": "me"}, | ||||||
|  | 			ignoredAnnotations:  nil, | ||||||
|  | 			podAnnotations:      map[string]string{"one": "two", "ignore": "this"}, | ||||||
|  | 			expectedShouldMatch: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:                "one additional annotation - change ignored - not different", | ||||||
|  | 			jenkinsAnnotations:  map[string]string{"one": "two", "ignore": "me"}, | ||||||
|  | 			ignoredAnnotations:  []string{"ignore"}, | ||||||
|  | 			podAnnotations:      map[string]string{"one": "two", "ignore": "this"}, | ||||||
|  | 			expectedShouldMatch: true, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, tc := range testCases { | ||||||
|  | 		runTest(t, tc) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestCompareVolumes(t *testing.T) { | func TestCompareVolumes(t *testing.T) { | ||||||
| 	t.Run("defaults", func(t *testing.T) { | 	t.Run("defaults", func(t *testing.T) { | ||||||
| 		jenkins := &v1alpha2.Jenkins{} | 		jenkins := &v1alpha2.Jenkins{} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue