Merge pull request #479 from SylwiaBrant/xmas-fix
Grand Christmas Patch
This commit is contained in:
		
						commit
						d6b10c6e0f
					
				
							
								
								
									
										4
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										4
									
								
								Makefile
								
								
								
								
							|  | @ -66,7 +66,7 @@ PACKAGES_FOR_UNIT_TESTS = $(shell go list -f '{{.ImportPath}}/' ./... | grep -v | |||
| E2E_TEST_SELECTOR ?= .* | ||||
| 
 | ||||
| JENKINS_API_HOSTNAME := $(shell $(JENKINS_API_HOSTNAME_COMMAND) 2> /dev/null || echo "" ) | ||||
| OPERATOR_ARGS ?= --jenkins-api-hostname=$(JENKINS_API_HOSTNAME) --jenkins-api-port=$(JENKINS_API_PORT) --jenkins-api-use-nodeport=$(JENKINS_API_USE_NODEPORT) $(OPERATOR_EXTRA_ARGS) | ||||
| OPERATOR_ARGS ?= --jenkins-api-hostname=$(JENKINS_API_HOSTNAME) --jenkins-api-port=$(JENKINS_API_PORT) --jenkins-api-use-nodeport=$(JENKINS_API_USE_NODEPORT) --cluster-domain=$(CLUSTER_DOMAIN) $(OPERATOR_EXTRA_ARGS) | ||||
| 
 | ||||
| .DEFAULT_GOAL := help | ||||
| 
 | ||||
|  | @ -422,7 +422,7 @@ endif | |||
| minikube-start: check-minikube ## Start minikube
 | ||||
| 	@echo "+ $@" | ||||
| 	@minikube status && exit 0 || \
 | ||||
| 	minikube start --kubernetes-version $(MINIKUBE_KUBERNETES_VERSION) --vm-driver=$(MINIKUBE_DRIVER) --memory 4096 --cpus 3 | ||||
| 	minikube start --kubernetes-version $(MINIKUBE_KUBERNETES_VERSION) --dns-domain=$(CLUSTER_DOMAIN) --extra-config=kubelet.cluster-domain=$(CLUSTER_DOMAIN) --vm-driver=$(MINIKUBE_DRIVER) --memory 4096 --cpus 3 | ||||
| 
 | ||||
| .PHONY: crc-start | ||||
| crc-start: check-crc ## Start CodeReady Containers Kubernetes cluster
 | ||||
|  |  | |||
|  | @ -98,3 +98,30 @@ rules: | |||
|       - get | ||||
|       - list | ||||
|       - watch | ||||
|   - apiGroups: | ||||
|       - "route.openshift.io" | ||||
|     resources: | ||||
|       - routes | ||||
|     verbs: | ||||
|       - get | ||||
|       - list | ||||
|       - watch | ||||
|       - create | ||||
|       - update | ||||
|   - apiGroups: | ||||
|       - "image.openshift.io" | ||||
|     resources: | ||||
|       - imagestreams | ||||
|     verbs: | ||||
|       - get | ||||
|       - list | ||||
|       - watch | ||||
|   - apiGroups: | ||||
|       - "build.openshift.io" | ||||
|     resources: | ||||
|       - builds | ||||
|       - buildconfigs | ||||
|     verbs: | ||||
|       - get | ||||
|       - list | ||||
|       - watch | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ jenkins: | |||
|   # image is the name (and tag) of the Jenkins instance | ||||
|   # Default: jenkins/jenkins:lts | ||||
|   # It's recommended to use LTS (tag: "lts") version | ||||
|   image: jenkins/jenkins:lts | ||||
|   image: jenkins/jenkins:2.249.3-lts-alpine | ||||
| 
 | ||||
|   # env contains jenkins container environment variables | ||||
|   env: [] | ||||
|  | @ -63,34 +63,34 @@ jenkins: | |||
|   # | ||||
|   # basePlugins: | ||||
|   # - name: kubernetes | ||||
|   #   version: 1.18.3 | ||||
|   #   version: 1.27.6 | ||||
|   # - name: workflow-job | ||||
|   #   version: "2.34" | ||||
|   #   version: "2.40" | ||||
|   # - name: workflow-aggregator | ||||
|   #   version: "2.6" | ||||
|   # - name: git | ||||
|   #   version: 3.12.0 | ||||
|   #   version: 4.4.5 | ||||
|   # - name: job-dsl | ||||
|   #   version: "1.76" | ||||
|   #   version: "1.77" | ||||
|   # - name: configuration-as-code | ||||
|   #   version: "1.29" | ||||
|   #   version: "1.46" | ||||
|   # - name: kubernetes-credentials-provider | ||||
|   #   version: 0.12.1 | ||||
|   #   version: 0.15 | ||||
|   basePlugins: | ||||
|     - name: kubernetes | ||||
|       version: "1.25.2" | ||||
|       version: "1.27.6" | ||||
|     - name: workflow-job | ||||
|       version: "2.39" | ||||
|       version: "2.40" | ||||
|     - name: workflow-aggregator | ||||
|       version: "2.6" | ||||
|     - name: git | ||||
|       version: "4.2.2" | ||||
|       version: "4.4.5" | ||||
|     - name: job-dsl | ||||
|       version: "1.77" | ||||
|     - name: configuration-as-code | ||||
|       version: "1.38" | ||||
|       version: "1.46" | ||||
|     - name: kubernetes-credentials-provider | ||||
|       version: "0.13" | ||||
|       version: "0.15" | ||||
| 
 | ||||
|   # plugins are plugins required by the user | ||||
|   # You can define plugins here | ||||
|  | @ -100,7 +100,7 @@ jenkins: | |||
|   # | ||||
|   # plugins: | ||||
|   # - name: simple-theme-plugin | ||||
|   #   version: 0.5.1 | ||||
|   #   version: "0.6" | ||||
|   plugins: [] | ||||
| 
 | ||||
|   # seedJobs is placeholder for jenkins seed jobs | ||||
|  | @ -159,7 +159,7 @@ jenkins: | |||
| 
 | ||||
|     # image used by backup feature | ||||
|     # By default using prebuilt backup PVC image by VirtusLab | ||||
|     image: virtuslab/jenkins-operator-backup-pvc:v0.0.8 | ||||
|     image: virtuslab/jenkins-operator-backup-pvc:v0.1.0 | ||||
| 
 | ||||
|     # containerName is backup container name | ||||
|     containerName: backup | ||||
|  | @ -178,6 +178,9 @@ jenkins: | |||
|     restoreCommand: | ||||
|       - /home/user/bin/restore.sh | ||||
| 
 | ||||
|     getLatestAction: | ||||
|       - /home/user/bin/get-latest.sh | ||||
| 
 | ||||
|     # pvc is Persistent Volume Claim Kubernetes resource | ||||
|     pvc: | ||||
|       # enabled is enable/disable switch for PVC | ||||
|  |  | |||
|  | @ -72,6 +72,7 @@ func main() { | |||
| 	port := pflag.Int("jenkins-api-port", 0, "The port on which Jenkins API is running. Note: If you want to use nodePort don't set this setting and --jenkins-api-use-nodeport must be true.") | ||||
| 	useNodePort := pflag.Bool("jenkins-api-use-nodeport", false, "Connect to Jenkins API using the service nodePort instead of service port. If you want to set this as true - don't set --jenkins-api-port.") | ||||
| 	debug := pflag.Bool("debug", false, "Set log level to debug") | ||||
| 	kubernetesClusterDomain := pflag.String("cluster-domain", "cluster.local", "Use custom domain name instead of 'cluster.local'.") | ||||
| 	pflag.Parse() | ||||
| 
 | ||||
| 	log.SetupLogger(*debug) | ||||
|  | @ -136,8 +137,13 @@ func main() { | |||
| 		fatal(errors.Wrap(err, "invalid command line parameters"), *debug) | ||||
| 	} | ||||
| 
 | ||||
| 	// validate kubernetes cluster domain
 | ||||
| 	if *kubernetesClusterDomain == "" { | ||||
| 		fatal(errors.Wrap(err, "Kubernetes cluster domain can't be empty"), *debug) | ||||
| 	} | ||||
| 
 | ||||
| 	// setup Jenkins controller
 | ||||
| 	if err := jenkins.Add(mgr, jenkinsAPIConnectionSettings, *clientSet, *cfg, &c); err != nil { | ||||
| 	if err := jenkins.Add(mgr, jenkinsAPIConnectionSettings, *kubernetesClusterDomain, *clientSet, *cfg, &c); err != nil { | ||||
| 		fatal(errors.Wrap(err, "failed to setup controllers"), *debug) | ||||
| 	} | ||||
| 	// setup JenkinsImage controller
 | ||||
|  |  | |||
|  | @ -12,3 +12,4 @@ ALL_IN_ONE_DEPLOY_FILE_PREFIX=all-in-one | |||
| GEN_CRD_API=gen-crd-api-reference-docs | ||||
| IMAGE_PULL_MODE=local | ||||
| HELM_VERSION=3.1.2 | ||||
| CLUSTER_DOMAIN=cluster.local | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ spec: | |||
|   master: | ||||
|     containers: | ||||
|     - name: jenkins-master | ||||
|       image: jenkins/jenkins:lts | ||||
|       image: jenkins/jenkins:2.249.3-lts-alpine | ||||
|       imagePullPolicy: Always | ||||
|       livenessProbe: | ||||
|         failureThreshold: 12 | ||||
|  |  | |||
|  | @ -5,20 +5,20 @@ metadata: | |||
| spec: | ||||
|   image: | ||||
|     name: jenkins/jenkins | ||||
|     tag: lts | ||||
|     tag: 2.249.3-lts-alpine | ||||
|   plugins: | ||||
|   - name: kubernetes | ||||
|     version: "1.15.7" | ||||
|     version: "1.27.6" | ||||
|   - name: workflow-job | ||||
|     version: "2.39" | ||||
|     version: "2.40" | ||||
|   - name: workflow-aggregator | ||||
|     version: "2.6" | ||||
|   - name: git | ||||
|     version: "3.10.0" | ||||
|     version: "4.4.5" | ||||
|   - name: job-dsl | ||||
|     version: "1.74" | ||||
|     version: "1.77" | ||||
|   - name: configuration-as-code | ||||
|     version: "1.19" | ||||
|     version: "1.46" | ||||
|   - name: kubernetes-credentials-provider | ||||
|     version: "0.12.1" | ||||
|     version: "0.15" | ||||
| 
 | ||||
|  |  | |||
|  | @ -626,6 +626,11 @@ type Restore struct { | |||
| 	// Action defines action which performs restore backup in restore container sidecar
 | ||||
| 	Action Handler `json:"action"` | ||||
| 
 | ||||
| 	// GetLatestAction defines action which returns the latest backup number. If there is no backup "-1" should be
 | ||||
| 	// returned.
 | ||||
| 	// +optional
 | ||||
| 	GetLatestAction Handler `json:"getLatestAction"` | ||||
| 
 | ||||
| 	// RecoveryOnce if want to restore specific backup set this field and then Jenkins will be restarted and desired backup will be restored
 | ||||
| 	// +optional
 | ||||
| 	RecoveryOnce uint64 `json:"recoveryOnce,omitempty"` | ||||
|  |  | |||
|  | @ -677,6 +677,7 @@ func (in *Plugin) DeepCopy() *Plugin { | |||
| func (in *Restore) DeepCopyInto(out *Restore) { | ||||
| 	*out = *in | ||||
| 	in.Action.DeepCopyInto(&out.Action) | ||||
| 	in.GetLatestAction.DeepCopyInto(&out.GetLatestAction) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ package backuprestore | |||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
|  | @ -12,6 +14,7 @@ import ( | |||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/log" | ||||
| 
 | ||||
| 	"github.com/go-logr/logr" | ||||
| 	"github.com/pkg/errors" | ||||
| 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	k8s "sigs.k8s.io/controller-runtime/pkg/client" | ||||
|  | @ -109,6 +112,8 @@ func (bar *BackupAndRestore) Validate() []string { | |||
| 
 | ||||
| 	return messages | ||||
| } | ||||
| // helper value indicating no saved backup
 | ||||
| const noBackup = "-1" | ||||
| 
 | ||||
| // Restore performs Jenkins restore backup operation
 | ||||
| func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error { | ||||
|  | @ -121,7 +126,8 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error | |||
| 		bar.logger.V(log.VDebug).Info("Skipping restore backup, backup already restored") | ||||
| 		return nil | ||||
| 	} | ||||
| 	if jenkins.Status.LastBackup == 0 { | ||||
| 
 | ||||
| 	if jenkins.Status.LastBackup == 0 && jenkins.Spec.Restore.GetLatestAction.Exec == nil { | ||||
| 		bar.logger.V(log.VDebug).Info("Skipping restore backup") | ||||
| 		if jenkins.Status.PendingBackup == 0 { | ||||
| 			jenkins.Status.PendingBackup = 1 | ||||
|  | @ -130,14 +136,40 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error | |||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	var backupNumber uint64 | ||||
| 	podName := resources.GetJenkinsMasterPodName(jenkins) | ||||
| 	var backupNumber = jenkins.Status.LastBackup | ||||
| 
 | ||||
| 	if jenkins.Spec.Restore.GetLatestAction.Exec != nil { | ||||
| 		command := jenkins.Spec.Restore.GetLatestAction.Exec.Command | ||||
| 		backupNumberRaw, _, err := bar.Exec(podName, jenkins.Spec.Restore.ContainerName, command) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		backupNumberString := strings.TrimSuffix(backupNumberRaw.String(), "\n") | ||||
| 		if backupNumberString == noBackup { | ||||
| 			bar.logger.V(log.VDebug).Info("Skipping restore backup, get latest action returned -1") | ||||
| 			jenkins.Status.LastBackup = 0 | ||||
| 			jenkins.Status.PendingBackup = 1 | ||||
| 			return bar.Client.Update(context.TODO(), jenkins) | ||||
| 		} | ||||
| 
 | ||||
| 		backupNumber, err = strconv.ParseUint(backupNumberString, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrapf(err, "invalid backup number '%s' returned by get last backup number action", backupNumberString) | ||||
| 		} | ||||
| 
 | ||||
| 		if backupNumber < 1 { | ||||
| 			return errors.Errorf("invalid backup number '%d' returned by get last backup number action", backupNumber) | ||||
| 		} | ||||
| 	} else { | ||||
| 		bar.logger.V(log.VWarn).Info("spec.restore.getLatestAction not set, you may loose backup history when Jenkins CR status will be clear") | ||||
| 	} | ||||
| 
 | ||||
| 	if jenkins.Spec.Restore.RecoveryOnce != 0 { | ||||
| 		backupNumber = jenkins.Spec.Restore.RecoveryOnce | ||||
| 	} else { | ||||
| 		backupNumber = jenkins.Status.LastBackup | ||||
| 	} | ||||
| 	bar.logger.Info(fmt.Sprintf("Restoring backup '%d'", backupNumber)) | ||||
| 	podName := resources.GetJenkinsMasterPodName(jenkins) | ||||
| 	command := jenkins.Spec.Restore.Action.Exec.Command | ||||
| 	command = append(command, fmt.Sprintf("%d", backupNumber)) | ||||
| 	_, _, err := bar.Exec(podName, jenkins.Spec.Restore.ContainerName, command) | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(met | |||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error { | ||||
| 	configMap, err := resources.NewBaseConfigurationConfigMap(meta, r.Configuration.Jenkins) | ||||
| 	configMap, err := resources.NewBaseConfigurationConfigMap(meta, r.Configuration.Jenkins, r.KubernetesClusterDomain) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  |  | |||
|  | @ -126,7 +126,7 @@ if (kubernetes == null) { | |||
|     add = true | ||||
| 	kubernetes = new KubernetesCloud("kubernetes") | ||||
| } | ||||
| kubernetes.setServerUrl("https://kubernetes.default.svc.cluster.local:443") | ||||
| kubernetes.setServerUrl("https://kubernetes.default.svc.%s:443") | ||||
| kubernetes.setNamespace("%s") | ||||
| kubernetes.setJenkinsUrl("%s") | ||||
| kubernetes.setJenkinsTunnel("%s") | ||||
|  | @ -178,16 +178,24 @@ func GetBaseConfigurationConfigMapName(jenkins *v1alpha2.Jenkins) string { | |||
| } | ||||
| 
 | ||||
| // NewBaseConfigurationConfigMap builds Kubernetes config map used to base configuration.
 | ||||
| func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha2.Jenkins) (*corev1.ConfigMap, error) { | ||||
| func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha2.Jenkins, kubernetesClusterDomain string) (*corev1.ConfigMap, error) { | ||||
| 	meta.Name = GetBaseConfigurationConfigMapName(jenkins) | ||||
| 	jenkinsServiceFQDN, err := GetJenkinsHTTPServiceFQDN(jenkins) | ||||
| 	clusterDomain, err := getClusterDomain(kubernetesClusterDomain) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	jenkinsSlavesServiceFQDN, err := GetJenkinsSlavesServiceFQDN(jenkins) | ||||
| 	jenkinsServiceFQDN, err := GetJenkinsHTTPServiceFQDN(jenkins, kubernetesClusterDomain) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	jenkinsSlavesServiceFQDN, err := GetJenkinsSlavesServiceFQDN(jenkins, kubernetesClusterDomain) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	suffix := "" | ||||
| 	if prefix, ok := GetJenkinsOpts(*jenkins)["prefix"]; ok { | ||||
| 		suffix = prefix | ||||
| 	} | ||||
| 	groovyScriptsMap := map[string]string{ | ||||
| 		basicSettingsGroovyScriptName:             fmt.Sprintf(basicSettingsFmt, constants.DefaultAmountOfExecutors), | ||||
| 		enableCSRFGroovyScriptName:                enableCSRF, | ||||
|  | @ -195,13 +203,15 @@ func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha2.Jen | |||
| 		enableMasterAccessControlGroovyScriptName: enableMasterAccessControl, | ||||
| 		disableInsecureFeaturesGroovyScriptName:   disableInsecureFeatures, | ||||
| 		configureKubernetesPluginGroovyScriptName: fmt.Sprintf(configureKubernetesPluginFmt, | ||||
| 			clusterDomain, | ||||
| 			jenkins.ObjectMeta.Namespace, | ||||
| 			fmt.Sprintf("http://%s:%d", jenkinsServiceFQDN, jenkins.Spec.Service.Port), | ||||
| 			fmt.Sprintf("http://%s:%d%s", jenkinsServiceFQDN, jenkins.Spec.Service.Port, suffix), | ||||
| 			fmt.Sprintf("%s:%d", jenkinsSlavesServiceFQDN, jenkins.Spec.SlaveService.Port), | ||||
| 		), | ||||
| 		configureViewsGroovyScriptName:              configureViews, | ||||
| 		disableJobDslScriptApprovalGroovyScriptName: disableJobDSLScriptApproval, | ||||
| 	} | ||||
| 
 | ||||
| 	if jenkins.Spec.Master.DisableCSRFProtection { | ||||
| 		delete(groovyScriptsMap, enableCSRFGroovyScriptName) | ||||
| 	} | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package resources | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/constants" | ||||
|  | @ -16,7 +17,7 @@ const ( | |||
| 	// JenkinsHomeVolumeName is the Jenkins home volume name
 | ||||
| 	JenkinsHomeVolumeName    = "jenkins-home" | ||||
| 	jenkinsPath              = "/var/jenkins" | ||||
| 
 | ||||
| 	httpGetPath              = "/login" | ||||
| 	jenkinsScriptsVolumeName = "scripts" | ||||
| 	// JenkinsScriptsVolumePath is a path where are scripts used to configure Jenkins
 | ||||
| 	JenkinsScriptsVolumePath = jenkinsPath + "/scripts" | ||||
|  | @ -233,6 +234,8 @@ func NewJenkinsMasterContainer(jenkins *v1alpha2.Jenkins) corev1.Container { | |||
| 		envs = append(envs, jenkinsHomeEnvVar) | ||||
| 	} | ||||
| 
 | ||||
| 	setLivenessAndReadinessPath(jenkins) | ||||
| 
 | ||||
| 	return corev1.Container{ | ||||
| 		Name:            JenkinsMasterContainerName, | ||||
| 		Image:           jenkinsContainer.Image, | ||||
|  | @ -259,6 +262,53 @@ func NewJenkinsMasterContainer(jenkins *v1alpha2.Jenkins) corev1.Container { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func setLivenessAndReadinessPath(jenkins *v1alpha2.Jenkins) { | ||||
| 	ReadinessProbePath := jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path | ||||
| 	LivenessProbePath := jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path | ||||
| 
 | ||||
| 	if prefix, ok := GetJenkinsOpts(*jenkins)["prefix"]; ok { | ||||
| 		if !strings.HasPrefix(ReadinessProbePath, prefix) { | ||||
| 			jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path = prefix + httpGetPath | ||||
| 		} | ||||
| 		if !strings.HasPrefix(LivenessProbePath, prefix) { | ||||
| 			jenkins.Spec.Master.Containers[0].LivenessProbe.HTTPGet.Path = prefix + httpGetPath | ||||
| 		} | ||||
| 	} else { | ||||
| 		if ReadinessProbePath != httpGetPath { | ||||
| 			jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path = httpGetPath | ||||
| 		} | ||||
| 		if LivenessProbePath != httpGetPath { | ||||
| 			jenkins.Spec.Master.Containers[0].LivenessProbe.HTTPGet.Path = httpGetPath | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetJenkinsOpts gets JENKINS_OPTS env parameter, parses it's values and returns it as a map`
 | ||||
| func GetJenkinsOpts(jenkins v1alpha2.Jenkins) map[string]string { | ||||
| 	envs := jenkins.Spec.Master.Containers[0].Env | ||||
| 	jenkinsOpts := make(map[string]string) | ||||
| 
 | ||||
| 	for key, value := range envs { | ||||
| 		if value.Name == "JENKINS_OPTS" { | ||||
| 			jenkinsOptsEnv := envs[key] | ||||
| 			jenkinsOptsWithDashes := jenkinsOptsEnv.Value | ||||
| 			if len(jenkinsOptsWithDashes) == 0 { | ||||
| 				return nil | ||||
| 			} | ||||
| 
 | ||||
| 			jenkinsOptsWithEqOperators := strings.Split(jenkinsOptsWithDashes, " ") | ||||
| 
 | ||||
| 			for _, vx := range jenkinsOptsWithEqOperators { | ||||
| 				opt := strings.Split(vx, "=") | ||||
| 				jenkinsOpts[strings.ReplaceAll(opt[0], "--", "")] = opt[1] | ||||
| 			} | ||||
| 
 | ||||
| 			return jenkinsOpts | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ConvertJenkinsContainerToKubernetesContainer converts Jenkins container to Kubernetes container
 | ||||
| func ConvertJenkinsContainerToKubernetesContainer(container v1alpha2.Container) corev1.Container { | ||||
| 	return corev1.Container{ | ||||
|  |  | |||
|  | @ -0,0 +1,229 @@ | |||
| package resources | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 
 | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| ) | ||||
| 
 | ||||
| var jenkins = v1alpha2.Jenkins{ | ||||
| 	Spec: v1alpha2.JenkinsSpec{ | ||||
| 		Master: v1alpha2.JenkinsMaster{ | ||||
| 			Containers: []v1alpha2.Container{ | ||||
| 				{ | ||||
| 					Env: []corev1.EnvVar{}, | ||||
| 					ReadinessProbe: &corev1.Probe{ | ||||
| 						Handler: corev1.Handler{ | ||||
| 							HTTPGet: &corev1.HTTPGetAction{}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					LivenessProbe: &corev1.Probe{ | ||||
| 						Handler: corev1.Handler{ | ||||
| 							HTTPGet: &corev1.HTTPGetAction{}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| func TestGetJenkinsOpts(t *testing.T) { | ||||
| 	t.Run("JENKINS_OPTS is uninitialized", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "", Value: ""}, | ||||
| 			} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 		assert.Equal(t, 0, len(opts)) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS is empty", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "JENKINS_OPTS", Value: ""}, | ||||
| 			} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 		assert.Equal(t, 0, len(opts)) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --prefix argument ", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins"}, | ||||
| 			} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 1, len(opts)) | ||||
| 		assert.NotContains(t, opts, "httpPort") | ||||
| 		assert.Contains(t, opts, "prefix") | ||||
| 		assert.Equal(t, opts["prefix"], "/jenkins") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --prefix and --httpPort argument", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins --httpPort=8080"}, | ||||
| 			} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 2, len(opts)) | ||||
| 
 | ||||
| 		assert.Contains(t, opts, "prefix") | ||||
| 		assert.Equal(t, opts["prefix"], "/jenkins") | ||||
| 
 | ||||
| 		assert.Contains(t, opts, "httpPort") | ||||
| 		assert.Equal(t, opts["httpPort"], "8080") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --httpPort argument", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "JENKINS_OPTS", Value: "--httpPort=8080"}, | ||||
| 			} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 1, len(opts)) | ||||
| 		assert.NotContains(t, opts, "prefix") | ||||
| 		assert.Contains(t, opts, "httpPort") | ||||
| 		assert.Equal(t, opts["httpPort"], "8080") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --httpPort=--8080 argument", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "JENKINS_OPTS", Value: "--httpPort=--8080"}, | ||||
| 			} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 1, len(opts)) | ||||
| 		assert.NotContains(t, opts, "prefix") | ||||
| 		assert.Contains(t, opts, "httpPort") | ||||
| 		assert.Equal(t, opts["httpPort"], "--8080") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestSetLivenessAndReadinessPath(t *testing.T) { | ||||
| 	t.Run("JENKINS_OPTS uninitialized. Probes' paths default.", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = []corev1.EnvVar{} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].ReadinessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].LivenessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		setLivenessAndReadinessPath(&jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, httpGetPath, jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path) | ||||
| 		assert.Equal(t, httpGetPath, jenkins.Spec.Master.Containers[0].LivenessProbe.HTTPGet.Path) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS initialized. Probes' paths default", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins"}, | ||||
| 			} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].ReadinessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].LivenessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		setLivenessAndReadinessPath(&jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, "/jenkins/login", jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path) | ||||
| 		assert.Equal(t, "/jenkins/login", jenkins.Spec.Master.Containers[0].LivenessProbe.HTTPGet.Path) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS initialized. Probes' paths customized", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = | ||||
| 			[]corev1.EnvVar{ | ||||
| 				{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins"}, | ||||
| 			} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].ReadinessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/jenkins/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].LivenessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/jenkins/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		setLivenessAndReadinessPath(&jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, "/jenkins/login", jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path) | ||||
| 		assert.Equal(t, "/jenkins/login", jenkins.Spec.Master.Containers[0].LivenessProbe.HTTPGet.Path) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS uninitialized. Probes' paths customized", func(t *testing.T) { | ||||
| 		jenkins.Spec.Master.Containers[0].Env = []corev1.EnvVar{} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].ReadinessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/jenkins/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		jenkins.Spec.Master.Containers[0].LivenessProbe = | ||||
| 			&corev1.Probe{ | ||||
| 				Handler: corev1.Handler{ | ||||
| 					HTTPGet: &corev1.HTTPGetAction{ | ||||
| 						Path: "/jenkins/login", | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 		setLivenessAndReadinessPath(&jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, "/login", jenkins.Spec.Master.Containers[0].ReadinessProbe.HTTPGet.Path) | ||||
| 		assert.Equal(t, "/login", jenkins.Spec.Master.Containers[0].LivenessProbe.HTTPGet.Path) | ||||
| 	}) | ||||
| } | ||||
|  | @ -50,8 +50,8 @@ func GetJenkinsSlavesServiceName(jenkins *v1alpha2.Jenkins) string { | |||
| } | ||||
| 
 | ||||
| // GetJenkinsHTTPServiceFQDN returns Kubernetes service FQDN used for expose Jenkins HTTP endpoint
 | ||||
| func GetJenkinsHTTPServiceFQDN(jenkins *v1alpha2.Jenkins) (string, error) { | ||||
| 	clusterDomain, err := getClusterDomain() | ||||
| func GetJenkinsHTTPServiceFQDN(jenkins *v1alpha2.Jenkins, kubernetesClusterDomain string) (string, error) { | ||||
| 	clusterDomain, err := getClusterDomain(kubernetesClusterDomain) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | @ -60,8 +60,8 @@ func GetJenkinsHTTPServiceFQDN(jenkins *v1alpha2.Jenkins) (string, error) { | |||
| } | ||||
| 
 | ||||
| // GetJenkinsSlavesServiceFQDN returns Kubernetes service FQDN used for expose Jenkins slave endpoint
 | ||||
| func GetJenkinsSlavesServiceFQDN(jenkins *v1alpha2.Jenkins) (string, error) { | ||||
| 	clusterDomain, err := getClusterDomain() | ||||
| func GetJenkinsSlavesServiceFQDN(jenkins *v1alpha2.Jenkins, kubernetesClusterDomain string) (string, error) { | ||||
| 	clusterDomain, err := getClusterDomain(kubernetesClusterDomain) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | @ -70,12 +70,12 @@ func GetJenkinsSlavesServiceFQDN(jenkins *v1alpha2.Jenkins) (string, error) { | |||
| } | ||||
| 
 | ||||
| // GetClusterDomain returns Kubernetes cluster domain, default to "cluster.local"
 | ||||
| func getClusterDomain() (string, error) { | ||||
| 	clusterDomain := "cluster.local" | ||||
| 
 | ||||
| 	if ok, err := isRunningInCluster(); !ok { | ||||
| 		return clusterDomain, nil | ||||
| 	} else if err != nil { | ||||
| func getClusterDomain(kubernetesClusterDomain string) (string, error) { | ||||
| 	isRunningInCluster, err := isRunningInCluster() | ||||
| 	if !isRunningInCluster { | ||||
| 		return kubernetesClusterDomain, nil | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 
 | ||||
|  | @ -86,11 +86,11 @@ func getClusterDomain() (string, error) { | |||
| 		return "", stackerr.WithStack(err) | ||||
| 	} | ||||
| 
 | ||||
| 	clusterDomain = strings.TrimPrefix(cname, "kubernetes.default.svc") | ||||
| 	clusterDomain = strings.TrimPrefix(clusterDomain, ".") | ||||
| 	clusterDomain = strings.TrimSuffix(clusterDomain, ".") | ||||
| 	kubernetesClusterDomain = strings.TrimPrefix(cname, "kubernetes.default.svc") | ||||
| 	kubernetesClusterDomain = strings.TrimPrefix(kubernetesClusterDomain, ".") | ||||
| 	kubernetesClusterDomain = strings.TrimSuffix(kubernetesClusterDomain, ".") | ||||
| 
 | ||||
| 	return clusterDomain, nil | ||||
| 	return kubernetesClusterDomain, nil | ||||
| } | ||||
| 
 | ||||
| func isRunningInCluster() (bool, error) { | ||||
|  | @ -99,7 +99,7 @@ func isRunningInCluster() (bool, error) { | |||
| 		if err == k8sutil.ErrNoNamespace || err == k8sutil.ErrRunLocal { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 		return true, nil | ||||
| 	} | ||||
| 		return false, stackerr.WithStack(err) | ||||
| 	} | ||||
| 	return true, nil | ||||
| } | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ type Configuration struct { | |||
| 	Scheme                       *runtime.Scheme | ||||
| 	Config                       *rest.Config | ||||
| 	JenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings | ||||
| 	KubernetesClusterDomain      string | ||||
| } | ||||
| 
 | ||||
| // RestartJenkinsMasterPod terminate Jenkins master pod and notifies about it.
 | ||||
|  |  | |||
|  | @ -1,144 +0,0 @@ | |||
| package configuration | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| ) | ||||
| 
 | ||||
| func TestGetJenkinsOpts(t *testing.T) { | ||||
| 	t.Run("JENKINS_OPTS is uninitialized", func(t *testing.T) { | ||||
| 		jenkins := v1alpha2.Jenkins{ | ||||
| 			Spec: v1alpha2.JenkinsSpec{ | ||||
| 				Master: v1alpha2.JenkinsMaster{ | ||||
| 					Containers: []v1alpha2.Container{ | ||||
| 						{ | ||||
| 							Env: []corev1.EnvVar{ | ||||
| 								{Name: "", Value: ""}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 		assert.Equal(t, 0, len(opts)) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS is empty", func(t *testing.T) { | ||||
| 		jenkins := v1alpha2.Jenkins{ | ||||
| 			Spec: v1alpha2.JenkinsSpec{ | ||||
| 				Master: v1alpha2.JenkinsMaster{ | ||||
| 					Containers: []v1alpha2.Container{ | ||||
| 						{ | ||||
| 							Env: []corev1.EnvVar{ | ||||
| 								{Name: "JENKINS_OPTS", Value: ""}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 		assert.Equal(t, 0, len(opts)) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --prefix argument ", func(t *testing.T) { | ||||
| 		jenkins := v1alpha2.Jenkins{ | ||||
| 			Spec: v1alpha2.JenkinsSpec{ | ||||
| 				Master: v1alpha2.JenkinsMaster{ | ||||
| 					Containers: []v1alpha2.Container{ | ||||
| 						{ | ||||
| 							Env: []corev1.EnvVar{ | ||||
| 								{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins"}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 1, len(opts)) | ||||
| 		assert.NotContains(t, opts, "httpPort") | ||||
| 		assert.Contains(t, opts, "prefix") | ||||
| 		assert.Equal(t, opts["prefix"], "/jenkins") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --prefix and --httpPort argument", func(t *testing.T) { | ||||
| 		jenkins := v1alpha2.Jenkins{ | ||||
| 			Spec: v1alpha2.JenkinsSpec{ | ||||
| 				Master: v1alpha2.JenkinsMaster{ | ||||
| 					Containers: []v1alpha2.Container{ | ||||
| 						{ | ||||
| 							Env: []corev1.EnvVar{ | ||||
| 								{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins --httpPort=8080"}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 2, len(opts)) | ||||
| 
 | ||||
| 		assert.Contains(t, opts, "prefix") | ||||
| 		assert.Equal(t, opts["prefix"], "/jenkins") | ||||
| 
 | ||||
| 		assert.Contains(t, opts, "httpPort") | ||||
| 		assert.Equal(t, opts["httpPort"], "8080") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --httpPort argument", func(t *testing.T) { | ||||
| 		jenkins := v1alpha2.Jenkins{ | ||||
| 			Spec: v1alpha2.JenkinsSpec{ | ||||
| 				Master: v1alpha2.JenkinsMaster{ | ||||
| 					Containers: []v1alpha2.Container{ | ||||
| 						{ | ||||
| 							Env: []corev1.EnvVar{ | ||||
| 								{Name: "JENKINS_OPTS", Value: "--httpPort=8080"}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 1, len(opts)) | ||||
| 		assert.NotContains(t, opts, "prefix") | ||||
| 		assert.Contains(t, opts, "httpPort") | ||||
| 		assert.Equal(t, opts["httpPort"], "8080") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("JENKINS_OPTS have --httpPort=--8080 argument", func(t *testing.T) { | ||||
| 		jenkins := v1alpha2.Jenkins{ | ||||
| 			Spec: v1alpha2.JenkinsSpec{ | ||||
| 				Master: v1alpha2.JenkinsMaster{ | ||||
| 					Containers: []v1alpha2.Container{ | ||||
| 						{ | ||||
| 							Env: []corev1.EnvVar{ | ||||
| 								{Name: "JENKINS_OPTS", Value: "--httpPort=--8080"}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		opts := GetJenkinsOpts(jenkins) | ||||
| 
 | ||||
| 		assert.Equal(t, 1, len(opts)) | ||||
| 		assert.NotContains(t, opts, "prefix") | ||||
| 		assert.Contains(t, opts, "httpPort") | ||||
| 		assert.Equal(t, opts["httpPort"], "--8080") | ||||
| 	}) | ||||
| } | ||||
|  | @ -370,7 +370,7 @@ func (s *seedJobs) createAgent(jenkinsClient jenkinsclient.Jenkins, k8sClient cl | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	deployment, err := agentDeployment(jenkinsManifest, namespace, agentName, secret) | ||||
| 	deployment, err := agentDeployment(jenkinsManifest, namespace, agentName, secret, s.KubernetesClusterDomain) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -392,15 +392,20 @@ func agentDeploymentName(jenkins v1alpha2.Jenkins, agentName string) string { | |||
| 	return fmt.Sprintf("%s-%s", agentName, jenkins.Name) | ||||
| } | ||||
| 
 | ||||
| func agentDeployment(jenkins *v1alpha2.Jenkins, namespace string, agentName string, secret string) (*appsv1.Deployment, error) { | ||||
| 	jenkinsSlavesServiceFQDN, err := resources.GetJenkinsSlavesServiceFQDN(jenkins) | ||||
| func agentDeployment(jenkins *v1alpha2.Jenkins, namespace string, agentName string, secret string, kubernetesDomainName string) (*appsv1.Deployment, error) { | ||||
| 	jenkinsSlavesServiceFQDN, err := resources.GetJenkinsSlavesServiceFQDN(jenkins, kubernetesDomainName) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	jenkinsHTTPServiceFQDN, err := resources.GetJenkinsHTTPServiceFQDN(jenkins) | ||||
| 	jenkinsHTTPServiceFQDN, err := resources.GetJenkinsHTTPServiceFQDN(jenkins, kubernetesDomainName) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	suffix := "" | ||||
| 	if prefix, ok := resources.GetJenkinsOpts(*jenkins)["prefix"]; ok { | ||||
| 		suffix = prefix | ||||
| 	} | ||||
| 	return &appsv1.Deployment{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:      agentDeploymentName(*jenkins, agentName), | ||||
|  | @ -443,10 +448,10 @@ func agentDeployment(jenkins *v1alpha2.Jenkins, namespace string, agentName stri | |||
| 								}, | ||||
| 								{ | ||||
| 									Name: "JENKINS_URL", | ||||
| 									Value: fmt.Sprintf("http://%s:%d", | ||||
| 									Value: fmt.Sprintf("http://%s:%d%s", | ||||
| 										jenkinsHTTPServiceFQDN, | ||||
| 										jenkins.Spec.Service.Port, | ||||
| 									), | ||||
| 										suffix), | ||||
| 								}, | ||||
| 								{ | ||||
| 									Name:  "JENKINS_AGENT_WORKDIR", | ||||
|  |  | |||
|  | @ -50,8 +50,8 @@ var _ reconcile.Reconciler = &ReconcileJenkins{} | |||
| 
 | ||||
| // Add creates a newReconcilierConfiguration Jenkins Controller and adds it to the Manager. The Manager will set fields on the Controller
 | ||||
| // and Start it when the Manager is Started.
 | ||||
| func Add(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) error { | ||||
| 	reconciler := newReconciler(mgr, jenkinsAPIConnectionSettings, clientSet, config, notificationEvents) | ||||
| func Add(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, kubernetesClusterDomain string, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) error { | ||||
| 	reconciler := newReconciler(mgr, jenkinsAPIConnectionSettings, kubernetesClusterDomain, clientSet, config, notificationEvents) | ||||
| 	return add(mgr, reconciler) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ type ReconcileJenkins struct { | |||
| 	clientSet                    kubernetes.Clientset | ||||
| 	config                       rest.Config | ||||
| 	notificationEvents           *chan event.Event | ||||
| 	KubernetesClusterDomain      string | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkins) newReconcilierConfiguration(jenkins *v1alpha2.Jenkins) configuration.Configuration { | ||||
|  | @ -32,12 +33,13 @@ func (r *ReconcileJenkins) newReconcilierConfiguration(jenkins *v1alpha2.Jenkins | |||
| 		Scheme:                       r.scheme, | ||||
| 		Config:                       &r.config, | ||||
| 		JenkinsAPIConnectionSettings: r.jenkinsAPIConnectionSettings, | ||||
| 		KubernetesClusterDomain:      r.KubernetesClusterDomain, | ||||
| 	} | ||||
| 	return config | ||||
| } | ||||
| 
 | ||||
| // newReconciler returns a newReconcilierConfiguration reconcile.Reconciler.
 | ||||
| func newReconciler(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) reconcile.Reconciler { | ||||
| func newReconciler(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, kubernetesClusterDomain string, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) reconcile.Reconciler { | ||||
| 	return &ReconcileJenkins{ | ||||
| 		client:                       mgr.GetClient(), | ||||
| 		scheme:                       mgr.GetScheme(), | ||||
|  | @ -45,5 +47,6 @@ func newReconciler(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclie | |||
| 		clientSet:                    clientSet, | ||||
| 		config:                       config, | ||||
| 		notificationEvents:           notificationEvents, | ||||
| 		KubernetesClusterDomain:      kubernetesClusterDomain, | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,13 +1,13 @@ | |||
| package plugins | ||||
| 
 | ||||
| const ( | ||||
| 	configurationAsCodePlugin           = "configuration-as-code:1.38" | ||||
| 	gitPlugin                           = "git:4.2.2" | ||||
| 	configurationAsCodePlugin           = "configuration-as-code:1.46" | ||||
| 	gitPlugin                           = "git:4.4.5" | ||||
| 	jobDslPlugin                        = "job-dsl:1.77" | ||||
| 	kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:0.13" | ||||
| 	kubernetesPlugin                    = "kubernetes:1.25.2" | ||||
| 	kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:0.15" | ||||
| 	kubernetesPlugin                    = "kubernetes:1.27.6" | ||||
| 	workflowAggregatorPlugin            = "workflow-aggregator:2.6" | ||||
| 	workflowJobPlugin                   = "workflow-job:2.39" | ||||
| 	workflowJobPlugin                   = "workflow-job:2.40" | ||||
| ) | ||||
| 
 | ||||
| // basePluginsList contains plugins to install by operator.
 | ||||
|  |  | |||
|  | @ -137,8 +137,8 @@ func TestPlugins(t *testing.T) { | |||
| 	require.NoError(t, err, job) | ||||
| 	i, err := job.InvokeSimple(map[string]string{}) | ||||
| 	require.NoError(t, err, i) | ||||
| 
 | ||||
| 	waitForJobToFinish(t, job, 2*time.Second, 2*time.Minute) | ||||
| 	// FIXME: waitForJobToFinish use
 | ||||
| 	time.Sleep(80 * time.Second) // wait for the build to complete
 | ||||
| 
 | ||||
| 	job, err = jenkinsClient.GetJob(jobID) | ||||
| 	require.NoError(t, err, job) | ||||
|  |  | |||
|  | @ -116,10 +116,10 @@ func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha2.S | |||
| 					}, | ||||
| 				}, | ||||
| 				Plugins: []v1alpha2.Plugin{ | ||||
| 					{Name: "audit-trail", Version: "2.4"}, | ||||
| 					{Name: "simple-theme-plugin", Version: "0.5.1"}, | ||||
| 					{Name: "github", Version: "1.29.4"}, | ||||
| 					{Name: "devoptics", Version: "1.1863", DownloadURL: "https://jenkins-updates.cloudbees.com/download/plugins/devoptics/1.1863/devoptics.hpi"}, | ||||
| 					{Name: "audit-trail", Version: "3.7"}, | ||||
| 					{Name: "simple-theme-plugin", Version: "0.6"}, | ||||
| 					{Name: "github", Version: "1.32.0"}, | ||||
| 					{Name: "devoptics", Version: "1.1905", DownloadURL: "https://jenkins-updates.cloudbees.com/download/plugins/devoptics/1.1905/devoptics.hpi"}, | ||||
| 				}, | ||||
| 				PriorityClassName: priorityClassName, | ||||
| 				NodeSelector:      map[string]string{"kubernetes.io/os": "linux"}, | ||||
|  |  | |||
|  | @ -42,13 +42,24 @@ func TestBackupAndRestore(t *testing.T) { | |||
| 	// FIXME: waitForJobToFinish use
 | ||||
| 	time.Sleep(60 * time.Second) // wait for the build to complete
 | ||||
| 
 | ||||
| 	jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name) | ||||
| 	lastDoneBackup := jenkins.Status.LastBackup | ||||
| 	restartJenkinsMasterPod(t, jenkins) | ||||
| 	waitForRecreateJenkinsMasterPod(t, jenkins) | ||||
| 	waitForJenkinsUserConfigurationToComplete(t, jenkins) | ||||
| 	jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name) | ||||
| 	assert.Equal(t, lastDoneBackup, jenkins.Status.RestoredBackup) | ||||
| 	jenkinsClient2, cleanUpFunc2 := verifyJenkinsAPIConnection(t, jenkins, namespace) | ||||
| 	defer cleanUpFunc2() | ||||
| 	waitForJob(t, jenkinsClient2, jobID) | ||||
| 	verifyJobBuildsAfterRestoreBackup(t, jenkinsClient2, jobID) | ||||
| 
 | ||||
| 	jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name) | ||||
| 	lastDoneBackup = jenkins.Status.LastBackup | ||||
| 	resetJenkinsStatus(t, jenkins) | ||||
| 	waitForJenkinsUserConfigurationToComplete(t, jenkins) | ||||
| 	jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name) | ||||
| 	assert.Equal(t, lastDoneBackup, jenkins.Status.RestoredBackup) | ||||
| } | ||||
| 
 | ||||
| func waitForJob(t *testing.T, jenkinsClient client.Jenkins, jobID string) { | ||||
|  | @ -106,6 +117,11 @@ func createJenkinsWithBackupAndRestoreConfigured(t *testing.T, name, namespace s | |||
| 			}, | ||||
| 			Restore: v1alpha2.Restore{ | ||||
| 				ContainerName: containerName, | ||||
| 				GetLatestAction: v1alpha2.Handler{ | ||||
| 					Exec: &corev1.ExecAction{ | ||||
| 						Command: []string{"/home/user/bin/get-latest.sh"}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				Action: v1alpha2.Handler{ | ||||
| 					Exec: &corev1.ExecAction{ | ||||
| 						Command: []string{"/home/user/bin/restore.sh"}, | ||||
|  | @ -125,7 +141,7 @@ func createJenkinsWithBackupAndRestoreConfigured(t *testing.T, name, namespace s | |||
| 					}, | ||||
| 					{ | ||||
| 						Name:            containerName, | ||||
| 						Image:           "virtuslab/jenkins-operator-backup-pvc:v0.0.6", | ||||
| 						Image:           "virtuslab/jenkins-operator-backup-pvc:v0.1.0", | ||||
| 						ImagePullPolicy: corev1.PullIfNotPresent, | ||||
| 						Env: []corev1.EnvVar{ | ||||
| 							{ | ||||
|  | @ -191,3 +207,10 @@ func createJenkinsWithBackupAndRestoreConfigured(t *testing.T, name, namespace s | |||
| 
 | ||||
| 	return jenkins | ||||
| } | ||||
| 
 | ||||
| func resetJenkinsStatus(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name) | ||||
| 	jenkins.Status = v1alpha2.JenkinsStatus{} | ||||
| 	err := framework.Global.Client.Update(context.TODO(), jenkins) | ||||
| 	require.NoError(t, err) | ||||
| } | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ import ( | |||
| 	jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||
| 
 | ||||
| 	"github.com/bndr/gojenkins" | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | @ -34,28 +33,6 @@ var ( | |||
| // checkConditionFunc is used to check if a condition for the jenkins CR is set
 | ||||
| type checkConditionFunc func(*v1alpha2.Jenkins, error) bool | ||||
| 
 | ||||
| func waitForJobToFinish(t *testing.T, job *gojenkins.Job, tick, timeout time.Duration) { | ||||
| 	err := try.Until(func() (end bool, err error) { | ||||
| 		t.Logf("Waiting for job `%s` to finish", job.GetName()) | ||||
| 		running, err := job.IsRunning() | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 
 | ||||
| 		queued, err := job.IsQueued() | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 
 | ||||
| 		if !running && !queued { | ||||
| 			return true, nil | ||||
| 		} | ||||
| 
 | ||||
| 		return false, nil | ||||
| 	}, tick, timeout) | ||||
| 	require.NoError(t, err) | ||||
| } | ||||
| 
 | ||||
| func waitForJenkinsBaseConfigurationToComplete(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	t.Log("Waiting for Jenkins base configuration to complete") | ||||
| 	_, err := WaitUntilJenkinsConditionSet(retryInterval, 170, jenkins, func(jenkins *v1alpha2.Jenkins, err error) bool { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue