diff --git a/Makefile b/Makefile index 96a5c462d..4c366c92b 100644 --- a/Makefile +++ b/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 diff --git a/chart/jenkins-operator/templates/role.yaml b/chart/jenkins-operator/templates/role.yaml index c82edaa6d..49ef89cf7 100644 --- a/chart/jenkins-operator/templates/role.yaml +++ b/chart/jenkins-operator/templates/role.yaml @@ -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 diff --git a/chart/jenkins-operator/values.yaml b/chart/jenkins-operator/values.yaml index ac300b916..8f39b5ceb 100644 --- a/chart/jenkins-operator/values.yaml +++ b/chart/jenkins-operator/values.yaml @@ -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 diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 518cb191c..165aed932 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -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 diff --git a/config.base.env b/config.base.env index 868b2b7a0..dda8893cd 100644 --- a/config.base.env +++ b/config.base.env @@ -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 diff --git a/deploy/crds/jenkins_v1alpha2_jenkins_cr.yaml b/deploy/crds/jenkins_v1alpha2_jenkins_cr.yaml index 51277624c..0fe81b4a3 100644 --- a/deploy/crds/jenkins_v1alpha2_jenkins_cr.yaml +++ b/deploy/crds/jenkins_v1alpha2_jenkins_cr.yaml @@ -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 diff --git a/deploy/crds/jenkins_v1alpha2_jenkinsimage_cr.yaml b/deploy/crds/jenkins_v1alpha2_jenkinsimage_cr.yaml index 9bf8eb2c9..623055ed5 100644 --- a/deploy/crds/jenkins_v1alpha2_jenkinsimage_cr.yaml +++ b/deploy/crds/jenkins_v1alpha2_jenkinsimage_cr.yaml @@ -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" - - name: workflow-job - version: "2.39" + version: "1.27.6" + - name: workflow-job + 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" diff --git a/pkg/apis/jenkins/v1alpha2/jenkins_types.go b/pkg/apis/jenkins/v1alpha2/jenkins_types.go index 92570ac98..8c77eee5e 100644 --- a/pkg/apis/jenkins/v1alpha2/jenkins_types.go +++ b/pkg/apis/jenkins/v1alpha2/jenkins_types.go @@ -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"` diff --git a/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go index 4f228623b..f390614c8 100644 --- a/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/jenkins/v1alpha2/zz_generated.deepcopy.go @@ -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 } diff --git a/pkg/configuration/backuprestore/backuprestore.go b/pkg/configuration/backuprestore/backuprestore.go index d3d25ba3d..68369fbd1 100644 --- a/pkg/configuration/backuprestore/backuprestore.go +++ b/pkg/configuration/backuprestore/backuprestore.go @@ -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) diff --git a/pkg/configuration/base/configmap.go b/pkg/configuration/base/configmap.go index 1ed97a2d1..fb3185e11 100644 --- a/pkg/configuration/base/configmap.go +++ b/pkg/configuration/base/configmap.go @@ -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 } diff --git a/pkg/configuration/base/resources/base_configuration_configmap.go b/pkg/configuration/base/resources/base_configuration_configmap.go index d1366b30f..ef16c63e1 100644 --- a/pkg/configuration/base/resources/base_configuration_configmap.go +++ b/pkg/configuration/base/resources/base_configuration_configmap.go @@ -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) } diff --git a/pkg/configuration/base/resources/pod.go b/pkg/configuration/base/resources/pod.go index 25c1be68f..265a75abb 100644 --- a/pkg/configuration/base/resources/pod.go +++ b/pkg/configuration/base/resources/pod.go @@ -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" @@ -14,9 +15,9 @@ const ( // JenkinsMasterContainerName is the Jenkins master container name in pod JenkinsMasterContainerName = "jenkins-master" // JenkinsHomeVolumeName is the Jenkins home volume name - JenkinsHomeVolumeName = "jenkins-home" - jenkinsPath = "/var/jenkins" - + 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{ diff --git a/pkg/configuration/base/resources/resources_test.go b/pkg/configuration/base/resources/resources_test.go new file mode 100644 index 000000000..64742f77d --- /dev/null +++ b/pkg/configuration/base/resources/resources_test.go @@ -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) + }) +} diff --git a/pkg/configuration/base/resources/service.go b/pkg/configuration/base/resources/service.go index 0d3201ad9..507b206bc 100644 --- a/pkg/configuration/base/resources/service.go +++ b/pkg/configuration/base/resources/service.go @@ -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 false, stackerr.WithStack(err) + return true, nil } diff --git a/pkg/configuration/configuration.go b/pkg/configuration/configuration.go index 264a3463d..534165830 100644 --- a/pkg/configuration/configuration.go +++ b/pkg/configuration/configuration.go @@ -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. diff --git a/pkg/configuration/configuration_test.go b/pkg/configuration/configuration_test.go deleted file mode 100644 index 1f2527ae0..000000000 --- a/pkg/configuration/configuration_test.go +++ /dev/null @@ -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") - }) -} diff --git a/pkg/configuration/user/seedjobs/seedjobs.go b/pkg/configuration/user/seedjobs/seedjobs.go index 0744529a2..3707a786c 100644 --- a/pkg/configuration/user/seedjobs/seedjobs.go +++ b/pkg/configuration/user/seedjobs/seedjobs.go @@ -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", diff --git a/pkg/controller/jenkins/jenkins_controller.go b/pkg/controller/jenkins/jenkins_controller.go index 35bfbc424..5be62cde6 100644 --- a/pkg/controller/jenkins/jenkins_controller.go +++ b/pkg/controller/jenkins/jenkins_controller.go @@ -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) } diff --git a/pkg/controller/jenkins/reconciler.go b/pkg/controller/jenkins/reconciler.go index 9f9be6e6f..9fdd30e11 100644 --- a/pkg/controller/jenkins/reconciler.go +++ b/pkg/controller/jenkins/reconciler.go @@ -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, } } diff --git a/pkg/plugins/base_plugins.go b/pkg/plugins/base_plugins.go index e7feb4bd5..811dbcb41 100644 --- a/pkg/plugins/base_plugins.go +++ b/pkg/plugins/base_plugins.go @@ -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. diff --git a/test/e2e/configuration_test.go b/test/e2e/configuration_test.go index 5d5cfc6b2..3dd5443c1 100644 --- a/test/e2e/configuration_test.go +++ b/test/e2e/configuration_test.go @@ -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) diff --git a/test/e2e/jenkins.go b/test/e2e/jenkins.go index b66a8f58e..73a118b0c 100644 --- a/test/e2e/jenkins.go +++ b/test/e2e/jenkins.go @@ -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"}, diff --git a/test/e2e/restorebackup_test.go b/test/e2e/restorebackup_test.go index 0fa269c57..2b09cf451 100644 --- a/test/e2e/restorebackup_test.go +++ b/test/e2e/restorebackup_test.go @@ -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) +} diff --git a/test/e2e/wait.go b/test/e2e/wait.go index a1ba2e51d..ff3919bb0 100644 --- a/test/e2e/wait.go +++ b/test/e2e/wait.go @@ -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 {