Refactor e2e tests to new ginkgo framework
This commit is contained in:
		
							parent
							
								
									b6bf47b949
								
							
						
					
					
						commit
						524d0b861f
					
				
							
								
								
									
										49
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										49
									
								
								Makefile
								
								
								
								
							|  | @ -89,47 +89,10 @@ test: ## Runs the go tests | |||
| 	@RUNNING_TESTS=1 go test -tags "$(BUILDTAGS) cgo" $(PACKAGES_FOR_UNIT_TESTS) | ||||
| 
 | ||||
| .PHONY: e2e | ||||
| CURRENT_DIRECTORY := $(shell pwd) | ||||
| e2e: container-runtime-build ## Runs e2e tests, you can use EXTRA_ARGS
 | ||||
| e2e: deepcopy-gen ## Runs e2e tests, you can use EXTRA_ARGS
 | ||||
| 	@echo "+ $@" | ||||
| 	@echo "Docker image: $(DOCKER_REGISTRY):$(GITCOMMIT)" | ||||
| ifeq ($(KUBERNETES_PROVIDER),minikube) | ||||
| 	kubectl config use-context $(KUBECTL_CONTEXT) | ||||
| endif | ||||
| ifeq ($(KUBERNETES_PROVIDER),crc) | ||||
| 	oc project $(CRC_OC_PROJECT) | ||||
| endif | ||||
| 	cp deploy/service_account.yaml deploy/namespace-init.yaml | ||||
| 	cat deploy/role.yaml >> deploy/namespace-init.yaml | ||||
| 	cat deploy/role_binding.yaml >> deploy/namespace-init.yaml | ||||
| 	cat deploy/operator.yaml >> deploy/namespace-init.yaml | ||||
| ifeq ($(OSFLAG), LINUX) | ||||
| ifeq ($(IMAGE_PULL_MODE), remote) | ||||
| 	sed -i 's|\(image:\).*|\1 $(DOCKER_ORGANIZATION)/$(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml | ||||
| 	sed -i 's|\(imagePullPolicy\): IfNotPresent|\1: Always|g' deploy/namespace-init.yaml | ||||
| else | ||||
| 	sed -i 's|\(image:\).*|\1 $(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml | ||||
| endif | ||||
| ifeq ($(KUBERNETES_PROVIDER),minikube) | ||||
| 	sed -i 's|\(imagePullPolicy\): IfNotPresent|\1: Never|g' deploy/namespace-init.yaml | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| ifeq ($(OSFLAG), OSX) | ||||
| ifeq ($(IMAGE_PULL_MODE), remote) | ||||
| 	sed -i '' 's|\(image:\).*|\1 $(DOCKER_ORGANIZATION)/$(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml | ||||
| 	sed -i '' 's|\(imagePullPolicy\): IfNotPresent|\1: Always|g' deploy/namespace-init.yaml | ||||
| else | ||||
| 	sed -i '' 's|\(image:\).*|\1 $(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml | ||||
| endif | ||||
| ifeq ($(KUBERNETES_PROVIDER),minikube) | ||||
| 	sed -i '' 's|\(imagePullPolicy\): IfNotPresent|\1: Never|g' deploy/namespace-init.yaml | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| 	RUNNING_TESTS=1 go test -parallel=1 "./test/e2e/" -tags "$(BUILDTAGS) cgo" -v -timeout 60m -run "$(E2E_TEST_SELECTOR)" \
 | ||||
| 		-root=$(CURRENT_DIRECTORY) -kubeconfig=$(HOME)/.kube/config -globalMan deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml \
 | ||||
| 		-namespacedMan deploy/namespace-init.yaml $(TEST_ARGS) | ||||
| 		$(TEST_ARGS) | ||||
| 
 | ||||
| .PHONY: vet | ||||
| vet: ## Verifies `go vet` passes
 | ||||
|  | @ -420,7 +383,6 @@ generate-docs: ## Re-generate docs directory from the website directory | |||
| 	hugo -s website -d ../docs | ||||
| 
 | ||||
| ##################### FROM OPERATOR SDK ########################
 | ||||
| #TODO rename
 | ||||
| # Install CRDs into a cluster
 | ||||
| install-crds: manifests kustomize | ||||
| 	$(KUSTOMIZE) build config/crd | kubectl apply -f - | ||||
|  | @ -474,9 +436,8 @@ bundle: manifests kustomize | |||
| bundle-build: | ||||
| 	docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . | ||||
| 
 | ||||
| #FIXME temporary target for running tests (test used above for go test)
 | ||||
| ENVTEST_ASSETS_DIR=$(shell pwd)/testbin | ||||
| testing: generate fmt vet manifests | ||||
| # Download kubebuilder
 | ||||
| kubebuilder: | ||||
| 	mkdir -p ${ENVTEST_ASSETS_DIR} | ||||
| 	test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.7.0/hack/setup-envtest.sh | ||||
| 	source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out | ||||
| 	source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); | ||||
|  | @ -16,7 +16,7 @@ limitations under the License. | |||
| 
 | ||||
| // Package v1alpha2 contains API Schema definitions for the jenkins.io v1alpha2 API group
 | ||||
| // +kubebuilder:object:generate=true
 | ||||
| // +groupName=jenkins.io.jenkins.io
 | ||||
| // +groupName=jenkins.io
 | ||||
| package v1alpha2 | ||||
| 
 | ||||
