Fix calculating hash for user/base configuration
This commit is contained in:
		
							parent
							
								
									f8190d61ce
								
							
						
					
					
						commit
						516418f97f
					
				
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								Makefile
								
								
								
								
							|  | @ -328,7 +328,7 @@ deepcopy-gen: ## Generate deepcopy golang code | |||
| start-minikube: ## Start minikube
 | ||||
| 	@echo "+ $@" | ||||
| 	@minikube status && exit 0 || \
 | ||||
| 	minikube start --kubernetes-version $(MINIKUBE_KUBERNETES_VERSION) --vm-driver=$(MINIKUBE_DRIVER) --memory 2048 | ||||
| 	minikube start --kubernetes-version $(MINIKUBE_KUBERNETES_VERSION) --vm-driver=$(MINIKUBE_DRIVER) --memory 4096 | ||||
| 
 | ||||
| .PHONY: bump-version | ||||
| BUMP := patch | ||||
|  |  | |||
|  | @ -2,11 +2,8 @@ package base | |||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/sha256" | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"time" | ||||
| 
 | ||||
| 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | ||||
|  | @ -35,7 +32,7 @@ const ( | |||
| 
 | ||||
| // ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration
 | ||||
| type ReconcileJenkinsBaseConfiguration struct { | ||||
| 	client          client.Client | ||||
| 	k8sClient       client.Client | ||||
| 	scheme          *runtime.Scheme | ||||
| 	logger          logr.Logger | ||||
| 	jenkins         *virtuslabv1alpha1.Jenkins | ||||
|  | @ -46,12 +43,12 @@ type ReconcileJenkinsBaseConfiguration struct { | |||
| func New(client client.Client, scheme *runtime.Scheme, logger logr.Logger, | ||||
| 	jenkins *virtuslabv1alpha1.Jenkins, local, minikube bool) *ReconcileJenkinsBaseConfiguration { | ||||
| 	return &ReconcileJenkinsBaseConfiguration{ | ||||
| 		client:   client, | ||||
| 		scheme:   scheme, | ||||
| 		logger:   logger, | ||||
| 		jenkins:  jenkins, | ||||
| 		local:    local, | ||||
| 		minikube: minikube, | ||||
| 		k8sClient: client, | ||||
| 		scheme:    scheme, | ||||
| 		logger:    logger, | ||||
| 		jenkins:   jenkins, | ||||
| 		local:     local, | ||||
| 		minikube:  minikube, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -128,7 +125,7 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (*reconcile.Result, jenk | |||
| 		if err != nil { | ||||
| 			return &reconcile.Result{}, nil, err | ||||
| 		} | ||||
| 		if err := r.client.Delete(context.TODO(), currentJenkinsMasterPod); err != nil { | ||||
| 		if err := r.k8sClient.Delete(context.TODO(), currentJenkinsMasterPod); err != nil { | ||||
| 			return &reconcile.Result{}, nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | @ -180,7 +177,7 @@ func isPluginInstalled(plugins *gojenkins.Plugins, requiredPlugin plugin.Plugin) | |||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error { | ||||
| 	found := &corev1.Secret{} | ||||
| 	err := r.client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, found) | ||||
| 	err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, found) | ||||
| 
 | ||||
| 	if err != nil && apierrors.IsNotFound(err) { | ||||
| 		return r.createResource(resources.NewOperatorCredentialsSecret(meta, r.jenkins)) | ||||
|  | @ -222,9 +219,9 @@ func (r *ReconcileJenkinsBaseConfiguration) createBaseConfigurationConfigMap(met | |||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) createUserConfigurationConfigMap(meta metav1.ObjectMeta) error { | ||||
| 	currentConfigMap := &corev1.ConfigMap{} | ||||
| 	err := r.client.Get(context.TODO(), types.NamespacedName{Name: resources.GetUserConfigurationConfigMapName(r.jenkins), Namespace: r.jenkins.Namespace}, currentConfigMap) | ||||
| 	err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: resources.GetUserConfigurationConfigMapName(r.jenkins), Namespace: r.jenkins.Namespace}, currentConfigMap) | ||||
| 	if err != nil && errors.IsNotFound(err) { | ||||
| 		return r.client.Create(context.TODO(), resources.NewUserConfigurationConfigMap(meta, r.jenkins)) | ||||
| 		return r.k8sClient.Create(context.TODO(), resources.NewUserConfigurationConfigMap(meta, r.jenkins)) | ||||
| 	} else if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -267,7 +264,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createService(meta metav1.ObjectMeta | |||
| func (r *ReconcileJenkinsBaseConfiguration) getJenkinsMasterPod(meta metav1.ObjectMeta) (*corev1.Pod, error) { | ||||
| 	jenkinsMasterPod := resources.NewJenkinsMasterPod(meta, r.jenkins) | ||||
| 	currentJenkinsMasterPod := &corev1.Pod{} | ||||
| 	err := r.client.Get(context.TODO(), types.NamespacedName{Name: jenkinsMasterPod.Name, Namespace: jenkinsMasterPod.Namespace}, currentJenkinsMasterPod) | ||||
| 	err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: jenkinsMasterPod.Name, Namespace: jenkinsMasterPod.Namespace}, currentJenkinsMasterPod) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -324,7 +321,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createJenkinsMasterPod(meta metav1.O | |||
| 
 | ||||
| 	if currentJenkinsMasterPod != nil && recreatePod && currentJenkinsMasterPod.ObjectMeta.DeletionTimestamp == nil { | ||||
| 		r.logger.Info(fmt.Sprintf("Terminating Jenkins Master Pod %s/%s", currentJenkinsMasterPod.Namespace, currentJenkinsMasterPod.Name)) | ||||
| 		if err := r.client.Delete(context.TODO(), currentJenkinsMasterPod); err != nil { | ||||
| 		if err := r.k8sClient.Delete(context.TODO(), currentJenkinsMasterPod); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &reconcile.Result{Requeue: true}, nil | ||||
|  | @ -368,7 +365,7 @@ func (r *ReconcileJenkinsBaseConfiguration) getJenkinsClient(meta metav1.ObjectM | |||
| 	r.logger.V(log.VDebug).Info(fmt.Sprintf("Jenkins API URL %s", jenkinsURL)) | ||||
| 
 | ||||
| 	credentialsSecret := &corev1.Secret{} | ||||
| 	err = r.client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, credentialsSecret) | ||||
| 	err = r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, credentialsSecret) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -421,7 +418,7 @@ func (r *ReconcileJenkinsBaseConfiguration) getJenkinsClient(meta metav1.ObjectM | |||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) baseConfiguration(jenkinsClient jenkinsclient.Jenkins) (*reconcile.Result, error) { | ||||
| 	groovyClient := groovy.New(jenkinsClient, r.client, r.logger, fmt.Sprintf("%s-base-configuration", constants.OperatorName), resources.JenkinsBaseConfigurationVolumePath) | ||||
| 	groovyClient := groovy.New(jenkinsClient, r.k8sClient, r.logger, fmt.Sprintf("%s-base-configuration", constants.OperatorName), resources.JenkinsBaseConfigurationVolumePath) | ||||
| 
 | ||||
| 	err := groovyClient.ConfigureGroovyJob() | ||||
| 	if err != nil { | ||||
|  | @ -429,30 +426,16 @@ func (r *ReconcileJenkinsBaseConfiguration) baseConfiguration(jenkinsClient jenk | |||
| 	} | ||||
| 
 | ||||
| 	configuration := &corev1.ConfigMap{} | ||||
| 	namespaceName := types.NamespacedName{Namespace: r.jenkins.Namespace, Name: resources.GetUserConfigurationConfigMapName(r.jenkins)} | ||||
| 	err = r.client.Get(context.TODO(), namespaceName, configuration) | ||||
| 	if err != nil { | ||||
| 		return &reconcile.Result{}, err | ||||
| 	} | ||||
| 	hash := sha256.New() | ||||
| 
 | ||||
| 	var keys []string | ||||
| 	for key := range configuration.Data { | ||||
| 		keys = append(keys, key) | ||||
| 	} | ||||
| 	sort.Strings(keys) | ||||
| 	for _, key := range keys { | ||||
| 		hash.Write([]byte(key)) | ||||
| 		hash.Write([]byte(configuration.Data[key])) | ||||
| 	} | ||||
| 
 | ||||
| 	encodedHash := base64.URLEncoding.EncodeToString(hash.Sum(nil)) | ||||
| 
 | ||||
| 	done, err := groovyClient.EnsureGroovyJob(encodedHash, r.jenkins) | ||||
| 	namespaceName := types.NamespacedName{Namespace: r.jenkins.Namespace, Name: resources.GetBaseConfigurationConfigMapName(r.jenkins)} | ||||
| 	err = r.k8sClient.Get(context.TODO(), namespaceName, configuration) | ||||
| 	if err != nil { | ||||
| 		return &reconcile.Result{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	done, err := groovyClient.EnsureGroovyJob(configuration.Data, r.jenkins) | ||||
| 	if err != nil { | ||||
| 		return &reconcile.Result{}, err | ||||
| 	} | ||||
| 	if !done { | ||||
| 		return &reconcile.Result{Requeue: true, RequeueAfter: time.Second * 10}, nil | ||||
| 	} | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createResource(obj metav1.Object) er | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return r.client.Create(context.TODO(), runtimeObj) | ||||
| 	return r.k8sClient.Create(context.TODO(), runtimeObj) | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) updateResource(obj metav1.Object) error { | ||||
|  | @ -33,7 +33,7 @@ func (r *ReconcileJenkinsBaseConfiguration) updateResource(obj metav1.Object) er | |||
| 	// set Jenkins instance as the owner and controller, don't check error(can be already set)
 | ||||
| 	_ = controllerutil.SetControllerReference(r.jenkins, obj, r.scheme) | ||||
| 
 | ||||
| 	return r.client.Update(context.TODO(), runtimeObj) | ||||
| 	return r.k8sClient.Update(context.TODO(), runtimeObj) | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) createOrUpdateResource(obj metav1.Object) error { | ||||
|  | @ -45,7 +45,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createOrUpdateResource(obj metav1.Ob | |||
| 	// set Jenkins instance as the owner and controller, don't check error(can be already set)
 | ||||
| 	_ = controllerutil.SetControllerReference(r.jenkins, obj, r.scheme) | ||||
| 
 | ||||
| 	err := r.client.Create(context.TODO(), runtimeObj) | ||||
| 	err := r.k8sClient.Create(context.TODO(), runtimeObj) | ||||
| 	if err != nil && errors.IsAlreadyExists(err) { | ||||
| 		return r.updateResource(obj) | ||||
| 	} else if err != nil && !errors.IsAlreadyExists(err) { | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package user | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| 
 | ||||
|  | @ -8,12 +9,13 @@ import ( | |||
| 	jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" | ||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/base/resources" | ||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user/seedjobs" | ||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user/theme" | ||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" | ||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/groovy" | ||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/jobs" | ||||
| 
 | ||||
| 	"github.com/go-logr/logr" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	k8s "sigs.k8s.io/controller-runtime/pkg/client" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||||
| ) | ||||
|  | @ -78,7 +80,14 @@ func (r *ReconcileUserConfiguration) userConfiguration(jenkinsClient jenkinsclie | |||
| 		return &reconcile.Result{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	done, err := groovyClient.EnsureGroovyJob(theme.SetThemeGroovyScript, r.jenkins) | ||||
| 	configuration := &corev1.ConfigMap{} | ||||
| 	namespaceName := types.NamespacedName{Namespace: r.jenkins.Namespace, Name: resources.GetUserConfigurationConfigMapName(r.jenkins)} | ||||
| 	err = r.k8sClient.Get(context.TODO(), namespaceName, configuration) | ||||
| 	if err != nil { | ||||
| 		return &reconcile.Result{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	done, err := groovyClient.EnsureGroovyJob(configuration.Data, r.jenkins) | ||||
| 	if err != nil { | ||||
| 		return &reconcile.Result{}, err | ||||
| 	} | ||||
|  |  | |||
|  | @ -1,25 +0,0 @@ | |||
| package theme | ||||
| 
 | ||||
| // SetThemeGroovyScript it's a groovy script which set custom jenkins theme
 | ||||
| // TODO move to base configuration
 | ||||
| var SetThemeGroovyScript = ` | ||||
| import jenkins.* | ||||
| import jenkins.model.* | ||||
| import hudson.* | ||||
| import hudson.model.* | ||||
| import org.jenkinsci.plugins.simpletheme.ThemeElement | ||||
| import org.jenkinsci.plugins.simpletheme.CssTextThemeElement | ||||
| import org.jenkinsci.plugins.simpletheme.CssUrlThemeElement | ||||
| 
 | ||||
| Jenkins jenkins = Jenkins.getInstance() | ||||
| 
 | ||||
| def decorator = Jenkins.instance.getDescriptorByType(org.codefirst.SimpleThemeDecorator.class) | ||||
| 
 | ||||
| List<ThemeElement> configElements = new ArrayList<>(); | ||||
| configElements.add(new CssTextThemeElement("DEFAULT")); | ||||
| configElements.add(new CssUrlThemeElement("https://cdn.rawgit.com/afonsof/jenkins-material-theme/gh-pages/dist/material-light-green.css")); | ||||
| decorator.setElements(configElements); | ||||
| decorator.save(); | ||||
| 
 | ||||
| jenkins.save() | ||||
| ` | ||||
|  | @ -1,7 +1,10 @@ | |||
| package groovy | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/sha256" | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
| 
 | ||||
| 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | ||||
| 	jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" | ||||
|  | @ -41,17 +44,31 @@ func (g *Groovy) ConfigureGroovyJob() error { | |||
| } | ||||
| 
 | ||||
| // EnsureGroovyJob executes groovy script and verifies jenkins job status according to reconciliation loop lifecycle
 | ||||
| // see https://wiki.jenkins.io/display/JENKINS/Jenkins+Script+Console
 | ||||
| func (g *Groovy) EnsureGroovyJob(hash string, jenkins *virtuslabv1alpha1.Jenkins) (bool, error) { | ||||
| func (g *Groovy) EnsureGroovyJob(secretOrConfigMapData map[string]string, jenkins *virtuslabv1alpha1.Jenkins) (bool, error) { | ||||
| 	jobsClient := jobs.New(g.jenkinsClient, g.k8sClient, g.logger) | ||||
| 
 | ||||
| 	done, err := jobsClient.EnsureBuildJob(g.jobName, hash, map[string]string{}, jenkins, true) | ||||
| 	done, err := jobsClient.EnsureBuildJob(g.jobName, g.calculateHash(secretOrConfigMapData), map[string]string{}, jenkins, true) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	return done, nil | ||||
| } | ||||
| 
 | ||||
| func (g *Groovy) calculateHash(secretOrConfigMapData map[string]string) string { | ||||
| 	hash := sha256.New() | ||||
| 
 | ||||
| 	var keys []string | ||||
| 	for key := range secretOrConfigMapData { | ||||
| 		keys = append(keys, key) | ||||
| 	} | ||||
| 	sort.Strings(keys) | ||||
| 	for _, key := range keys { | ||||
| 		hash.Write([]byte(key)) | ||||
| 		hash.Write([]byte(secretOrConfigMapData[key])) | ||||
| 	} | ||||
| 	return base64.URLEncoding.EncodeToString(hash.Sum(nil)) | ||||
| } | ||||
| 
 | ||||
| const configurationJobXMLFmt = `<?xml version='1.1' encoding='UTF-8'?> | ||||
| <flow-definition plugin="workflow-job@2.25"> | ||||
|   <actions/> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue