Fix calculating hash for user/base configuration

This commit is contained in:
Tomasz Sęk 2019-01-11 07:56:03 +01:00
parent f8190d61ce
commit 516418f97f
No known key found for this signature in database
GPG Key ID: DC356D23F6A644D0
6 changed files with 56 additions and 72 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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) {

View File

@ -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
}

View File

@ -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()
`

View File

@ -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/>