| import ( | ||||
|  | @ -26,7 +26,7 @@ import ( | |||
| 
 | ||||
| var ( | ||||
| 	// GroupVersion is group version used to register these objects
 | ||||
| 	GroupVersion = schema.GroupVersion{Group: "jenkins.io.jenkins.io", Version: "v1alpha2"} | ||||
| 	GroupVersion = schema.GroupVersion{Group: "jenkins.io", Version: "v1alpha2"} | ||||
| 
 | ||||
| 	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
 | ||||
| 	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} | ||||
|  |  | |||
|  | @ -674,7 +674,3 @@ type GroovyScripts struct { | |||
| type ConfigurationAsCode struct { | ||||
| 	Customization `json:",inline"` | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	SchemeBuilder.Register(&Jenkins{}, &JenkinsList{}) | ||||
| } | ||||
|  |  | |||
|  | @ -47,7 +47,3 @@ type JenkinsImageList struct { | |||
| 	metav1.ListMeta `json:"metadata,omitempty"` | ||||
| 	Items           []JenkinsImage `json:"items"` | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	SchemeBuilder.Register(&JenkinsImage{}, &JenkinsImageList{}) | ||||
| } | ||||
|  |  | |||
|  | @ -6,9 +6,9 @@ metadata: | |||
|   annotations: | ||||
|     controller-gen.kubebuilder.io/version: v0.4.1 | ||||
|   creationTimestamp: null | ||||
|   name: jenkins.jenkins.io.jenkins.io | ||||
|   name: jenkins.jenkins.io | ||||
| spec: | ||||
|   group: jenkins.io.jenkins.io | ||||
|   group: jenkins.io | ||||
|   names: | ||||
|     kind: Jenkins | ||||
|     listKind: JenkinsList | ||||
|  | @ -38,7 +38,7 @@ spec: | |||
|             properties: | ||||
|               backup: | ||||
|                 description: 'Backup defines configuration of Jenkins backup More | ||||
|                   info: https://github.com/jenkinsci/kubernetes-operator/blob/master/docs/getting-started.md#configure-backup-and-restore' | ||||
|                   info: https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configure-backup-and-restore/' | ||||
|                 properties: | ||||
|                   action: | ||||
|                     description: Action defines action which performs backup in backup | ||||
|  | @ -157,11 +157,11 @@ spec: | |||
|                     type: object | ||||
|                   basePlugins: | ||||
|                     description: 'BasePlugins contains plugins required by operator | ||||
|                       Defaults to : - name: kubernetes version: 1.15.7 - name: workflow-job | ||||
|                       version: "2.39" - name: workflow-aggregator version: "2.6" - | ||||
|                       name: git version: 3.10.0 - name: job-dsl version: "1.74" - | ||||
|                       name: configuration-as-code version: "1.19" - name: kubernetes-credentials-provider | ||||
|                       version: 0.12.1' | ||||
|                       Defaults to : - name: kubernetes version: "1.28.6" - name: workflow-job | ||||
|                       version: "2.40" - name: workflow-aggregator version: "2.6" - | ||||
|                       name: git version: "4.5.0" - name: job-dsl version: "1.77" - | ||||
|                       name: configuration-as-code version: "1.46" - name: kubernetes-credentials-provider | ||||
|                       version: "0.15"' | ||||
|                     items: | ||||
|                       description: Plugin defines Jenkins plugin. | ||||
|                       properties: | ||||
|  | @ -1184,7 +1184,7 @@ spec: | |||
|                           support fsGroup based ownership(and permissions). It will | ||||
|                           have no effect on ephemeral volume types such as: secret, | ||||
|                           configmaps and emptydir. Valid values are "OnRootMismatch" | ||||
|                           and "Always". If not specified defaults to "Always".' | ||||
|                           and "Always". If not specified, "Always" is used.' | ||||
|                         type: string | ||||
|                       runAsGroup: | ||||
|                         description: The GID to run the entrypoint of the container | ||||
|  | @ -1817,22 +1817,16 @@ spec: | |||
|                                     dataSource: | ||||
|                                       description: 'This field can be used to specify | ||||
|                                         either: * An existing VolumeSnapshot object | ||||
|                                         (snapshot.storage.k8s.io/VolumeSnapshot - | ||||
|                                         Beta) * An existing PVC (PersistentVolumeClaim) | ||||
|                                         * An existing custom resource/object that | ||||
|                                         implements data population (Alpha) In order | ||||
|                                         to use VolumeSnapshot object types, the appropriate | ||||
|                                         feature gate must be enabled (VolumeSnapshotDataSource | ||||
|                                         or AnyVolumeDataSource) If the provisioner | ||||
|                                         or an external controller can support the | ||||
|                                         specified data source, it will create a new | ||||
|                                         volume based on the contents of the specified | ||||
|                                         data source. If the specified data source | ||||
|                                         is not supported, the volume will not be created | ||||
|                                         and the failure will be reported as an event. | ||||
|                                         In the future, we plan to support more data | ||||
|                                         source types and the behavior of the provisioner | ||||
|                                         may change.' | ||||
|                                         (snapshot.storage.k8s.io/VolumeSnapshot) * | ||||
|                                         An existing PVC (PersistentVolumeClaim) * | ||||
|                                         An existing custom resource that implements | ||||
|                                         data population (Alpha) In order to use custom | ||||
|                                         resource types that implement data population, | ||||
|                                         the AnyVolumeDataSource feature gate must | ||||
|                                         be enabled. If the provisioner or an external | ||||
|                                         controller can support the specified data | ||||
|                                         source, it will create a new volume based | ||||
|                                         on the contents of the specified data source.' | ||||
|                                       properties: | ||||
|                                         apiGroup: | ||||
|                                           description: APIGroup is the group for the | ||||
|  | @ -2560,8 +2554,6 @@ spec: | |||
|                                     type: object | ||||
|                                 type: object | ||||
|                               type: array | ||||
|                           required: | ||||
|                           - sources | ||||
|                           type: object | ||||
|                         quobyte: | ||||
|                           description: Quobyte represents a Quobyte mount on the host | ||||
|  | @ -3030,7 +3022,7 @@ spec: | |||
|                 type: array | ||||
|               restore: | ||||
|                 description: 'Backup defines configuration of Jenkins backup restore | ||||
|                   More info: https://github.com/jenkinsci/kubernetes-operator/blob/master/docs/getting-started.md#configure-backup-and-restore' | ||||
|                   More info: https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configure-backup-and-restore/' | ||||
|                 properties: | ||||
|                   action: | ||||
|                     description: Action defines action which performs restore backup | ||||
|  | @ -3112,10 +3104,10 @@ spec: | |||
|                 type: array | ||||
|               seedJobs: | ||||
|                 description: 'SeedJobs defines list of Jenkins Seed Job configurations | ||||
|                   More info: https://github.com/jenkinsci/kubernetes-operator/blob/master/docs/getting-started.md#configure-seed-jobs-and-pipelines' | ||||
|                   More info: https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuration#configure-seed-jobs-and-pipelines' | ||||
|                 items: | ||||
|                   description: 'SeedJob defines configuration for seed job More info: | ||||
|                     https://github.com/jenkinsci/kubernetes-operator/blob/master/docs/getting-started.md#configure-seed-jobs-and-pipelines.' | ||||
|                     https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuration/#configure-seed-jobs-and-pipelines.' | ||||
|                   properties: | ||||
|                     additionalClasspath: | ||||
|                       description: AdditionalClasspath is setting for Job DSL API | ||||
|  | @ -3209,7 +3201,7 @@ spec: | |||
|                       will restrict traffic through the cloud-provider load-balancer | ||||
|                       will be restricted to the specified client IPs. This field will | ||||
|                       be ignored if the cloud-provider does not support the feature." | ||||
|                       More info: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/' | ||||
|                       More info: https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/#restricting-cloud-metadata-api-access' | ||||
|                     items: | ||||
|                       type: string | ||||
|                     type: array | ||||
|  | @ -3290,7 +3282,7 @@ spec: | |||
|                       will restrict traffic through the cloud-provider load-balancer | ||||
|                       will be restricted to the specified client IPs. This field will | ||||
|                       be ignored if the cloud-provider does not support the feature." | ||||
|                       More info: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/' | ||||
|                       More info: https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/#restricting-cloud-metadata-api-access' | ||||
|                     items: | ||||
|                       type: string | ||||
|                     type: array | ||||
|  | @ -6,9 +6,9 @@ metadata: | |||
|   annotations: | ||||
|     controller-gen.kubebuilder.io/version: v0.4.1 | ||||
|   creationTimestamp: null | ||||
|   name: jenkinsimages.jenkins.io.jenkins.io | ||||
|   name: jenkinsimages.jenkins.io | ||||
| spec: | ||||
|   group: jenkins.io.jenkins.io | ||||
|   group: jenkins.io | ||||
|   names: | ||||
|     kind: JenkinsImage | ||||
|     listKind: JenkinsImageList | ||||
|  | @ -2,7 +2,7 @@ | |||
| # since it depends on service name and namespace that are out of this kustomize package. | ||||
| # It should be run by config/default | ||||
| resources: | ||||
| - bases/jenkins.io.jenkins.io_jenkins.yaml | ||||
| - bases/jenkins.io_jenkins.yaml | ||||
| # +kubebuilder:scaffold:crdkustomizeresource | ||||
| 
 | ||||
| patchesStrategicMerge: | ||||
|  |  | |||
|  | @ -4,4 +4,4 @@ kind: CustomResourceDefinition | |||
| metadata: | ||||
|   annotations: | ||||
|     cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) | ||||
|   name: jenkins.jenkins.io.jenkins.io | ||||
|   name: jenkins.jenkins.io | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| apiVersion: apiextensions.k8s.io/v1 | ||||
| kind: CustomResourceDefinition | ||||
| metadata: | ||||
|   name: jenkins.jenkins.io.jenkins.io | ||||
|   name: jenkins.jenkins.io | ||||
| spec: | ||||
|   conversion: | ||||
|     strategy: Webhook | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ metadata: | |||
|   name: jenkins-editor-role | ||||
| rules: | ||||
| - apiGroups: | ||||
|   - jenkins.io.jenkins.io | ||||
|   - jenkins.io | ||||
|   resources: | ||||
|   - jenkins | ||||
|   verbs: | ||||
|  | @ -17,7 +17,7 @@ rules: | |||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - jenkins.io.jenkins.io | ||||
|   - jenkins.io | ||||
|   resources: | ||||
|   - jenkins/status | ||||
|   verbs: | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ metadata: | |||
|   name: jenkins-viewer-role | ||||
| rules: | ||||
| - apiGroups: | ||||
|   - jenkins.io.jenkins.io | ||||
|   - jenkins.io | ||||
|   resources: | ||||
|   - jenkins | ||||
|   verbs: | ||||
|  | @ -13,7 +13,7 @@ rules: | |||
|   - list | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - jenkins.io.jenkins.io | ||||
|   - jenkins.io | ||||
|   resources: | ||||
|   - jenkins/status | ||||
|   verbs: | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| apiVersion: jenkins.io.jenkins.io/v1alpha2 | ||||
| apiVersion: jenkins.io/v1alpha2 | ||||
| kind: Jenkins | ||||
| metadata: | ||||
|   name: jenkins-example | ||||
|  |  | |||
|  | @ -1,170 +0,0 @@ | |||
| package controllers | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/constants" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	rbacv1 "k8s.io/api/rbac/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/util/intstr" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	userConfigurationConfigMapName = "user-config" | ||||
| 	userConfigurationSecretName    = "user-secret" | ||||
| ) | ||||
| 
 | ||||
| type seedJobConfig struct { | ||||
| 	v1alpha2.SeedJob | ||||
| 	JobNames   []string `json:"jobNames,omitempty"` | ||||
| 	Username   string   `json:"username,omitempty"` | ||||
| 	Password   string   `json:"password,omitempty"` | ||||
| 	PrivateKey string   `json:"privateKey,omitempty"` | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	jenkinsCRName     = "jenkins-example" | ||||
| 	namespace         = "default" | ||||
| 	priorityClassName = "" | ||||
| 
 | ||||
| 	mySeedJob = seedJobConfig{ | ||||
| 		SeedJob: v1alpha2.SeedJob{ | ||||
| 			ID:                    "jenkins-operator", | ||||
| 			CredentialID:          "jenkins-operator", | ||||
| 			JenkinsCredentialType: v1alpha2.NoJenkinsCredentialCredentialType, | ||||
| 			Targets:               "cicd/jobs/*.jenkins", | ||||
| 			Description:           "Jenkins Operator repository", | ||||
| 			RepositoryBranch:      "master", | ||||
| 			RepositoryURL:         "https://github.com/jenkinsci/kubernetes-operator.git", | ||||
| 			PollSCM:               "1 1 1 1 1", | ||||
| 			UnstableOnDeprecation: true, | ||||
| 			BuildPeriodically:     "1 1 1 1 1", | ||||
| 			FailOnMissingPlugin:   true, | ||||
| 			IgnoreMissingFiles:    true, | ||||
| 			//AdditionalClasspath: can fail with the seed job agent
 | ||||
| 			GitHubPushTrigger: true, | ||||
| 		}, | ||||
| 	} | ||||
| 	groovyScripts = v1alpha2.GroovyScripts{ | ||||
| 		Customization: v1alpha2.Customization{ | ||||
| 			Configurations: []v1alpha2.ConfigMapRef{ | ||||
| 				{ | ||||
| 					Name: userConfigurationConfigMapName, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Secret: v1alpha2.SecretRef{ | ||||
| 				Name: userConfigurationSecretName, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	casc = v1alpha2.ConfigurationAsCode{ | ||||
| 		Customization: v1alpha2.Customization{ | ||||
| 			Configurations: []v1alpha2.ConfigMapRef{ | ||||
| 				{ | ||||
| 					Name: userConfigurationConfigMapName, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Secret: v1alpha2.SecretRef{ | ||||
| 				Name: userConfigurationSecretName, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| func createJenkinsCR(name, namespace string, seedJob *[]v1alpha2.SeedJob, groovyScripts v1alpha2.GroovyScripts, casc v1alpha2.ConfigurationAsCode, priorityClassName string) *v1alpha2.Jenkins { | ||||
| 	var seedJobs []v1alpha2.SeedJob | ||||
| 	if seedJob != nil { | ||||
| 		seedJobs = append(seedJobs, *seedJob...) | ||||
| 	} | ||||
| 
 | ||||
| 	jenkins := &v1alpha2.Jenkins{ | ||||
| 		TypeMeta: v1alpha2.JenkinsTypeMeta(), | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:      name, | ||||
| 			Namespace: namespace, | ||||
| 		}, | ||||
| 		Spec: v1alpha2.JenkinsSpec{ | ||||
| 			GroovyScripts:       groovyScripts, | ||||
| 			ConfigurationAsCode: casc, | ||||
| 			Master: v1alpha2.JenkinsMaster{ | ||||
| 				Annotations: map[string]string{"test": "label"}, | ||||
| 				Containers: []v1alpha2.Container{ | ||||
| 					{ | ||||
| 						Name: resources.JenkinsMasterContainerName, | ||||
| 						Env: []corev1.EnvVar{ | ||||
| 							{ | ||||
| 								Name:  "TEST_ENV", | ||||
| 								Value: "test_env_value", | ||||
| 							}, | ||||
| 						}, | ||||
| 						ReadinessProbe: &corev1.Probe{ | ||||
| 							Handler: corev1.Handler{ | ||||
| 								HTTPGet: &corev1.HTTPGetAction{ | ||||
| 									Path:   "/login", | ||||
| 									Port:   intstr.FromString("http"), | ||||
| 									Scheme: corev1.URISchemeHTTP, | ||||
| 								}, | ||||
| 							}, | ||||
| 							InitialDelaySeconds: int32(80), | ||||
| 							TimeoutSeconds:      int32(4), | ||||
| 							FailureThreshold:    int32(10), | ||||
| 						}, | ||||
| 						LivenessProbe: &corev1.Probe{ | ||||
| 							Handler: corev1.Handler{ | ||||
| 								HTTPGet: &corev1.HTTPGetAction{ | ||||
| 									Path:   "/login", | ||||
| 									Port:   intstr.FromString("http"), | ||||
| 									Scheme: corev1.URISchemeHTTP, | ||||
| 								}, | ||||
| 							}, | ||||
| 							InitialDelaySeconds: int32(80), | ||||
| 							TimeoutSeconds:      int32(4), | ||||
| 							FailureThreshold:    int32(10), | ||||
| 						}, | ||||
| 						VolumeMounts: []corev1.VolumeMount{ | ||||
| 							{ | ||||
| 								Name:      "plugins-cache", | ||||
| 								MountPath: "/usr/share/jenkins/ref/plugins", | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:  "envoyproxy", | ||||
| 						Image: "envoyproxy/envoy-alpine:v1.14.1", | ||||
| 					}, | ||||
| 				}, | ||||
| 				Plugins: []v1alpha2.Plugin{ | ||||
| 					{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"}, | ||||
| 				Volumes: []corev1.Volume{ | ||||
| 					{ | ||||
| 						Name: "plugins-cache", | ||||
| 						VolumeSource: corev1.VolumeSource{ | ||||
| 							EmptyDir: &corev1.EmptyDirVolumeSource{}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			SeedJobs: seedJobs, | ||||
| 			Service: v1alpha2.Service{ | ||||
| 				Type: corev1.ServiceTypeNodePort, | ||||
| 				Port: constants.DefaultHTTPPortInt32, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	jenkins.Spec.Roles = []rbacv1.RoleRef{ | ||||
| 		{ | ||||
| 			APIGroup: "rbac.authorization.k8s.io", | ||||
| 			Kind:     "Role", | ||||
| 			Name:     resources.GetResourceName(jenkins), | ||||
| 		}, | ||||
| 	} | ||||
| 	return jenkins | ||||
| } | ||||
|  | @ -1,40 +0,0 @@ | |||
| /* | ||||
| Copyright 2021. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package controllers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	. "github.com/onsi/gomega" | ||||
| 	// +kubebuilder:scaffold:imports
 | ||||
| ) | ||||
| 
 | ||||
| // These tests use Ginkgo (BDD-style Go testing framework). Refer to
 | ||||
| // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
 | ||||
| var _ = Describe("Jenkins controller", func() { | ||||
| 	Describe("deploying Jenkins CR into a cluster", func() { | ||||
| 		Context("when deploying CR to cluster", func() { | ||||
| 			It("create Jenkins instance", func() { | ||||
| 				ctx := context.Background() | ||||
| 				jenkins := createJenkinsCR(jenkinsCRName, namespace, &[]v1alpha2.SeedJob{mySeedJob.SeedJob}, groovyScripts, casc, priorityClassName) | ||||
| 				Expect(k8sClient.Create(ctx, jenkins)).Should(Succeed()) | ||||
| 			}) | ||||
| 		}) | ||||
| 	}) | ||||
| }) | ||||
							
								
								
									
										1
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										1
									
								
								go.mod
								
								
								
								
							|  | @ -22,6 +22,7 @@ require ( | |||
| 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | ||||
| 	k8s.io/api v0.20.2 | ||||
| 	k8s.io/apimachinery v0.20.2 | ||||
| 	k8s.io/cli-runtime v0.20.2 | ||||
| 	k8s.io/client-go v0.20.2 | ||||
| 	k8s.io/utils v0.0.0-20201110183641-67b214c5f920 | ||||
| 	sigs.k8s.io/controller-runtime v0.7.0 | ||||
|  |  | |||
|  | @ -15,6 +15,8 @@ func NewSimpleProbe(uri string, port string, scheme corev1.URIScheme, initialDel | |||
| 			}, | ||||
| 		}, | ||||
| 		InitialDelaySeconds: initialDelaySeconds, | ||||
| 		SuccessThreshold:    int32(1), | ||||
| 		PeriodSeconds:       int32(1), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,10 +3,8 @@ package e2e | |||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||
|  | @ -15,9 +13,8 @@ import ( | |||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/plugins" | ||||
| 
 | ||||
| 	"github.com/bndr/gojenkins" | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	. "github.com/onsi/gomega" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
|  | @ -26,86 +23,8 @@ import ( | |||
| 
 | ||||
| const e2e = "e2e" | ||||
| 
 | ||||
| func TestConfiguration(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	namespace, ctx := setupTest(t) | ||||
| 
 | ||||
| 	defer showLogsAndCleanup(t, ctx) | ||||
| 
 | ||||
| 	jenkinsCRName := e2e | ||||
| 	numberOfExecutors := 6 | ||||
| 	numberOfExecutorsEnvName := "NUMBER_OF_EXECUTORS" | ||||
| 	systemMessage := "Configuration as Code integration works!!!" | ||||
| 	systemMessageEnvName := "SYSTEM_MESSAGE" | ||||
| 	priorityClassName := "" | ||||
| 	mySeedJob := seedJobConfig{ | ||||
| 		SeedJob: v1alpha2.SeedJob{ | ||||
| 			ID:                    "jenkins-operator", | ||||
| 			CredentialID:          "jenkins-operator", | ||||
| 			JenkinsCredentialType: v1alpha2.NoJenkinsCredentialCredentialType, | ||||
| 			Targets:               "cicd/jobs/*.jenkins", | ||||
| 			Description:           "Jenkins Operator repository", | ||||
| 			RepositoryBranch:      "master", | ||||
| 			RepositoryURL:         "https://github.com/jenkinsci/kubernetes-operator.git", | ||||
| 			PollSCM:               "1 1 1 1 1", | ||||
| 			UnstableOnDeprecation: true, | ||||
| 			BuildPeriodically:     "1 1 1 1 1", | ||||
| 			FailOnMissingPlugin:   true, | ||||
| 			IgnoreMissingFiles:    true, | ||||
| 			//AdditionalClasspath: can fail with the seed job agent
 | ||||
| 			GitHubPushTrigger: true, | ||||
| 		}, | ||||
| 	} | ||||
| 	groovyScripts := v1alpha2.GroovyScripts{ | ||||
| 		Customization: v1alpha2.Customization{ | ||||
| 			Configurations: []v1alpha2.ConfigMapRef{ | ||||
| 				{ | ||||
| 					Name: userConfigurationConfigMapName, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Secret: v1alpha2.SecretRef{ | ||||
| 				Name: userConfigurationSecretName, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	casc := v1alpha2.ConfigurationAsCode{ | ||||
| 		Customization: v1alpha2.Customization{ | ||||
| 			Configurations: []v1alpha2.ConfigMapRef{ | ||||
| 				{ | ||||
| 					Name: userConfigurationConfigMapName, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Secret: v1alpha2.SecretRef{ | ||||
| 				Name: userConfigurationSecretName, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	stringData := make(map[string]string) | ||||
| 	stringData[systemMessageEnvName] = systemMessage | ||||
| 	stringData[numberOfExecutorsEnvName] = fmt.Sprintf("%d", numberOfExecutors) | ||||
| 
 | ||||
| 	// base
 | ||||
| 	createUserConfigurationSecret(t, namespace, stringData) | ||||
| 	createUserConfigurationConfigMap(t, namespace, numberOfExecutorsEnvName, fmt.Sprintf("${%s}", systemMessageEnvName)) | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &[]v1alpha2.SeedJob{mySeedJob.SeedJob}, groovyScripts, casc, priorityClassName) | ||||
| 	createDefaultLimitsForContainersInNamespace(t, namespace) | ||||
| 	createKubernetesCredentialsProviderSecret(t, namespace, mySeedJob) | ||||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||
| 	verifyJenkinsMasterPodAttributes(t, jenkins) | ||||
| 	verifyServices(t, jenkins) | ||||
| 	jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(t, jenkins, namespace) | ||||
| 	defer cleanUpFunc() | ||||
| 	verifyPlugins(t, jenkinsClient, jenkins) | ||||
| 
 | ||||
| 	// user
 | ||||
| 	waitForJenkinsUserConfigurationToComplete(t, jenkins) | ||||
| 	verifyUserConfiguration(t, jenkinsClient, numberOfExecutors, systemMessage) | ||||
| 	verifyJenkinsSeedJobs(t, jenkinsClient, []seedJobConfig{mySeedJob}) | ||||
| } | ||||
| 
 | ||||
| func TestPlugins(t *testing.T) { | ||||
| // FIXME
 | ||||
| /*func TestPlugins(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	namespace, ctx := setupTest(t) | ||||
| 	// Deletes test namespace
 | ||||
|  | @ -145,28 +64,11 @@ func TestPlugins(t *testing.T) { | |||
| 	build, err := job.GetLastBuild() | ||||
| 	require.NoError(t, err) | ||||
| 	assert.True(t, build.IsGood()) | ||||
| } | ||||
| }*/ | ||||
| 
 | ||||
| func TestPriorityClass(t *testing.T) { | ||||
| 	if skipTestPriorityClass { | ||||
| 		t.Skip() | ||||
| 	} | ||||
| 	t.Parallel() | ||||
| 	namespace, ctx := setupTest(t) | ||||
| 	defer showLogsAndCleanup(t, ctx) | ||||
| func createUserConfigurationSecret(namespace string, stringData map[string]string) { | ||||
| 	By("creating user configuration secret") | ||||
| 
 | ||||
| 	jenkinsCRName := "k8s-ete-priority-class-existing" | ||||
| 	// One of the existing priority classes
 | ||||
| 	priorityClassName := "system-cluster-critical" | ||||
| 
 | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, nil, v1alpha2.GroovyScripts{}, v1alpha2.ConfigurationAsCode{}, priorityClassName) | ||||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||
| 	verifyJenkinsMasterPodAttributes(t, jenkins) | ||||
| 	_, cleanUpFunc := verifyJenkinsAPIConnection(t, jenkins, namespace) | ||||
| 	defer cleanUpFunc() | ||||
| } | ||||
| 
 | ||||
| func createUserConfigurationSecret(t *testing.T, namespace string, stringData map[string]string) { | ||||
| 	userConfiguration := &corev1.Secret{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:      userConfigurationSecretName, | ||||
|  | @ -175,13 +77,13 @@ func createUserConfigurationSecret(t *testing.T, namespace string, stringData ma | |||
| 		StringData: stringData, | ||||
| 	} | ||||
| 
 | ||||
| 	t.Logf("User configuration secret %+v", *userConfiguration) | ||||
| 	if err := framework.Global.Client.Create(context.TODO(), userConfiguration, nil); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "User configuration secret %+v\n", *userConfiguration) | ||||
| 	Expect(k8sClient.Create(context.TODO(), userConfiguration)).Should(Succeed()) | ||||
| } | ||||
| 
 | ||||
| func createUserConfigurationConfigMap(t *testing.T, namespace string, numberOfExecutorsSecretKeyName string, systemMessage string) { | ||||
| func createUserConfigurationConfigMap(namespace string, numberOfExecutorsSecretKeyName string, systemMessage string) { | ||||
| 	By("creating user configuration config map") | ||||
| 
 | ||||
| 	userConfiguration := &corev1.ConfigMap{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:      userConfigurationConfigMapName, | ||||
|  | @ -203,13 +105,13 @@ unclassified: | |||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	t.Logf("User configuration %+v", *userConfiguration) | ||||
| 	if err := framework.Global.Client.Create(context.TODO(), userConfiguration, nil); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "User configuration %+v\n", *userConfiguration) | ||||
| 	Expect(k8sClient.Create(context.TODO(), userConfiguration)).Should(Succeed()) | ||||
| } | ||||
| 
 | ||||
| func createDefaultLimitsForContainersInNamespace(t *testing.T, namespace string) { | ||||
| func createDefaultLimitsForContainersInNamespace(namespace string) { | ||||
| 	By("creating default limits for containers in namespace") | ||||
| 
 | ||||
| 	limitRange := &corev1.LimitRange{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:      e2e, | ||||
|  | @ -232,31 +134,34 @@ func createDefaultLimitsForContainersInNamespace(t *testing.T, namespace string) | |||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	t.Logf("LimitRange %+v", *limitRange) | ||||
| 	if err := framework.Global.Client.Create(context.TODO(), limitRange, nil); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "LimitRange %+v\n", *limitRange) | ||||
| 	Expect(k8sClient.Create(context.TODO(), limitRange)).Should(Succeed()) | ||||
| } | ||||
| 
 | ||||
| func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	jenkinsPod := getJenkinsMasterPod(t, jenkins) | ||||
| 	jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name) | ||||
| func verifyJenkinsMasterPodAttributes(jenkins *v1alpha2.Jenkins) { | ||||
| 	By("creating Jenkins master pod properly") | ||||
| 
 | ||||
| 	assertMapContainsElementsFromAnotherMap(t, jenkins.Spec.Master.Annotations, jenkinsPod.ObjectMeta.Annotations) | ||||
| 	assert.Equal(t, jenkins.Spec.Master.NodeSelector, jenkinsPod.Spec.NodeSelector) | ||||
| 	jenkinsPod := getJenkinsMasterPod(jenkins) | ||||
| 	jenkins = getJenkins(jenkins.Namespace, jenkins.Name) | ||||
| 
 | ||||
| 	assert.Equal(t, resources.JenkinsMasterContainerName, jenkinsPod.Spec.Containers[0].Name) | ||||
| 	assert.Equal(t, len(jenkins.Spec.Master.Containers), len(jenkinsPod.Spec.Containers)) | ||||
| 	assertMapContainsElementsFromAnotherMap(jenkins.Spec.Master.Annotations, jenkinsPod.ObjectMeta.Annotations) | ||||
| 	Expect(jenkinsPod.Spec.NodeSelector).Should(Equal(jenkins.Spec.Master.NodeSelector)) | ||||
| 
 | ||||
| 	assert.Equal(t, jenkins.Spec.Master.SecurityContext, jenkinsPod.Spec.SecurityContext) | ||||
| 	assert.Equal(t, jenkins.Spec.Master.Containers[0].Command, jenkinsPod.Spec.Containers[0].Command) | ||||
| 	Expect(jenkinsPod.Spec.Containers[0].Name).Should(Equal(resources.JenkinsMasterContainerName)) | ||||
| 	Expect(jenkinsPod.Spec.Containers).Should(HaveLen(len(jenkins.Spec.Master.Containers))) | ||||
| 
 | ||||
| 	assert.Equal(t, resources.GetJenkinsMasterPodLabels(*jenkins), jenkinsPod.Labels) | ||||
| 	assert.Equal(t, jenkins.Spec.Master.PriorityClassName, jenkinsPod.Spec.PriorityClassName) | ||||
| 	if jenkins.Spec.Master.SecurityContext == nil { | ||||
| 		jenkins.Spec.Master.SecurityContext = &corev1.PodSecurityContext{} | ||||
| 	} | ||||
| 	Expect(jenkinsPod.Spec.SecurityContext).Should(Equal(jenkins.Spec.Master.SecurityContext)) | ||||
| 	Expect(jenkinsPod.Spec.Containers[0].Command).Should(Equal(jenkins.Spec.Master.Containers[0].Command)) | ||||
| 
 | ||||
| 	Expect(jenkinsPod.Labels).Should(Equal(resources.GetJenkinsMasterPodLabels(*jenkins))) | ||||
| 	Expect(jenkinsPod.Spec.PriorityClassName).Should(Equal(jenkins.Spec.Master.PriorityClassName)) | ||||
| 
 | ||||
| 	for _, actualContainer := range jenkinsPod.Spec.Containers { | ||||
| 		if actualContainer.Name == resources.JenkinsMasterContainerName { | ||||
| 			verifyContainer(t, resources.NewJenkinsMasterContainer(jenkins), actualContainer) | ||||
| 			verifyContainer(resources.NewJenkinsMasterContainer(jenkins), actualContainer) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
|  | @ -269,11 +174,11 @@ func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *v1alpha2.Jenkins) { | |||
| 		} | ||||
| 
 | ||||
| 		if expectedContainer == nil { | ||||
| 			t.Errorf("Container '%+v' not found in pod", actualContainer) | ||||
| 			Fail(fmt.Sprintf("Container '%+v' not found in pod", actualContainer)) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		verifyContainer(t, *expectedContainer, actualContainer) | ||||
| 		verifyContainer(*expectedContainer, actualContainer) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, expectedVolume := range jenkins.Spec.Master.Volumes { | ||||
|  | @ -281,58 +186,54 @@ func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *v1alpha2.Jenkins) { | |||
| 		for _, actualVolume := range jenkinsPod.Spec.Volumes { | ||||
| 			if expectedVolume.Name == actualVolume.Name { | ||||
| 				volumeFound = true | ||||
| 				assert.Equal(t, expectedVolume, actualVolume) | ||||
| 				Expect(actualVolume).Should(Equal(expectedVolume)) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if !volumeFound { | ||||
| 			t.Errorf("Missing volume '+%v', actaul volumes '%+v'", expectedVolume, jenkinsPod.Spec.Volumes) | ||||
| 			Fail(fmt.Sprintf("Missing volume '+%v', actaul volumes '%+v'", expectedVolume, jenkinsPod.Spec.Volumes)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	t.Log("Jenkins pod attributes are valid") | ||||
| } | ||||
| 
 | ||||
| func verifyContainer(t *testing.T, expected corev1.Container, actual corev1.Container) { | ||||
| 	assert.Equal(t, expected.Args, actual.Args, expected.Name, expected.Name) | ||||
| 	assert.Equal(t, expected.Command, actual.Command, expected.Name) | ||||
| 	assert.ElementsMatch(t, expected.Env, actual.Env, expected.Name) | ||||
| 	assert.Equal(t, expected.EnvFrom, actual.EnvFrom, expected.Name) | ||||
| 	assert.Equal(t, expected.Image, actual.Image, expected.Name) | ||||
| 	assert.Equal(t, expected.ImagePullPolicy, actual.ImagePullPolicy, expected.Name) | ||||
| 	assert.Equal(t, expected.Lifecycle, actual.Lifecycle, expected.Name) | ||||
| 	assert.Equal(t, expected.LivenessProbe, actual.LivenessProbe, expected.Name) | ||||
| 	assert.Equal(t, expected.Ports, actual.Ports, expected.Name) | ||||
| 	assert.Equal(t, expected.ReadinessProbe, actual.ReadinessProbe, expected.Name) | ||||
| 	assert.Equal(t, expected.Resources, actual.Resources, expected.Name) | ||||
| 	assert.Equal(t, expected.SecurityContext, actual.SecurityContext, expected.Name) | ||||
| 	assert.Equal(t, expected.WorkingDir, actual.WorkingDir, expected.Name) | ||||
| func verifyContainer(expected corev1.Container, actual corev1.Container) { | ||||
| 	Expect(actual.Args).Should(Equal(expected.Args), expected.Name) | ||||
| 	Expect(actual.Command).Should(Equal(expected.Command), expected.Name) | ||||
| 	Expect(actual.Env).Should(ConsistOf(expected.Env), expected.Name) | ||||
| 	Expect(actual.EnvFrom).Should(Equal(expected.EnvFrom), expected.Name) | ||||
| 	Expect(actual.Image).Should(Equal(expected.Image), expected.Name) | ||||
| 	Expect(actual.ImagePullPolicy).Should(Equal(expected.ImagePullPolicy), expected.Name) | ||||
| 	Expect(actual.Lifecycle).Should(Equal(expected.Lifecycle), expected.Name) | ||||
| 	Expect(actual.LivenessProbe).Should(Equal(expected.LivenessProbe), expected.Name) | ||||
| 	Expect(actual.Ports).Should(Equal(expected.Ports), expected.Name) | ||||
| 	Expect(actual.ReadinessProbe).Should(Equal(expected.ReadinessProbe), expected.Name) | ||||
| 	Expect(actual.Resources).Should(Equal(expected.Resources), expected.Name) | ||||
| 	Expect(actual.SecurityContext).Should(Equal(expected.SecurityContext), expected.Name) | ||||
| 	Expect(actual.WorkingDir).Should(Equal(expected.WorkingDir), expected.Name) | ||||
| 	if !base.CompareContainerVolumeMounts(expected, actual) { | ||||
| 		t.Errorf("Volume mounts are different in container '%s': expected '%+v', actual '%+v'", | ||||
| 			expected.Name, expected.VolumeMounts, actual.VolumeMounts) | ||||
| 		Fail(fmt.Sprintf("Volume mounts are different in container '%s': expected '%+v', actual '%+v'", | ||||
| 			expected.Name, expected.VolumeMounts, expected.VolumeMounts)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func verifyPlugins(t *testing.T, jenkinsClient jenkinsclient.Jenkins, jenkins *v1alpha2.Jenkins) { | ||||
| func verifyPlugins(jenkinsClient jenkinsclient.Jenkins, jenkins *v1alpha2.Jenkins) { | ||||
| 	By("installing plugins in Jenkins instance") | ||||
| 
 | ||||
| 	installedPlugins, err := jenkinsClient.GetPlugins(1) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 
 | ||||
| 	for _, basePlugin := range plugins.BasePlugins() { | ||||
| 		if found, ok := isPluginValid(installedPlugins, basePlugin); !ok { | ||||
| 			t.Fatalf("Invalid plugin '%s', actual '%+v'", basePlugin, found) | ||||
| 			Fail(fmt.Sprintf("Invalid plugin '%s', actual '%+v'", basePlugin, found)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, userPlugin := range jenkins.Spec.Master.Plugins { | ||||
| 		plugin := plugins.Plugin{Name: userPlugin.Name, Version: userPlugin.Version} | ||||
| 		if found, ok := isPluginValid(installedPlugins, plugin); !ok { | ||||
| 			t.Fatalf("Invalid plugin '%s', actual '%+v'", plugin, found) | ||||
| 			Fail(fmt.Sprintf("Invalid plugin '%s', actual '%+v'", plugin, found)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	t.Log("All plugins have been installed") | ||||
| } | ||||
| 
 | ||||
| func isPluginValid(plugins *gojenkins.Plugins, requiredPlugin plugins.Plugin) (*gojenkins.Plugin, bool) { | ||||
|  | @ -348,13 +249,15 @@ func isPluginValid(plugins *gojenkins.Plugins, requiredPlugin plugins.Plugin) (* | |||
| 	return p, requiredPlugin.Version == p.Version | ||||
| } | ||||
| 
 | ||||
| func verifyUserConfiguration(t *testing.T, jenkinsClient jenkinsclient.Jenkins, amountOfExecutors int, systemMessage string) { | ||||
| func verifyUserConfiguration(jenkinsClient jenkinsclient.Jenkins, amountOfExecutors int, systemMessage string) { | ||||
| 	By("configuring Jenkins by groovy scripts") | ||||
| 
 | ||||
| 	checkConfigurationViaGroovyScript := fmt.Sprintf(` | ||||
| if (!new Integer(%d).equals(Jenkins.instance.numExecutors)) { | ||||
| 	throw new Exception("Configuration via groovy scripts failed") | ||||
| }`, amountOfExecutors) | ||||
| 	logs, err := jenkinsClient.ExecuteScript(checkConfigurationViaGroovyScript) | ||||
| 	assert.NoError(t, err, logs) | ||||
| 	Expect(err).NotTo(HaveOccurred(), logs) | ||||
| 
 | ||||
| 	checkSecretLoaderViaGroovyScript := fmt.Sprintf(` | ||||
| if (!new Integer(%d).equals(new Integer(secrets['NUMBER_OF_EXECUTORS']))) { | ||||
|  | @ -363,30 +266,33 @@ if (!new Integer(%d).equals(new Integer(secrets['NUMBER_OF_EXECUTORS']))) { | |||
| 
 | ||||
| 	loader := groovy.AddSecretsLoaderToGroovyScript("/var/jenkins/groovy-scripts-secrets") | ||||
| 	logs, err = jenkinsClient.ExecuteScript(loader(checkSecretLoaderViaGroovyScript)) | ||||
| 	assert.NoError(t, err, logs) | ||||
| 	Expect(err).NotTo(HaveOccurred(), logs) | ||||
| 
 | ||||
| 	By("configuring Jenkins by CasC") | ||||
| 	checkConfigurationAsCode := fmt.Sprintf(` | ||||
| if (!"%s".equals(Jenkins.instance.systemMessage)) { | ||||
| 	throw new Exception("Configuration as code failed") | ||||
| }`, systemMessage) | ||||
| 	logs, err = jenkinsClient.ExecuteScript(checkConfigurationAsCode) | ||||
| 	assert.NoError(t, err, logs) | ||||
| 	Expect(err).NotTo(HaveOccurred(), logs) | ||||
| } | ||||
| 
 | ||||
| func verifyServices(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	jenkinsHTTPService := getJenkinsService(t, jenkins, "http") | ||||
| 	jenkinsSlaveService := getJenkinsService(t, jenkins, "slave") | ||||
| 	assert.Equal(t, intstr.IntOrString{IntVal: constants.DefaultHTTPPortInt32, Type: intstr.Int}, jenkinsHTTPService.Spec.Ports[0].TargetPort) | ||||
| 	assert.Equal(t, intstr.IntOrString{IntVal: constants.DefaultSlavePortInt32, Type: intstr.Int}, jenkinsSlaveService.Spec.Ports[0].TargetPort) | ||||
| func verifyServices(jenkins *v1alpha2.Jenkins) { | ||||
| 	By("creating Jenkins services properly") | ||||
| 
 | ||||
| 	jenkinsHTTPService := getJenkinsService(jenkins, "http") | ||||
| 	jenkinsSlaveService := getJenkinsService(jenkins, "slave") | ||||
| 	Expect(jenkinsHTTPService.Spec.Ports[0].TargetPort).Should(Equal(intstr.IntOrString{IntVal: constants.DefaultHTTPPortInt32, Type: intstr.Int})) | ||||
| 	Expect(jenkinsSlaveService.Spec.Ports[0].TargetPort).Should(Equal(intstr.IntOrString{IntVal: constants.DefaultSlavePortInt32, Type: intstr.Int})) | ||||
| } | ||||
| 
 | ||||
| func assertMapContainsElementsFromAnotherMap(t *testing.T, expected map[string]string, actual map[string]string) { | ||||
| func assertMapContainsElementsFromAnotherMap(expected map[string]string, actual map[string]string) { | ||||
| 	for key, expectedValue := range expected { | ||||
| 		actualValue, keyExists := actual[key] | ||||
| 		if !keyExists { | ||||
| 			assert.Failf(t, "key '%s' doesn't exist in map '%+v'", key, actual) | ||||
| 			Fail(fmt.Sprintf("key '%s' doesn't exist in map '%+v'", key, actual)) | ||||
| 			continue | ||||
| 		} | ||||
| 		assert.Equal(t, expectedValue, actualValue, expected, actual) | ||||
| 		Expect(actualValue).Should(Equal(expectedValue), key, expected, actual) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| 
 | ||||
| package e2e | ||||
| 
 | ||||
| // TODO
 | ||||
| /* | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os/exec" | ||||
|  | @ -66,3 +68,4 @@ func TestDeployHelmChart(t *testing.T) { | |||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||
| 	waitForJenkinsUserConfigurationToComplete(t, jenkins) | ||||
| } | ||||
| /* | ||||
|  | @ -0,0 +1,141 @@ | |||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 
 | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	// +kubebuilder:scaffold:imports
 | ||||
| ) | ||||
| 
 | ||||
| var _ = Describe("Jenkins controller configuration", func() { | ||||
| 
 | ||||
| 	const ( | ||||
| 		jenkinsCRName            = e2e | ||||
| 		numberOfExecutors        = 6 | ||||
| 		numberOfExecutorsEnvName = "NUMBER_OF_EXECUTORS" | ||||
| 		systemMessage            = "Configuration as Code integration works!!!" | ||||
| 		systemMessageEnvName     = "SYSTEM_MESSAGE" | ||||
| 		priorityClassName        = "" | ||||
| 	) | ||||
| 
 | ||||
| 	var ( | ||||
| 		namespace *corev1.Namespace | ||||
| 		jenkins   *v1alpha2.Jenkins | ||||
| 		mySeedJob = seedJobConfig{ | ||||
| 			SeedJob: v1alpha2.SeedJob{ | ||||
| 				ID:                    "jenkins-operator", | ||||
| 				CredentialID:          "jenkins-operator", | ||||
| 				JenkinsCredentialType: v1alpha2.NoJenkinsCredentialCredentialType, | ||||
| 				Targets:               "cicd/jobs/*.jenkins", | ||||
| 				Description:           "Jenkins Operator repository", | ||||
| 				RepositoryBranch:      "master", | ||||
| 				RepositoryURL:         "https://github.com/jenkinsci/kubernetes-operator.git", | ||||
| 				PollSCM:               "1 1 1 1 1", | ||||
| 				UnstableOnDeprecation: true, | ||||
| 				BuildPeriodically:     "1 1 1 1 1", | ||||
| 				FailOnMissingPlugin:   true, | ||||
| 				IgnoreMissingFiles:    true, | ||||
| 				//AdditionalClasspath: can fail with the seed job agent
 | ||||
| 				GitHubPushTrigger: true, | ||||
| 			}, | ||||
| 		} | ||||
| 		groovyScripts = v1alpha2.GroovyScripts{ | ||||
| 			Customization: v1alpha2.Customization{ | ||||
| 				Configurations: []v1alpha2.ConfigMapRef{ | ||||
| 					{ | ||||
| 						Name: userConfigurationConfigMapName, | ||||
| 					}, | ||||
| 				}, | ||||
| 				Secret: v1alpha2.SecretRef{ | ||||
| 					Name: userConfigurationSecretName, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		casc = v1alpha2.ConfigurationAsCode{ | ||||
| 			Customization: v1alpha2.Customization{ | ||||
| 				Configurations: []v1alpha2.ConfigMapRef{ | ||||
| 					{ | ||||
| 						Name: userConfigurationConfigMapName, | ||||
| 					}, | ||||
| 				}, | ||||
| 				Secret: v1alpha2.SecretRef{ | ||||
| 					Name: userConfigurationSecretName, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		userConfigurationSecretData = map[string]string{ | ||||
| 			systemMessageEnvName:     systemMessage, | ||||
| 			numberOfExecutorsEnvName: fmt.Sprintf("%d", numberOfExecutors), | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| 	BeforeEach(func() { | ||||
| 		namespace = createNamespace() | ||||
| 
 | ||||
| 		createUserConfigurationSecret(namespace.Name, userConfigurationSecretData) | ||||
| 		createUserConfigurationConfigMap(namespace.Name, numberOfExecutorsEnvName, fmt.Sprintf("${%s}", systemMessageEnvName)) | ||||
| 		jenkins = createJenkinsCR(jenkinsCRName, namespace.Name, &[]v1alpha2.SeedJob{mySeedJob.SeedJob}, groovyScripts, casc, priorityClassName) | ||||
| 		createDefaultLimitsForContainersInNamespace(namespace.Name) | ||||
| 		createKubernetesCredentialsProviderSecret(namespace.Name, mySeedJob) | ||||
| 	}) | ||||
| 
 | ||||
| 	AfterEach(func() { | ||||
| 		destroyNamespace(namespace) | ||||
| 	}) | ||||
| 
 | ||||
| 	Context("when deploying CR to cluster", func() { | ||||
| 		It("creates Jenkins instance and configures it", func() { | ||||
| 			waitForJenkinsBaseConfigurationToComplete(jenkins) | ||||
| 			verifyJenkinsMasterPodAttributes(jenkins) | ||||
| 			verifyServices(jenkins) | ||||
| 			jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(jenkins, namespace.Name) | ||||
| 			defer cleanUpFunc() | ||||
| 			verifyPlugins(jenkinsClient, jenkins) | ||||
| 			waitForJenkinsUserConfigurationToComplete(jenkins) | ||||
| 			verifyUserConfiguration(jenkinsClient, numberOfExecutors, systemMessage) | ||||
| 			verifyJenkinsSeedJobs(jenkinsClient, []seedJobConfig{mySeedJob}) | ||||
| 		}) | ||||
| 	}) | ||||
| }) | ||||
| 
 | ||||
| var _ = Describe("Jenkins controller priority class", func() { | ||||
| 
 | ||||
| 	const ( | ||||
| 		jenkinsCRName     = "k8s-ete-priority-class-existing" | ||||
| 		priorityClassName = "system-cluster-critical" | ||||
| 	) | ||||
| 
 | ||||
| 	var ( | ||||
| 		namespace     *corev1.Namespace | ||||
| 		jenkins       *v1alpha2.Jenkins | ||||
| 		groovyScripts = v1alpha2.GroovyScripts{ | ||||
| 			Customization: v1alpha2.Customization{ | ||||
| 				Configurations: []v1alpha2.ConfigMapRef{}, | ||||
| 			}, | ||||
| 		} | ||||
| 		casc = v1alpha2.ConfigurationAsCode{ | ||||
| 			Customization: v1alpha2.Customization{ | ||||
| 				Configurations: []v1alpha2.ConfigMapRef{}, | ||||
| 			}, | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| 	BeforeEach(func() { | ||||
| 		namespace = createNamespace() | ||||
| 		jenkins = createJenkinsCR(jenkinsCRName, namespace.Name, nil, groovyScripts, casc, priorityClassName) | ||||
| 	}) | ||||
| 
 | ||||
| 	AfterEach(func() { | ||||
| 		destroyNamespace(namespace) | ||||
| 	}) | ||||
| 
 | ||||
| 	Context("when deploying CR with priority class to cluster", func() { | ||||
| 		It("creates Jenkins instance and configures it", func() { | ||||
| 			waitForJenkinsBaseConfigurationToComplete(jenkins) | ||||
| 			verifyJenkinsMasterPodAttributes(jenkins) | ||||
| 		}) | ||||
| 	}) | ||||
| }) | ||||
|  | @ -3,25 +3,24 @@ package e2e | |||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/constants" | ||||
| 
 | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	. "github.com/onsi/gomega" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	rbacv1 "k8s.io/api/rbac/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/fields" | ||||
| 	"k8s.io/apimachinery/pkg/labels" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	"k8s.io/apimachinery/pkg/util/intstr" | ||||
| 	"k8s.io/client-go/kubernetes" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/client" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
|  | @ -29,31 +28,25 @@ const ( | |||
| 	userConfigurationSecretName    = "user-secret" | ||||
| ) | ||||
| 
 | ||||
| func getJenkins(t *testing.T, namespace, name string) *v1alpha2.Jenkins { | ||||
| func getJenkins(namespace, name string) *v1alpha2.Jenkins { | ||||
| 	jenkins := &v1alpha2.Jenkins{} | ||||
| 	namespaceName := types.NamespacedName{Namespace: namespace, Name: name} | ||||
| 	if err := framework.Global.Client.Get(context.TODO(), namespaceName, jenkins); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	Expect(k8sClient.Get(context.TODO(), namespaceName, jenkins)).Should(Succeed()) | ||||
| 	return jenkins | ||||
| } | ||||
| 
 | ||||
| func getJenkinsMasterPod(t *testing.T, jenkins *v1alpha2.Jenkins) *corev1.Pod { | ||||
| 	lo := metav1.ListOptions{ | ||||
| 		LabelSelector: labels.SelectorFromSet(resources.GetJenkinsMasterPodLabels(*jenkins)).String(), | ||||
| func getJenkinsMasterPod(jenkins *v1alpha2.Jenkins) *corev1.Pod { | ||||
| 	lo := &client.ListOptions{ | ||||
| 		LabelSelector: labels.SelectorFromSet(resources.GetJenkinsMasterPodLabels(*jenkins)), | ||||
| 		Namespace:     jenkins.Namespace, | ||||
| 	} | ||||
| 	podList, err := framework.Global.KubeClient.CoreV1().Pods(jenkins.ObjectMeta.Namespace).List(lo) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if len(podList.Items) != 1 { | ||||
| 		t.Fatalf("Jenkins pod not found, pod list: %+v", podList) | ||||
| 	} | ||||
| 	return &podList.Items[0] | ||||
| 	pods := &corev1.PodList{} | ||||
| 	Expect(k8sClient.List(context.TODO(), pods, lo)).Should(Succeed()) | ||||
| 	Expect(pods.Items).Should(HaveLen(1), fmt.Sprintf("Jenkins pod not found, pod list: %+v", pods.Items)) | ||||
| 	return &pods.Items[0] | ||||
| } | ||||
| 
 | ||||
| func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha2.SeedJob, groovyScripts v1alpha2.GroovyScripts, casc v1alpha2.ConfigurationAsCode, priorityClassName string) *v1alpha2.Jenkins { | ||||
| func createJenkinsCR(name, namespace string, seedJob *[]v1alpha2.SeedJob, groovyScripts v1alpha2.GroovyScripts, casc v1alpha2.ConfigurationAsCode, priorityClassName string) *v1alpha2.Jenkins { | ||||
| 	var seedJobs []v1alpha2.SeedJob | ||||
| 	if seedJob != nil { | ||||
| 		seedJobs = append(seedJobs, *seedJob...) | ||||
|  | @ -90,6 +83,8 @@ func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha2.S | |||
| 							InitialDelaySeconds: int32(80), | ||||
| 							TimeoutSeconds:      int32(4), | ||||
| 							FailureThreshold:    int32(10), | ||||
| 							SuccessThreshold:    int32(1), | ||||
| 							PeriodSeconds:       int32(1), | ||||
| 						}, | ||||
| 						LivenessProbe: &corev1.Probe{ | ||||
| 							Handler: corev1.Handler{ | ||||
|  | @ -102,6 +97,8 @@ func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha2.S | |||
| 							InitialDelaySeconds: int32(80), | ||||
| 							TimeoutSeconds:      int32(4), | ||||
| 							FailureThreshold:    int32(10), | ||||
| 							SuccessThreshold:    int32(1), | ||||
| 							PeriodSeconds:       int32(1), | ||||
| 						}, | ||||
| 						VolumeMounts: []corev1.VolumeMount{ | ||||
| 							{ | ||||
|  | @ -146,25 +143,23 @@ func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha2.S | |||
| 			Name:     resources.GetResourceName(jenkins), | ||||
| 		}, | ||||
| 	} | ||||
| 	updateJenkinsCR(t, jenkins) | ||||
| 	updateJenkinsCR(jenkins) | ||||
| 
 | ||||
| 	t.Logf("Jenkins CR %+v", *jenkins) | ||||
| 	if err := framework.Global.Client.Create(context.TODO(), jenkins, nil); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins CR %+v\n", *jenkins) | ||||
| 
 | ||||
| 	Expect(k8sClient.Create(context.TODO(), jenkins)).Should(Succeed()) | ||||
| 
 | ||||
| 	return jenkins | ||||
| } | ||||
| 
 | ||||
| func createJenkinsAPIClientFromServiceAccount(t *testing.T, jenkins *v1alpha2.Jenkins, jenkinsAPIURL string) (jenkinsclient.Jenkins, error) { | ||||
| 	t.Log("Creating Jenkins API client from service account") | ||||
| func createJenkinsAPIClientFromServiceAccount(jenkins *v1alpha2.Jenkins, jenkinsAPIURL string) (jenkinsclient.Jenkins, error) { | ||||
| 	podName := resources.GetJenkinsMasterPodName(jenkins) | ||||
| 
 | ||||
| 	clientSet, err := kubernetes.NewForConfig(framework.Global.KubeConfig) | ||||
| 	clientSet, err := kubernetes.NewForConfig(cfg) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	config := configuration.Configuration{Jenkins: jenkins, ClientSet: *clientSet, Config: framework.Global.KubeConfig} | ||||
| 	config := configuration.Configuration{Jenkins: jenkins, ClientSet: *clientSet, Config: cfg} | ||||
| 	r := base.New(config, jenkinsclient.JenkinsAPIConnectionSettings{}) | ||||
| 
 | ||||
| 	token, _, err := r.Configuration.Exec(podName, resources.JenkinsMasterContainerName, []string{"cat", "/var/run/secrets/kubernetes.io/serviceaccount/token"}) | ||||
|  | @ -175,12 +170,12 @@ func createJenkinsAPIClientFromServiceAccount(t *testing.T, jenkins *v1alpha2.Je | |||
| 	return jenkinsclient.NewBearerTokenAuthorization(jenkinsAPIURL, token.String()) | ||||
| } | ||||
| 
 | ||||
| func createJenkinsAPIClientFromSecret(t *testing.T, jenkins *v1alpha2.Jenkins, jenkinsAPIURL string) (jenkinsclient.Jenkins, error) { | ||||
| 	t.Log("Creating Jenkins API client from secret") | ||||
| func createJenkinsAPIClientFromSecret(jenkins *v1alpha2.Jenkins, jenkinsAPIURL string) (jenkinsclient.Jenkins, error) { | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "Creating Jenkins API client from secret\n") | ||||
| 
 | ||||
| 	adminSecret := &corev1.Secret{} | ||||
| 	namespaceName := types.NamespacedName{Namespace: jenkins.Namespace, Name: resources.GetOperatorCredentialsSecretName(jenkins)} | ||||
| 	if err := framework.Global.Client.Get(context.TODO(), namespaceName, adminSecret); err != nil { | ||||
| 	if err := k8sClient.Get(context.TODO(), namespaceName, adminSecret); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
|  | @ -191,19 +186,19 @@ func createJenkinsAPIClientFromSecret(t *testing.T, jenkins *v1alpha2.Jenkins, j | |||
| 	) | ||||
| } | ||||
| 
 | ||||
| func verifyJenkinsAPIConnection(t *testing.T, jenkins *v1alpha2.Jenkins, namespace string) (jenkinsclient.Jenkins, func()) { | ||||
| func verifyJenkinsAPIConnection(jenkins *v1alpha2.Jenkins, namespace string) (jenkinsclient.Jenkins, func()) { | ||||
| 	By("establishing Jenkins API connection") | ||||
| 
 | ||||
| 	var service corev1.Service | ||||
| 	err := framework.Global.Client.Get(context.TODO(), types.NamespacedName{ | ||||
| 	err := k8sClient.Get(context.TODO(), types.NamespacedName{ | ||||
| 		Namespace: jenkins.Namespace, | ||||
| 		Name:      resources.GetJenkinsHTTPServiceName(jenkins), | ||||
| 	}, &service) | ||||
| 	require.NoError(t, err) | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 
 | ||||
| 	podName := resources.GetJenkinsMasterPodName(jenkins) | ||||
| 	port, cleanUpFunc, waitFunc, portForwardFunc, err := setupPortForwardToPod(t, namespace, podName, int(constants.DefaultHTTPPortInt32)) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	port, cleanUpFunc, waitFunc, portForwardFunc, err := setupPortForwardToPod(namespace, podName, int(constants.DefaultHTTPPortInt32)) | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 	go portForwardFunc() | ||||
| 	waitFunc() | ||||
| 
 | ||||
|  | @ -213,41 +208,33 @@ func verifyJenkinsAPIConnection(t *testing.T, jenkins *v1alpha2.Jenkins, namespa | |||
| 		UseNodePort: false, | ||||
| 	}.BuildJenkinsAPIUrl(service.Name, service.Namespace, service.Spec.Ports[0].Port, service.Spec.Ports[0].NodePort) | ||||
| 
 | ||||
| 	var client jenkinsclient.Jenkins | ||||
| 	var jenkinsClient jenkinsclient.Jenkins | ||||
| 	if jenkins.Spec.JenkinsAPISettings.AuthorizationStrategy == v1alpha2.ServiceAccountAuthorizationStrategy { | ||||
| 		client, err = createJenkinsAPIClientFromServiceAccount(t, jenkins, jenkinsAPIURL) | ||||
| 		jenkinsClient, err = createJenkinsAPIClientFromServiceAccount(jenkins, jenkinsAPIURL) | ||||
| 	} else { | ||||
| 		client, err = createJenkinsAPIClientFromSecret(t, jenkins, jenkinsAPIURL) | ||||
| 		jenkinsClient, err = createJenkinsAPIClientFromSecret(jenkins, jenkinsAPIURL) | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		defer cleanUpFunc() | ||||
| 		t.Fatal(err) | ||||
| 		Fail(err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	t.Log("I can establish connection to Jenkins API") | ||||
| 	return client, cleanUpFunc | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "I can establish connection to Jenkins API\n") | ||||
| 	return jenkinsClient, cleanUpFunc | ||||
| } | ||||
| 
 | ||||
| func restartJenkinsMasterPod(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	t.Log("Restarting Jenkins master pod") | ||||
| 	jenkinsPod := getJenkinsMasterPod(t, jenkins) | ||||
| 	err := framework.Global.Client.Delete(context.TODO(), jenkinsPod) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	t.Log("Jenkins master pod has been restarted") | ||||
| } | ||||
| /*func restartJenkinsMasterPod(jenkins *v1alpha2.Jenkins) { | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "Restarting Jenkins master pod") | ||||
| 	jenkinsPod := getJenkinsMasterPod(jenkins) | ||||
| 	Expect(k8sClient.Delete(context.TODO(), jenkinsPod)).Should(Succeed()) | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins master pod has been restarted") | ||||
| }*/ | ||||
| 
 | ||||
| func getJenkinsService(t *testing.T, jenkins *v1alpha2.Jenkins, serviceKind string) *corev1.Service { | ||||
| func getJenkinsService(jenkins *v1alpha2.Jenkins, serviceKind string) *corev1.Service { | ||||
| 	service := &corev1.Service{} | ||||
| 	serviceName := constants.OperatorName + "-" + serviceKind + "-" + jenkins.ObjectMeta.Name | ||||
| 	lo := metav1.ListOptions{ | ||||
| 		FieldSelector: fields.SelectorFromSet(fields.Set{"metadata.name": serviceName}).String(), | ||||
| 	} | ||||
| 	serviceList, err := framework.Global.KubeClient.CoreV1().Services(jenkins.Namespace).List(lo) | ||||
| 	Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: serviceName, Namespace: jenkins.Namespace}, service)).Should(Succeed()) | ||||
| 
 | ||||
| 	require.NoError(t, err) | ||||
| 	require.Equal(t, 1, len(serviceList.Items), fmt.Sprintf("'%s' service not found", serviceName)) | ||||
| 
 | ||||
| 	return &serviceList.Items[0] | ||||
| 	return service | ||||
| } | ||||
|  | @ -1,69 +0,0 @@ | |||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/constants" | ||||
| 
 | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	"github.com/operator-framework/operator-sdk/pkg/test/e2eutil" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	jenkinsOperatorDeploymentName     = constants.OperatorName | ||||
| 	seedJobConfigurationParameterName = "seed-job-config" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	seedJobConfigurationFile *string | ||||
| ) | ||||
| 
 | ||||
| func TestMain(m *testing.M) { | ||||
| 	seedJobConfigurationFile = flag.String(seedJobConfigurationParameterName, "", "path to seed job config") | ||||
| 
 | ||||
| 	framework.MainEntry(m) | ||||
| } | ||||
| 
 | ||||
| func setupTest(t *testing.T) (string, *framework.Context) { | ||||
| 	ctx := framework.NewContext(t) | ||||
| 	err := ctx.InitializeClusterResources(nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("could not initialize cluster resources: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	defer func() { | ||||
| 		showLogsIfTestHasFailed(t, ctx) | ||||
| 		if t.Failed() && ctx != nil { | ||||
| 			ctx.Cleanup() | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	jenkinsServiceList := &v1alpha2.JenkinsList{ | ||||
| 		TypeMeta: metav1.TypeMeta{ | ||||
| 			Kind:       v1alpha2.Kind, | ||||
| 			APIVersion: v1alpha2.SchemeGroupVersion.String(), | ||||
| 		}, | ||||
| 	} | ||||
| 	err = framework.AddToFrameworkScheme(apis.AddToScheme, jenkinsServiceList) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("could not add scheme to framework scheme: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	namespace, err := ctx.GetOperatorNamespace() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("could not get namespace: %v", err) | ||||
| 	} | ||||
| 	t.Logf("Test namespace '%s'", namespace) | ||||
| 
 | ||||
| 	// wait for jenkins-operator to be ready
 | ||||
| 	err = e2eutil.WaitForDeployment(t, framework.Global.KubeClient, namespace, jenkinsOperatorDeploymentName, 1, retryInterval, timeout) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return namespace, ctx | ||||
| } | ||||
|  | @ -4,17 +4,14 @@ | |||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	skipTestSafeRestart   = false | ||||
| 	skipTestPriorityClass = false | ||||
| //skipTestSafeRestart   = false
 | ||||
| //skipTestPriorityClass = false
 | ||||
| ) | ||||
| 
 | ||||
| func updateJenkinsCR(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	t.Log("Update Jenkins CR") | ||||
| func updateJenkinsCR(jenkins *v1alpha2.Jenkins) { | ||||
| 	// do nothing
 | ||||
| } | ||||
|  |  | |||
|  | @ -3,9 +3,7 @@ | |||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||
| 
 | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
|  | @ -16,9 +14,7 @@ const ( | |||
| 	skipTestPriorityClass = true | ||||
| ) | ||||
| 
 | ||||
| func updateJenkinsCR(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	t.Log("Update Jenkins CR: OpenShift") | ||||
| 
 | ||||
| func updateJenkinsCR(jenkins *v1alpha2.Jenkins) { | ||||
| 	jenkins.Spec.Master.Containers[0].Image = "quay.io/openshift/origin-jenkins" | ||||
| 	jenkins.Spec.Master.Containers[0].Command = []string{ | ||||
| 		"bash", | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| 
 | ||||
| package e2e | ||||
| 
 | ||||
| // TODO
 | ||||
| /* | ||||
| import ( | ||||
| 	"context" | ||||
| 	"testing" | ||||
|  | @ -100,3 +102,4 @@ func updateJenkinsCR(t *testing.T, jenkins *v1alpha2.Jenkins) { | |||
| 		jenkins.Spec.Master.Plugins = jenkins.Spec.Master.Plugins[0:3] // remove devoptics plugin
 | ||||
| 	} | ||||
| } | ||||
| */ | ||||
|  | @ -1,155 +0,0 @@ | |||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"sort" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	"k8s.io/api/events/v1beta1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/labels" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	podLogTailLimit       int64 = 15 | ||||
| 	kubernetesEventsLimit int64 = 15 | ||||
| 	// MUST match the labels in the deployment manifest: deploy/operator.yaml
 | ||||
| 	operatorPodLabels = map[string]string{ | ||||
| 		"name": "jenkins-operator", | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| func getOperatorPod(namespace string) (*v1.Pod, error) { | ||||
| 	listOptions := metav1.ListOptions{ | ||||
| 		LabelSelector: labels.SelectorFromSet(operatorPodLabels).String(), | ||||
| 	} | ||||
| 
 | ||||
| 	podList, err := framework.Global.KubeClient.CoreV1().Pods(namespace).List(listOptions) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(podList.Items) != 1 { | ||||
| 		return nil, fmt.Errorf("expected exactly one pod, got: '%+v'", podList) | ||||
| 	} | ||||
| 
 | ||||
| 	return &podList.Items[0], nil | ||||
| } | ||||
| 
 | ||||
| func getOperatorLogs(namespace string) (string, error) { | ||||
| 	pod, err := getOperatorPod(namespace) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	logOptions := v1.PodLogOptions{TailLines: &podLogTailLimit} | ||||
| 	req := framework.Global.KubeClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &logOptions) | ||||
| 	podLogs, err := req.Stream() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	defer func() { | ||||
| 		if podLogs != nil { | ||||
| 			_ = podLogs.Close() | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	_, err = io.Copy(buf, podLogs) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	logs := buf.String() | ||||
| 	return logs, nil | ||||
| } | ||||
| 
 | ||||
| func printOperatorLogs(t *testing.T, namespace string) { | ||||
| 	t.Logf("Operator logs in '%s' namespace:\n", namespace) | ||||
| 	logs, err := getOperatorLogs(namespace) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Couldn't get the operator pod logs: %s", err) | ||||
| 	} else { | ||||
| 		t.Logf("Last %d lines of log from operator:\n %s", podLogTailLimit, logs) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getKubernetesEvents(namespace string) ([]v1beta1.Event, error) { | ||||
| 	listOptions := metav1.ListOptions{ | ||||
| 		Limit: kubernetesEventsLimit, | ||||
| 	} | ||||
| 
 | ||||
| 	events, err := framework.Global.KubeClient.EventsV1beta1().Events(namespace).List(listOptions) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	sort.SliceStable(events.Items, func(i, j int) bool { | ||||
| 		return events.Items[i].CreationTimestamp.Unix() < events.Items[j].CreationTimestamp.Unix() | ||||
| 	}) | ||||
| 
 | ||||
| 	return events.Items, nil | ||||
| } | ||||
| 
 | ||||
| func printKubernetesEvents(t *testing.T, namespace string) { | ||||
| 	t.Logf("Kubernetes events in '%s' namespace:\n", namespace) | ||||
| 	events, err := getKubernetesEvents(namespace) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Couldn't get kubernetes events: %s", err) | ||||
| 	} else { | ||||
| 		t.Logf("Last %d events from kubernetes:\n", kubernetesEventsLimit) | ||||
| 
 | ||||
| 		for _, event := range events { | ||||
| 			t.Logf("%+v\n\n", event) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getKubernetesPods(namespace string) (*v1.PodList, error) { | ||||
| 	return framework.Global.KubeClient.CoreV1().Pods(namespace).List(metav1.ListOptions{}) | ||||
| } | ||||
| 
 | ||||
| func printKubernetesPods(t *testing.T, namespace string) { | ||||
| 	t.Logf("All pods in '%s' namespace:\n", namespace) | ||||
| 	podList, err := getKubernetesPods(namespace) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Couldn't get kubernetes pods: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, pod := range podList.Items { | ||||
| 		t.Logf("%+v\n\n", pod) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func showLogsIfTestHasFailed(t *testing.T, ctx *framework.Context) { | ||||
| 	namespace, err := ctx.GetOperatorNamespace() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed to get '%s' namespace", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if t.Failed() { | ||||
| 		t.Log("Test failed. Bellow here you can check logs:") | ||||
| 
 | ||||
| 		printKubernetesEvents(t, namespace) | ||||
| 		printKubernetesPods(t, namespace) | ||||
| 		printOperatorLogs(t, namespace) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func showLogsAndCleanup(t *testing.T, ctx *framework.Context) { | ||||
| 	namespace, err := ctx.GetOperatorNamespace() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed to get '%s' namespace", err) | ||||
| 	} | ||||
| 
 | ||||
| 	showLogsIfTestHasFailed(t, ctx) | ||||
| 
 | ||||
| 	ctx.Cleanup() | ||||
| 	if err = waitUntilNamespaceDestroyed(namespace); err != nil { | ||||
| 		t.Fatalf("Failed to wait for namespace until destroyed '%s'", err) | ||||
| 	} | ||||
| } | ||||
|  | @ -7,9 +7,9 @@ import ( | |||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	. "github.com/onsi/gomega" | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/cli-runtime/pkg/genericclioptions" | ||||
|  | @ -49,11 +49,9 @@ func getFreePort() (int, error) { | |||
| 	return l.Addr().(*net.TCPAddr).Port, nil | ||||
| } | ||||
| 
 | ||||
| func setupPortForwardToPod(t *testing.T, namespace, podName string, podPort int) (port int, cleanUpFunc func(), waitFunc func(), portForwardFunc func(), err error) { | ||||
| func setupPortForwardToPod(namespace, podName string, podPort int) (port int, cleanUpFunc func(), waitFunc func(), portForwardFunc func(), err error) { | ||||
| 	port, err = getFreePort() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 
 | ||||
| 	stream := genericclioptions.IOStreams{ | ||||
| 		In:     os.Stdin, | ||||
|  | @ -68,7 +66,7 @@ func setupPortForwardToPod(t *testing.T, namespace, podName string, podPort int) | |||
| 	readyCh := make(chan struct{}) | ||||
| 
 | ||||
| 	req := portForwardToPodRequest{ | ||||
| 		config: framework.Global.KubeConfig, | ||||
| 		config: cfg, | ||||
| 		pod: v1.Pod{ | ||||
| 			ObjectMeta: metav1.ObjectMeta{ | ||||
| 				Name:      podName, | ||||
|  | @ -83,9 +81,9 @@ func setupPortForwardToPod(t *testing.T, namespace, podName string, podPort int) | |||
| 	} | ||||
| 
 | ||||
| 	waitFunc = func() { | ||||
| 		t.Log("Waiting for the port-forward.") | ||||
| 		_, _ = fmt.Fprintf(GinkgoWriter, "Waiting for the port-forward.\n") | ||||
| 		<-readyCh | ||||
| 		t.Log("The port-forward is established.") | ||||
| 		_, _ = fmt.Fprintf(GinkgoWriter, "The port-forward is established.\n") | ||||
| 	} | ||||
| 
 | ||||
| 	portForwardFunc = func() { | ||||
|  | @ -96,7 +94,7 @@ func setupPortForwardToPod(t *testing.T, namespace, podName string, podPort int) | |||
| 	} | ||||
| 
 | ||||
| 	cleanUpFunc = func() { | ||||
| 		t.Log("Closing port-forward") | ||||
| 		_, _ = fmt.Fprintf(GinkgoWriter, "Closing port-forward\n") | ||||
| 		close(stopCh) | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1,5 +1,7 @@ | |||
| package e2e | ||||
| 
 | ||||
| // TODO
 | ||||
| /* | ||||
| import ( | ||||
| 	"context" | ||||
| 	"testing" | ||||
|  | @ -109,3 +111,4 @@ func checkBaseConfigurationCompleteTimeIsNotSet(t *testing.T, jenkins *v1alpha2. | |||
| 		t.Fatalf("Status.BaseConfigurationCompletedTime is set after pod restart, status %+v", jenkinsStatus.Status) | ||||
| 	} | ||||
| } | ||||
| */ | ||||
|  | @ -1,5 +1,7 @@ | |||
| package e2e | ||||
| 
 | ||||
| // TODO
 | ||||
| /* | ||||
| import ( | ||||
| 	"context" | ||||
| 	"testing" | ||||
|  | @ -214,3 +216,4 @@ func resetJenkinsStatus(t *testing.T, jenkins *v1alpha2.Jenkins) { | |||
| 	err := framework.Global.Client.Update(context.TODO(), jenkins) | ||||
| 	require.NoError(t, err) | ||||
| } | ||||
| */ | ||||
|  | @ -2,24 +2,19 @@ package e2e | |||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 	"text/template" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/internal/render" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/internal/try" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/user/seedjobs" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/constants" | ||||
| 
 | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	. "github.com/onsi/gomega" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
|  | @ -32,11 +27,12 @@ type seedJobConfig struct { | |||
| 	PrivateKey string   `json:"privateKey,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type seedJobsConfig struct { | ||||
| /*type seedJobsConfig struct { | ||||
| 	SeedJobs []seedJobConfig `json:"seedJobs,omitempty"` | ||||
| } | ||||
| }*/ | ||||
| 
 | ||||
| func TestSeedJobs(t *testing.T) { | ||||
| // FIXME
 | ||||
| /*func TestSeedJobs(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	if seedJobConfigurationFile == nil || len(*seedJobConfigurationFile) == 0 { | ||||
| 		t.Skipf("Skipping test because flag '%+v' is not set", seedJobConfigurationFile) | ||||
|  | @ -81,8 +77,9 @@ func loadSeedJobsConfig(t *testing.T) seedJobsConfig { | |||
| 	assert.NotEmpty(t, result.SeedJobs) | ||||
| 	return result | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| func createKubernetesCredentialsProviderSecret(t *testing.T, namespace string, config seedJobConfig) { | ||||
| func createKubernetesCredentialsProviderSecret(namespace string, config seedJobConfig) { | ||||
| 	if config.JenkinsCredentialType == v1alpha2.NoJenkinsCredentialCredentialType { | ||||
| 		return | ||||
| 	} | ||||
|  | @ -105,31 +102,32 @@ func createKubernetesCredentialsProviderSecret(t *testing.T, namespace string, c | |||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	err := framework.Global.Client.Create(context.TODO(), secret, nil) | ||||
| 	require.NoError(t, err) | ||||
| 	Expect(k8sClient.Create(context.TODO(), secret)).Should(Succeed()) | ||||
| } | ||||
| 
 | ||||
| func verifyJenkinsSeedJobs(t *testing.T, jenkinsClient jenkinsclient.Jenkins, seedJobs []seedJobConfig) { | ||||
| func verifyJenkinsSeedJobs(jenkinsClient jenkinsclient.Jenkins, seedJobs []seedJobConfig) { | ||||
| 	By("creating Jenkins jobs by seed jobs") | ||||
| 
 | ||||
| 	var err error | ||||
| 	for _, seedJob := range seedJobs { | ||||
| 		if seedJob.JenkinsCredentialType == v1alpha2.BasicSSHCredentialType || seedJob.JenkinsCredentialType == v1alpha2.UsernamePasswordCredentialType { | ||||
| 			err = verifyIfJenkinsCredentialExists(jenkinsClient, seedJob.CredentialID) | ||||
| 			assert.NoErrorf(t, err, "Jenkins credential '%s' not created for seed job ID '%s'", seedJob.CredentialID, seedJob.ID) | ||||
| 			Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Jenkins credential '%s' not created for seed job ID '%s'", seedJob.CredentialID, seedJob.ID)) | ||||
| 		} | ||||
| 
 | ||||
| 		verifySeedJobProperties(t, jenkinsClient, seedJob) | ||||
| 		verifySeedJobProperties(jenkinsClient, seedJob) | ||||
| 
 | ||||
| 		for _, requireJobName := range seedJob.JobNames { | ||||
| 			err = try.Until(func() (end bool, err error) { | ||||
| 				_, err = jenkinsClient.GetJob(requireJobName) | ||||
| 				return err == nil, err | ||||
| 			}, time.Second*2, time.Minute*2) | ||||
| 			assert.NoErrorf(t, err, "Jenkins job '%s' not created by seed job ID '%s'", requireJobName, seedJob.ID) | ||||
| 			Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Jenkins job '%s' not created by seed job ID '%s'", requireJobName, seedJob.ID)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func verifySeedJobProperties(t *testing.T, jenkinsClient jenkinsclient.Jenkins, seedJob seedJobConfig) { | ||||
| func verifySeedJobProperties(jenkinsClient jenkinsclient.Jenkins, seedJob seedJobConfig) { | ||||
| 	data := struct { | ||||
| 		ID                    string | ||||
| 		CredentialID          string | ||||
|  | @ -163,10 +161,10 @@ func verifySeedJobProperties(t *testing.T, jenkinsClient jenkinsclient.Jenkins, | |||
| 	} | ||||
| 
 | ||||
| 	groovyScript, err := render.Render(verifySeedJobPropertiesGroovyScriptTemplate, data) | ||||
| 	assert.NoError(t, err, groovyScript) | ||||
| 	Expect(err).NotTo(HaveOccurred(), groovyScript) | ||||
| 
 | ||||
| 	logs, err := jenkinsClient.ExecuteScript(groovyScript) | ||||
| 	assert.NoError(t, err, logs, groovyScript) | ||||
| 	Expect(err).NotTo(HaveOccurred(), logs, groovyScript) | ||||
| } | ||||
| 
 | ||||
| func verifyIfJenkinsCredentialExists(jenkinsClient jenkinsclient.Jenkins, credentialName string) error { | ||||
|  |  | |||
|  | @ -1,33 +1,27 @@ | |||
| /* | ||||
| Copyright 2021. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package controllers | ||||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	jenkinsiov1alpha2 "github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/controllers" | ||||
| 	jenkinsClient "github.com/jenkinsci/kubernetes-operator/pkg/client" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/constants" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/event" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/notifications" | ||||
| 	e "github.com/jenkinsci/kubernetes-operator/pkg/notifications/event" | ||||
| 
 | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	. "github.com/onsi/gomega" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/client-go/kubernetes" | ||||
| 	"k8s.io/client-go/kubernetes/scheme" | ||||
| 	"k8s.io/client-go/rest" | ||||
| 	ctrl "sigs.k8s.io/controller-runtime" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/client" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/envtest" | ||||
|  | @ -37,11 +31,8 @@ import ( | |||
| 	// +kubebuilder:scaffold:imports
 | ||||
| ) | ||||
| 
 | ||||
| // These tests use Ginkgo (BDD-style Go testing framework). Refer to
 | ||||
| // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
 | ||||
| 
 | ||||
| var ( | ||||
| 	//cfg       *rest.Config
 | ||||
| 	cfg       *rest.Config | ||||
| 	k8sClient client.Client | ||||
| 	testEnv   *envtest.Environment | ||||
| ) | ||||
|  | @ -55,45 +46,55 @@ func TestAPIs(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| var _ = BeforeSuite(func(done Done) { | ||||
| 	logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) | ||||
| 	logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(false))) | ||||
| 
 | ||||
| 	By("bootstrapping test environment") | ||||
| 	useExistingCluster := true | ||||
| 	testEnv = &envtest.Environment{ | ||||
| 		CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, | ||||
| 		CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, | ||||
| 		//BinaryAssetsDirectory: path.Join("..", "..", "testbin", "bin"),
 | ||||
| 		UseExistingCluster: &useExistingCluster, | ||||
| 	} | ||||
| 
 | ||||
| 	cfg, err := testEnv.Start() | ||||
| 	var err error | ||||
| 	cfg, err = testEnv.Start() | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 	Expect(cfg).NotTo(BeNil()) | ||||
| 
 | ||||
| 	err = jenkinsiov1alpha2.AddToScheme(scheme.Scheme) | ||||
| 	err = v1alpha2.AddToScheme(scheme.Scheme) | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 
 | ||||
| 	// +kubebuilder:scaffold:scheme
 | ||||
| 
 | ||||
| 	//setup manager
 | ||||
| 	// setup manager
 | ||||
| 	k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ | ||||
| 		Scheme: scheme.Scheme, | ||||
| 	}) | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 
 | ||||
| 	//setup controller
 | ||||
| 	// setup controller
 | ||||
| 	clientSet, err := kubernetes.NewForConfig(cfg) | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 
 | ||||
| 	// setup events
 | ||||
| 	events, err := event.New(cfg, constants.OperatorName) | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 	notificationEvents := make(chan e.Event) | ||||
| 	go notifications.Listen(notificationEvents, events, k8sClient) | ||||
| 
 | ||||
| 	// validate jenkins API connection
 | ||||
| 	jenkinsAPIConnectionSettings := jenkinsClient.JenkinsAPIConnectionSettings{} | ||||
| 	jenkinsAPIConnectionSettings := jenkinsClient.JenkinsAPIConnectionSettings{ | ||||
| 		Hostname:    "192.168.99.100", // FIXME minikube ip
 | ||||
| 		UseNodePort: true, | ||||
| 	} | ||||
| 
 | ||||
| 	err = (&JenkinsReconciler{ | ||||
| 	err = (&controllers.JenkinsReconciler{ | ||||
| 		Client:                       k8sManager.GetClient(), | ||||
| 		Scheme:                       k8sManager.GetScheme(), | ||||
| 		JenkinsAPIConnectionSettings: jenkinsAPIConnectionSettings, | ||||
| 		ClientSet:                    *clientSet, | ||||
| 		Config:                       *cfg, | ||||
| 		NotificationEvents:           ¬ificationEvents, | ||||
| 		KubernetesClusterDomain:      "", | ||||
| 		KubernetesClusterDomain:      "cluster.local", | ||||
| 	}).SetupWithManager(k8sManager) | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| 
 | ||||
|  | @ -105,7 +106,6 @@ var _ = BeforeSuite(func(done Done) { | |||
| 	k8sClient = k8sManager.GetClient() | ||||
| 	Expect(k8sClient).NotTo(BeNil()) | ||||
| 	close(done) | ||||
| 
 | ||||
| }, 60) | ||||
| 
 | ||||
| var _ = AfterSuite(func() { | ||||
|  | @ -113,3 +113,39 @@ var _ = AfterSuite(func() { | |||
| 	err := testEnv.Stop() | ||||
| 	Expect(err).NotTo(HaveOccurred()) | ||||
| }) | ||||
| 
 | ||||
| func createNamespace() *corev1.Namespace { | ||||
| 	By("creating temporary namespace") | ||||
| 
 | ||||
| 	namespace := &corev1.Namespace{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name: fmt.Sprintf("%d", time.Now().Unix()), | ||||
| 		}, | ||||
| 	} | ||||
| 	Expect(k8sClient.Create(context.TODO(), namespace)).Should(Succeed()) | ||||
| 	return namespace | ||||
| } | ||||
| 
 | ||||
| func destroyNamespace(namespace *corev1.Namespace) { | ||||
| 	By("deleting temporary namespace") | ||||
| 
 | ||||
| 	Expect(k8sClient.Delete(context.TODO(), namespace)).Should(Succeed()) | ||||
| 
 | ||||
| 	Eventually(func() (bool, error) { | ||||
| 		namespaces := &corev1.NamespaceList{} | ||||
| 		err := k8sClient.List(context.TODO(), namespaces) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 
 | ||||
| 		exists := false | ||||
| 		for _, namespaceItem := range namespaces.Items { | ||||
| 			if namespaceItem.Name == namespace.Name { | ||||
| 				exists = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return !exists, nil | ||||
| 	}, time.Second*120, time.Second).Should(BeTrue()) | ||||
| } | ||||
							
								
								
									
										134
									
								
								test/e2e/wait.go
								
								
								
								
							
							
						
						
									
										134
									
								
								test/e2e/wait.go
								
								
								
								
							|  | @ -1,134 +0,0 @@ | |||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	goctx "context" | ||||
| 	"net/http" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"golang.org/x/net/context" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/internal/try" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||
| 	jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||
| 
 | ||||
| 	framework "github.com/operator-framework/operator-sdk/pkg/test" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/labels" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| 	"k8s.io/apimachinery/pkg/util/wait" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/client" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	retryInterval = time.Second * 5 | ||||
| 	timeout       = time.Second * 60 | ||||
| ) | ||||
| 
 | ||||
| // checkConditionFunc is used to check if a condition for the jenkins CR is set
 | ||||
| type checkConditionFunc func(*v1alpha2.Jenkins, error) bool | ||||
| 
 | ||||
| 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 { | ||||
| 		t.Logf("Current Jenkins status: '%+v', error '%s'", jenkins.Status, err) | ||||
| 		return err == nil && jenkins.Status.BaseConfigurationCompletedTime != nil | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	t.Log("Jenkins pod is running") | ||||
| 
 | ||||
| 	// update jenkins CR because Operator sets default values
 | ||||
| 	namespacedName := types.NamespacedName{Namespace: jenkins.Namespace, Name: jenkins.Name} | ||||
| 	err = framework.Global.Client.Get(goctx.TODO(), namespacedName, jenkins) | ||||
| 	assert.NoError(t, err) | ||||
| } | ||||
| 
 | ||||
| func waitForRecreateJenkinsMasterPod(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	err := wait.Poll(retryInterval, 30*retryInterval, func() (bool, error) { | ||||
| 		lo := metav1.ListOptions{ | ||||
| 			LabelSelector: labels.SelectorFromSet(resources.GetJenkinsMasterPodLabels(*jenkins)).String(), | ||||
| 		} | ||||
| 		podList, err := framework.Global.KubeClient.CoreV1().Pods(jenkins.ObjectMeta.Namespace).List(lo) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		if len(podList.Items) != 1 { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 
 | ||||
| 		return podList.Items[0].DeletionTimestamp == nil, nil | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	t.Log("Jenkins pod has been recreated") | ||||
| } | ||||
| 
 | ||||
| func waitForJenkinsUserConfigurationToComplete(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	t.Log("Waiting for Jenkins user configuration to complete") | ||||
| 	_, err := WaitUntilJenkinsConditionSet(retryInterval, 110, jenkins, func(jenkins *v1alpha2.Jenkins, err error) bool { | ||||
| 		t.Logf("Current Jenkins status: '%+v', error '%s'", jenkins.Status, err) | ||||
| 		return err == nil && jenkins.Status.UserConfigurationCompletedTime != nil | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	t.Log("Jenkins pod is running") | ||||
| } | ||||
| 
 | ||||
| func waitForJenkinsSafeRestart(t *testing.T, jenkinsClient jenkinsclient.Jenkins) { | ||||
| 	err := try.Until(func() (end bool, err error) { | ||||
| 		status, err := jenkinsClient.Poll() | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		if status != http.StatusOK { | ||||
| 			return false, errors.Wrap(err, "couldn't poll data from Jenkins API") | ||||
| 		} | ||||
| 		return true, nil | ||||
| 	}, time.Second, time.Second*70) | ||||
| 	require.NoError(t, err) | ||||
| } | ||||
| 
 | ||||
| // WaitUntilJenkinsConditionSet retries until the specified condition check becomes true for the jenkins CR
 | ||||
| func WaitUntilJenkinsConditionSet(retryInterval time.Duration, retries int, jenkins *v1alpha2.Jenkins, checkCondition checkConditionFunc) (*v1alpha2.Jenkins, error) { | ||||
| 	jenkinsStatus := &v1alpha2.Jenkins{} | ||||
| 	err := wait.Poll(retryInterval, time.Duration(retries)*retryInterval, func() (bool, error) { | ||||
| 		namespacedName := types.NamespacedName{Namespace: jenkins.Namespace, Name: jenkins.Name} | ||||
| 		err := framework.Global.Client.Get(goctx.TODO(), namespacedName, jenkinsStatus) | ||||
| 		return checkCondition(jenkinsStatus, err), nil | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return jenkinsStatus, nil | ||||
| } | ||||
| 
 | ||||
| func waitUntilNamespaceDestroyed(namespace string) error { | ||||
| 	err := try.Until(func() (bool, error) { | ||||
| 		var namespaceList v1.NamespaceList | ||||
| 		err := framework.Global.Client.List(context.TODO(), &namespaceList, &client.ListOptions{}) | ||||
| 		if err != nil { | ||||
| 			return true, err | ||||
| 		} | ||||
| 
 | ||||
| 		exists := false | ||||
| 		for _, namespaceItem := range namespaceList.Items { | ||||
| 			if namespaceItem.Name == namespace { | ||||
| 				exists = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return !exists, nil | ||||
| 	}, time.Second, time.Second*120) | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
|  | @ -0,0 +1,87 @@ | |||
| package e2e | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" | ||||
| 	. "github.com/onsi/ginkgo" | ||||
| 	. "github.com/onsi/gomega" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	retryInterval = time.Second * 5 | ||||
| ) | ||||
| 
 | ||||
| func waitForJenkinsBaseConfigurationToComplete(jenkins *v1alpha2.Jenkins) { | ||||
| 	By("waiting for Jenkins base configuration phase to complete") | ||||
| 
 | ||||
| 	Eventually(func() (*metav1.Time, error) { | ||||
| 		actualJenkins := &v1alpha2.Jenkins{} | ||||
| 		err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: jenkins.Name, Namespace: jenkins.Namespace}, actualJenkins) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		return actualJenkins.Status.BaseConfigurationCompletedTime, nil | ||||
| 	}, time.Duration(170)*retryInterval, retryInterval).Should(Not(BeNil())) | ||||
| 
 | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins pod is running\n") | ||||
| 
 | ||||
| 	// update jenkins CR because Operator sets default values
 | ||||
| 	namespacedName := types.NamespacedName{Namespace: jenkins.Namespace, Name: jenkins.Name} | ||||
| 	Expect(k8sClient.Get(context.TODO(), namespacedName, jenkins)).Should(Succeed()) | ||||
| } | ||||
| 
 | ||||
| /*func waitForRecreateJenkinsMasterPod(t *testing.T, jenkins *v1alpha2.Jenkins) { | ||||
| 	err := wait.Poll(retryInterval, 30*retryInterval, func() (bool, error) { | ||||
| 		lo := metav1.ListOptions{ | ||||
| 			LabelSelector: labels.SelectorFromSet(resources.GetJenkinsMasterPodLabels(*jenkins)).String(), | ||||
| 		} | ||||
| 		podList, err := framework.Global.KubeClient.CoreV1().Pods(jenkins.ObjectMeta.Namespace).List(lo) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		if len(podList.Items) != 1 { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 
 | ||||
| 		return podList.Items[0].DeletionTimestamp == nil, nil | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter,"Jenkins pod has been recreated") | ||||
| }*/ | ||||
| 
 | ||||
| func waitForJenkinsUserConfigurationToComplete(jenkins *v1alpha2.Jenkins) { | ||||
| 	By("waiting for Jenkins user configuration phase to complete") | ||||
| 
 | ||||
| 	Eventually(func() (*metav1.Time, error) { | ||||
| 		actualJenkins := &v1alpha2.Jenkins{} | ||||
| 		err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: jenkins.Name, Namespace: jenkins.Namespace}, actualJenkins) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		return actualJenkins.Status.UserConfigurationCompletedTime, nil | ||||
| 	}, time.Duration(110)*retryInterval, retryInterval).Should(Not(BeNil())) | ||||
| 	_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins instance is up and ready\n") | ||||
| } | ||||
| 
 | ||||
| /*func waitForJenkinsSafeRestart(t *testing.T, jenkinsClient jenkinsclient.Jenkins) { | ||||
| 	err := try.Until(func() (end bool, err error) { | ||||
| 		status, err := jenkinsClient.Poll() | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		if status != http.StatusOK { | ||||
| 			return false, errors.Wrap(err, "couldn't poll data from Jenkins API") | ||||
| 		} | ||||
| 		return true, nil | ||||
| 	}, time.Second, time.Second*70) | ||||
| 	require.NoError(t, err) | ||||
| }*/ | ||||
|  | @ -1,5 +1,4 @@ | |||
| # Set POSIX sh for maximum interoperability
 | ||||
| SHELL := /bin/sh | ||||
| SHELL := /bin/bash | ||||
| PATH  := $(GOPATH)/bin:$(PATH) | ||||
| 
 | ||||
| OSFLAG 				:= | ||||
|  | @ -60,7 +59,7 @@ GO_LDFLAGS_STATIC=-ldflags "-w $(CTIMEVAR) -extldflags -static" | |||
| GOOSARCHES = linux/amd64 | ||||
| 
 | ||||
| PACKAGES = $(shell go list -f '{{.ImportPath}}/' ./... | grep -v vendor) | ||||
| PACKAGES_FOR_UNIT_TESTS = $(shell go list -f '{{.ImportPath}}/' ./... | grep -v vendor | grep -v e2e) | ||||
| PACKAGES_FOR_UNIT_TESTS = $(shell go list -f '{{.ImportPath}}/' ./... | grep -v vendor | grep -v e2e | grep -v controllers) | ||||
| 
 | ||||
| # Run all the e2e tests by default
 | ||||
| E2E_TEST_SELECTOR ?= .* | ||||
|  | @ -94,3 +93,5 @@ GOBIN=$(shell go env GOPATH)/bin | |||
| else | ||||
| GOBIN=$(shell go env GOBIN) | ||||
| endif | ||||
| 
 | ||||
| ENVTEST_ASSETS_DIR=$(shell pwd)/testbin | ||||
		Loading…
	
		Reference in New Issue