#9 Allow mount secrets and configmaps in Jenkins pod
This commit is contained in:
		
							parent
							
								
									af10a97299
								
							
						
					
					
						commit
						55d6aecb93
					
				|  | @ -53,6 +53,12 @@ eval $(minikube docker-env) | |||
| make e2e | ||||
| ``` | ||||
| 
 | ||||
| Run the specific e2e test: | ||||
| 
 | ||||
| ```bash | ||||
| make e2e E2E_TEST_SELECTOR='^TestConfiguration$' | ||||
| ``` | ||||
| 
 | ||||
| ## Tips & Tricks | ||||
| 
 | ||||
| ### Building docker image on minikube (for e2e tests) | ||||
|  |  | |||
|  | @ -40,12 +40,13 @@ type Container struct { | |||
| // JenkinsMaster defines the Jenkins master pod attributes and plugins,
 | ||||
| // every single change requires Jenkins master pod restart
 | ||||
| type JenkinsMaster struct { | ||||
| 	Container | ||||
| 	Container //TODO move to containers
 | ||||
| 
 | ||||
| 	// pod properties
 | ||||
| 	Annotations  map[string]string `json:"masterAnnotations,omitempty"` | ||||
| 	NodeSelector map[string]string `json:"nodeSelector,omitempty"` | ||||
| 	Containers   []Container       `json:"containers,omitempty"` | ||||
| 	Volumes      []corev1.Volume   `json:"volumes,omitempty"` | ||||
| 
 | ||||
| 	// OperatorPlugins contains plugins required by operator
 | ||||
| 	OperatorPlugins map[string][]string `json:"basePlugins,omitempty"` | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import ( | |||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" | ||||
|  | @ -378,6 +379,8 @@ func (r *ReconcileJenkinsBaseConfiguration) isRecreatePodNeeded(currentJenkinsMa | |||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	//TODO check if image can't be pulled, volume can't be mounted etc. (get info from events)
 | ||||
| 
 | ||||
| 	if currentJenkinsMasterPod.Status.Phase == corev1.PodFailed || | ||||
| 		currentJenkinsMasterPod.Status.Phase == corev1.PodSucceeded || | ||||
| 		currentJenkinsMasterPod.Status.Phase == corev1.PodUnknown { | ||||
|  | @ -397,6 +400,12 @@ func (r *ReconcileJenkinsBaseConfiguration) isRecreatePodNeeded(currentJenkinsMa | |||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	if !r.compareVolumes(currentJenkinsMasterPod) { | ||||
| 		r.logger.Info(fmt.Sprintf("Jenkins pod volumes have changed, actual '%+v' required '%+v', recreating pod", | ||||
| 			currentJenkinsMasterPod.Spec.Volumes, r.jenkins.Spec.Master.Volumes)) | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	if (len(r.jenkins.Spec.Master.Containers) + 1) != len(currentJenkinsMasterPod.Spec.Containers) { | ||||
| 		r.logger.Info(fmt.Sprintf("Jenkins amount of containers has changed to '%+v', recreating pod", len(r.jenkins.Spec.Master.Containers)+1)) | ||||
| 		return true | ||||
|  | @ -485,7 +494,7 @@ func (r *ReconcileJenkinsBaseConfiguration) compareContainers(expected corev1.Co | |||
| 		return true | ||||
| 	} | ||||
| 	if !CompareContainerVolumeMounts(expected, actual) { | ||||
| 		r.logger.Info(fmt.Sprintf("Volume mounts has changed to '%+v' in container '%s', recreating pod", expected.VolumeMounts, expected.Name)) | ||||
| 		r.logger.Info(fmt.Sprintf("Volume mounts have changed to '%+v' in container '%s', recreating pod", expected.VolumeMounts, expected.Name)) | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
|  | @ -504,6 +513,21 @@ func CompareContainerVolumeMounts(expected corev1.Container, actual corev1.Conta | |||
| 	return reflect.DeepEqual(expected.VolumeMounts, withoutServiceAccount) | ||||
| } | ||||
| 
 | ||||
| // compareVolumes returns true if Jenkins pod and Jenkins CR volumes are the same
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) compareVolumes(actualPod corev1.Pod) bool { | ||||
| 	var withoutServiceAccount []corev1.Volume | ||||
| 	for _, volume := range actualPod.Spec.Volumes { | ||||
| 		if !strings.HasPrefix(volume.Name, actualPod.Spec.ServiceAccountName) { | ||||
| 			withoutServiceAccount = append(withoutServiceAccount, volume) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return reflect.DeepEqual( | ||||
| 		append(resources.GetJenkinsMasterPodBaseVolumes(r.jenkins), r.jenkins.Spec.Master.Volumes...), | ||||
| 		withoutServiceAccount, | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) restartJenkinsMasterPod(meta metav1.ObjectMeta) error { | ||||
| 	currentJenkinsMasterPod, err := r.getJenkinsMasterPod(meta) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -3,6 +3,9 @@ package base | |||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| ) | ||||
|  | @ -81,3 +84,68 @@ func TestCompareContainerVolumeMounts(t *testing.T) { | |||
| 		assert.False(t, got) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestCompareVolumes(t *testing.T) { | ||||
| 	t.Run("defaults", func(t *testing.T) { | ||||
| 		jenkins := &v1alpha1.Jenkins{} | ||||
| 		pod := corev1.Pod{ | ||||
| 			Spec: corev1.PodSpec{ | ||||
| 				ServiceAccountName: "service-account-name", | ||||
| 				Volumes:            resources.GetJenkinsMasterPodBaseVolumes(jenkins), | ||||
| 			}, | ||||
| 		} | ||||
| 		reconciler := New(nil, nil, nil, jenkins, false, false) | ||||
| 
 | ||||
| 		got := reconciler.compareVolumes(pod) | ||||
| 
 | ||||
| 		assert.True(t, got) | ||||
| 	}) | ||||
| 	t.Run("different", func(t *testing.T) { | ||||
| 		jenkins := &v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Volumes: []corev1.Volume{ | ||||
| 						{ | ||||
| 							Name: "added", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		pod := corev1.Pod{ | ||||
| 			Spec: corev1.PodSpec{ | ||||
| 				ServiceAccountName: "service-account-name", | ||||
| 				Volumes:            resources.GetJenkinsMasterPodBaseVolumes(jenkins), | ||||
| 			}, | ||||
| 		} | ||||
| 		reconciler := New(nil, nil, nil, jenkins, false, false) | ||||
| 
 | ||||
| 		got := reconciler.compareVolumes(pod) | ||||
| 
 | ||||
| 		assert.False(t, got) | ||||
| 	}) | ||||
| 	t.Run("added one volume", func(t *testing.T) { | ||||
| 		jenkins := &v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Volumes: []corev1.Volume{ | ||||
| 						{ | ||||
| 							Name: "added", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		pod := corev1.Pod{ | ||||
| 			Spec: corev1.PodSpec{ | ||||
| 				ServiceAccountName: "service-account-name", | ||||
| 				Volumes:            append(resources.GetJenkinsMasterPodBaseVolumes(jenkins), corev1.Volume{Name: "added"}), | ||||
| 			}, | ||||
| 		} | ||||
| 		reconciler := New(nil, nil, nil, jenkins, false, false) | ||||
| 
 | ||||
| 		got := reconciler.compareVolumes(pod) | ||||
| 
 | ||||
| 		assert.True(t, got) | ||||
| 	}) | ||||
| } | ||||
|  |  | |||
|  | @ -13,7 +13,8 @@ import ( | |||
| const ( | ||||
| 	// JenkinsMasterContainerName is the Jenkins master container name in pod
 | ||||
| 	JenkinsMasterContainerName = "jenkins-master" | ||||
| 	jenkinsHomeVolumeName      = "home" | ||||
| 	// JenkinsHomeVolumeName is the Jenkins home volume name
 | ||||
| 	JenkinsHomeVolumeName = "home" | ||||
| 	jenkinsPath           = "/var/jenkins" | ||||
| 	jenkinsHomePath       = jenkinsPath + "/home" | ||||
| 
 | ||||
|  | @ -74,38 +75,87 @@ func GetJenkinsMasterPodBaseEnvs() []corev1.EnvVar { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewJenkinsMasterContainer returns Jenkins master Kubernetes container
 | ||||
| func NewJenkinsMasterContainer(jenkins *v1alpha1.Jenkins) corev1.Container { | ||||
| 	envs := GetJenkinsMasterPodBaseEnvs() | ||||
| 	envs = append(envs, jenkins.Spec.Master.Env...) | ||||
| // GetJenkinsMasterPodBaseVolumes returns Jenkins master pod volumes required by operator
 | ||||
| func GetJenkinsMasterPodBaseVolumes(jenkins *v1alpha1.Jenkins) []corev1.Volume { | ||||
| 	configMapVolumeSourceDefaultMode := corev1.ConfigMapVolumeSourceDefaultMode | ||||
| 	secretVolumeSourceDefaultMode := corev1.SecretVolumeSourceDefaultMode | ||||
| 	return []corev1.Volume{ | ||||
| 		{ | ||||
| 			Name: JenkinsHomeVolumeName, | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				EmptyDir: &corev1.EmptyDirVolumeSource{}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: jenkinsScriptsVolumeName, | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					DefaultMode: &configMapVolumeSourceDefaultMode, | ||||
| 					LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 						Name: getScriptsConfigMapName(jenkins), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: jenkinsInitConfigurationVolumeName, | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					DefaultMode: &configMapVolumeSourceDefaultMode, | ||||
| 					LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 						Name: GetInitConfigurationConfigMapName(jenkins), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: jenkinsBaseConfigurationVolumeName, | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					DefaultMode: &configMapVolumeSourceDefaultMode, | ||||
| 					LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 						Name: GetBaseConfigurationConfigMapName(jenkins), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: jenkinsUserConfigurationVolumeName, | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					DefaultMode: &configMapVolumeSourceDefaultMode, | ||||
| 					LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 						Name: GetUserConfigurationConfigMapNameFromJenkins(jenkins), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: jenkinsOperatorCredentialsVolumeName, | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				Secret: &corev1.SecretVolumeSource{ | ||||
| 					DefaultMode: &secretVolumeSourceDefaultMode, | ||||
| 					SecretName:  GetOperatorCredentialsSecretName(jenkins), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: userConfigurationSecretVolumeName, | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				Secret: &corev1.SecretVolumeSource{ | ||||
| 					DefaultMode: &secretVolumeSourceDefaultMode, | ||||
| 					SecretName:  GetUserConfigurationSecretNameFromJenkins(jenkins), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 	return corev1.Container{ | ||||
| 		Name:            JenkinsMasterContainerName, | ||||
| 		Image:           jenkins.Spec.Master.Image, | ||||
| 		ImagePullPolicy: jenkins.Spec.Master.ImagePullPolicy, | ||||
| 		Command: []string{ | ||||
| 			"bash", | ||||
| 			fmt.Sprintf("%s/%s", jenkinsScriptsVolumePath, initScriptName), | ||||
| 		}, | ||||
| 		LivenessProbe:  jenkins.Spec.Master.LivenessProbe, | ||||
| 		ReadinessProbe: jenkins.Spec.Master.ReadinessProbe, | ||||
| 		Ports: []corev1.ContainerPort{ | ||||
| // GetJenkinsMasterContainerBaseVolumeMounts returns Jenkins master pod volume mounts required by operator
 | ||||
| func GetJenkinsMasterContainerBaseVolumeMounts() []corev1.VolumeMount { | ||||
| 	return []corev1.VolumeMount{ | ||||
| 		{ | ||||
| 				Name:          httpPortName, | ||||
| 				ContainerPort: constants.DefaultHTTPPortInt32, | ||||
| 				Protocol:      corev1.ProtocolTCP, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Name:          slavePortName, | ||||
| 				ContainerPort: constants.DefaultSlavePortInt32, | ||||
| 				Protocol:      corev1.ProtocolTCP, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Env:       envs, | ||||
| 		Resources: jenkins.Spec.Master.Resources, | ||||
| 		VolumeMounts: []corev1.VolumeMount{ | ||||
| 			{ | ||||
| 				Name:      jenkinsHomeVolumeName, | ||||
| 			Name:      JenkinsHomeVolumeName, | ||||
| 			MountPath: jenkinsHomePath, | ||||
| 			ReadOnly:  false, | ||||
| 		}, | ||||
|  | @ -139,7 +189,39 @@ func NewJenkinsMasterContainer(jenkins *v1alpha1.Jenkins) corev1.Container { | |||
| 			MountPath: UserConfigurationSecretVolumePath, | ||||
| 			ReadOnly:  true, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewJenkinsMasterContainer returns Jenkins master Kubernetes container
 | ||||
| func NewJenkinsMasterContainer(jenkins *v1alpha1.Jenkins) corev1.Container { | ||||
| 	envs := GetJenkinsMasterPodBaseEnvs() | ||||
| 	envs = append(envs, jenkins.Spec.Master.Env...) | ||||
| 
 | ||||
| 	return corev1.Container{ | ||||
| 		Name:            JenkinsMasterContainerName, | ||||
| 		Image:           jenkins.Spec.Master.Image, | ||||
| 		ImagePullPolicy: jenkins.Spec.Master.ImagePullPolicy, | ||||
| 		Command: []string{ | ||||
| 			"bash", | ||||
| 			fmt.Sprintf("%s/%s", jenkinsScriptsVolumePath, initScriptName), | ||||
| 		}, | ||||
| 		LivenessProbe:  jenkins.Spec.Master.LivenessProbe, | ||||
| 		ReadinessProbe: jenkins.Spec.Master.ReadinessProbe, | ||||
| 		Ports: []corev1.ContainerPort{ | ||||
| 			{ | ||||
| 				Name:          httpPortName, | ||||
| 				ContainerPort: constants.DefaultHTTPPortInt32, | ||||
| 				Protocol:      corev1.ProtocolTCP, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Name:          slavePortName, | ||||
| 				ContainerPort: constants.DefaultSlavePortInt32, | ||||
| 				Protocol:      corev1.ProtocolTCP, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Env:          envs, | ||||
| 		Resources:    jenkins.Spec.Master.Resources, | ||||
| 		VolumeMounts: append(GetJenkinsMasterContainerBaseVolumeMounts(), jenkins.Spec.Master.VolumeMounts...), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -192,70 +274,7 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins | |||
| 			}, | ||||
| 			NodeSelector: jenkins.Spec.Master.NodeSelector, | ||||
| 			Containers:   newContainers(jenkins), | ||||
| 			Volumes: []corev1.Volume{ | ||||
| 				{ | ||||
| 					Name: jenkinsHomeVolumeName, | ||||
| 					VolumeSource: corev1.VolumeSource{ | ||||
| 						EmptyDir: &corev1.EmptyDirVolumeSource{}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name: jenkinsScriptsVolumeName, | ||||
| 					VolumeSource: corev1.VolumeSource{ | ||||
| 						ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 							LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 								Name: getScriptsConfigMapName(jenkins), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name: jenkinsInitConfigurationVolumeName, | ||||
| 					VolumeSource: corev1.VolumeSource{ | ||||
| 						ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 							LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 								Name: GetInitConfigurationConfigMapName(jenkins), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name: jenkinsBaseConfigurationVolumeName, | ||||
| 					VolumeSource: corev1.VolumeSource{ | ||||
| 						ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 							LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 								Name: GetBaseConfigurationConfigMapName(jenkins), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name: jenkinsUserConfigurationVolumeName, | ||||
| 					VolumeSource: corev1.VolumeSource{ | ||||
| 						ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 							LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 								Name: GetUserConfigurationConfigMapNameFromJenkins(jenkins), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name: jenkinsOperatorCredentialsVolumeName, | ||||
| 					VolumeSource: corev1.VolumeSource{ | ||||
| 						Secret: &corev1.SecretVolumeSource{ | ||||
| 							SecretName: GetOperatorCredentialsSecretName(jenkins), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					Name: userConfigurationSecretVolumeName, | ||||
| 					VolumeSource: corev1.VolumeSource{ | ||||
| 						Secret: &corev1.SecretVolumeSource{ | ||||
| 							SecretName: GetUserConfigurationSecretNameFromJenkins(jenkins), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Volumes:      append(GetJenkinsMasterPodBaseVolumes(jenkins), jenkins.Spec.Master.Volumes...), | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package base | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 
 | ||||
|  | @ -10,6 +11,10 @@ import ( | |||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/log" | ||||
| 
 | ||||
| 	docker "github.com/docker/distribution/reference" | ||||
| 	stackerr "github.com/pkg/errors" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||
| 	"k8s.io/apimachinery/pkg/types" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
|  | @ -18,6 +23,15 @@ var ( | |||
| 
 | ||||
| // Validate validates Jenkins CR Spec.master section
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha1.Jenkins) (bool, error) { | ||||
| 	if !r.validateReservedVolumes() { | ||||
| 		return false, nil | ||||
| 	} | ||||
| 	if valid, err := r.validateVolumes(); err != nil { | ||||
| 		return false, err | ||||
| 	} else if !valid { | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	if !r.validateContainer(jenkins.Spec.Master.Container) { | ||||
| 		return false, nil | ||||
| 	} | ||||
|  | @ -39,6 +53,80 @@ func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha1.Jenkins) | |||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateVolumes() (bool, error) { | ||||
| 	valid := true | ||||
| 	for _, volume := range r.jenkins.Spec.Master.Volumes { | ||||
| 		switch { | ||||
| 		case volume.ConfigMap != nil: | ||||
| 			if ok, err := r.validateConfigMapVolume(volume); err != nil { | ||||
| 				return false, err | ||||
| 			} else if !ok { | ||||
| 				valid = false | ||||
| 			} | ||||
| 		case volume.Secret != nil: | ||||
| 			if ok, err := r.validateSecretVolume(volume); err != nil { | ||||
| 				return false, err | ||||
| 			} else if !ok { | ||||
| 				valid = false | ||||
| 			} | ||||
| 		default: //TODO add support for rest of volumes
 | ||||
| 			valid = false | ||||
| 			r.logger.V(log.VWarn).Info(fmt.Sprintf("Unsupported volume '%+v'", volume)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return valid, nil | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateConfigMapVolume(volume corev1.Volume) (bool, error) { | ||||
| 	if volume.ConfigMap.Optional != nil && *volume.ConfigMap.Optional { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 
 | ||||
| 	configMap := &corev1.ConfigMap{} | ||||
| 	err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: volume.ConfigMap.Name, Namespace: r.jenkins.ObjectMeta.Namespace}, configMap) | ||||
| 	if err != nil && apierrors.IsNotFound(err) { | ||||
| 		r.logger.V(log.VWarn).Info(fmt.Sprintf("ConfigMap '%s' not found for volume '%+v'", volume.ConfigMap.Name, volume)) | ||||
| 		return false, nil | ||||
| 	} else if err != nil && !apierrors.IsNotFound(err) { | ||||
| 		return false, stackerr.WithStack(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateSecretVolume(volume corev1.Volume) (bool, error) { | ||||
| 	if volume.Secret.Optional != nil && *volume.Secret.Optional { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 
 | ||||
| 	secret := &corev1.Secret{} | ||||
| 	err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: volume.Secret.SecretName, Namespace: r.jenkins.ObjectMeta.Namespace}, secret) | ||||
| 	if err != nil && apierrors.IsNotFound(err) { | ||||
| 		r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' not found for volume '%+v'", volume.Secret.SecretName, volume)) | ||||
| 		return false, nil | ||||
| 	} else if err != nil && !apierrors.IsNotFound(err) { | ||||
| 		return false, stackerr.WithStack(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateReservedVolumes() bool { | ||||
| 	valid := true | ||||
| 
 | ||||
| 	for _, baseVolume := range resources.GetJenkinsMasterPodBaseVolumes(r.jenkins) { | ||||
| 		for _, volume := range r.jenkins.Spec.Master.Volumes { | ||||
| 			if baseVolume.Name == volume.Name { | ||||
| 				r.logger.V(log.VWarn).Info(fmt.Sprintf("Jenkins Master pod volume '%s' is reserved please choose different one", volume.Name)) | ||||
| 				valid = false | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return valid | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateContainer(container v1alpha1.Container) bool { | ||||
| 	logger := r.logger.WithValues("container", container.Name) | ||||
| 	if container.Image == "" { | ||||
|  | @ -47,7 +135,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateContainer(container v1alpha1 | |||
| 	} | ||||
| 
 | ||||
| 	if !dockerImageRegexp.MatchString(container.Image) && !docker.ReferenceRegexp.MatchString(container.Image) { | ||||
| 		r.logger.V(log.VWarn).Info("Invalid image") | ||||
| 		logger.V(log.VWarn).Info("Invalid image") | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
|  | @ -56,9 +144,40 @@ func (r *ReconcileJenkinsBaseConfiguration) validateContainer(container v1alpha1 | |||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	if !r.validateContainerVolumeMounts(container) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateContainerVolumeMounts(container v1alpha1.Container) bool { | ||||
| 	logger := r.logger.WithValues("container", container.Name) | ||||
| 	allVolumes := append(resources.GetJenkinsMasterPodBaseVolumes(r.jenkins), r.jenkins.Spec.Master.Volumes...) | ||||
| 	valid := true | ||||
| 
 | ||||
| 	for _, volumeMount := range container.VolumeMounts { | ||||
| 		if len(volumeMount.MountPath) == 0 { | ||||
| 			logger.V(log.VWarn).Info(fmt.Sprintf("mountPath not set for '%s' volume mount", volumeMount.Name)) | ||||
| 			valid = false | ||||
| 		} | ||||
| 
 | ||||
| 		foundVolume := false | ||||
| 		for _, volume := range allVolumes { | ||||
| 			if volumeMount.Name == volume.Name { | ||||
| 				foundVolume = true | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if !foundVolume { | ||||
| 			logger.V(log.VWarn).Info(fmt.Sprintf("Not found volume for '%s' volume mount", volumeMount.Name)) | ||||
| 			valid = false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return valid | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateJenkinsMasterPodEnvs() bool { | ||||
| 	baseEnvs := resources.GetJenkinsMasterPodBaseEnvs() | ||||
| 	baseEnvNames := map[string]string{} | ||||
|  |  | |||
|  | @ -1,12 +1,17 @@ | |||
| package base | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"k8s.io/api/core/v1" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/client/fake" | ||||
| 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" | ||||
| ) | ||||
| 
 | ||||
|  | @ -111,3 +116,266 @@ func TestValidateJenkinsMasterPodEnvs(t *testing.T) { | |||
| 		assert.Equal(t, false, got) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestValidateReservedVolumes(t *testing.T) { | ||||
| 	t.Run("happy", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Volumes: []v1.Volume{ | ||||
| 						{ | ||||
| 							Name: "not-used-name", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateReservedVolumes() | ||||
| 		assert.Equal(t, true, got) | ||||
| 	}) | ||||
| 	t.Run("used reserved name", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Volumes: []v1.Volume{ | ||||
| 						{ | ||||
| 							Name: resources.JenkinsHomeVolumeName, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateReservedVolumes() | ||||
| 		assert.Equal(t, false, got) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestValidateContainerVolumeMounts(t *testing.T) { | ||||
| 	t.Run("default Jenkins master container", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Container) | ||||
| 		assert.Equal(t, true, got) | ||||
| 	}) | ||||
| 	t.Run("one extra volume", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Volumes: []v1.Volume{ | ||||
| 						{ | ||||
| 							Name: "example", | ||||
| 						}, | ||||
| 					}, | ||||
| 					Container: v1alpha1.Container{ | ||||
| 						VolumeMounts: []v1.VolumeMount{ | ||||
| 							{ | ||||
| 								Name:      "example", | ||||
| 								MountPath: "/test", | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Container) | ||||
| 		assert.Equal(t, true, got) | ||||
| 	}) | ||||
| 	t.Run("empty mountPath", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Volumes: []v1.Volume{ | ||||
| 						{ | ||||
| 							Name: "example", | ||||
| 						}, | ||||
| 					}, | ||||
| 					Container: v1alpha1.Container{ | ||||
| 						VolumeMounts: []v1.VolumeMount{ | ||||
| 							{ | ||||
| 								Name:      "example", | ||||
| 								MountPath: "", // empty
 | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Container) | ||||
| 		assert.Equal(t, false, got) | ||||
| 	}) | ||||
| 	t.Run("missing volume", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Container: v1alpha1.Container{ | ||||
| 						VolumeMounts: []v1.VolumeMount{ | ||||
| 							{ | ||||
| 								Name:      "missing-volume", | ||||
| 								MountPath: "/test", | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Container) | ||||
| 		assert.Equal(t, false, got) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestValidateConfigMapVolume(t *testing.T) { | ||||
| 	namespace := "default" | ||||
| 	t.Run("optional", func(t *testing.T) { | ||||
| 		optional := true | ||||
| 		volume := corev1.Volume{ | ||||
| 			Name: "name", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					Optional: &optional, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		fakeClient := fake.NewFakeClient() | ||||
| 		baseReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), | ||||
| 			nil, false, false) | ||||
| 
 | ||||
| 		got, err := baseReconcileLoop.validateConfigMapVolume(volume) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.True(t, got) | ||||
| 	}) | ||||
| 	t.Run("happy, required", func(t *testing.T) { | ||||
| 		optional := false | ||||
| 		configMap := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "configmap-name"}} | ||||
| 		jenkins := &v1alpha1.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}} | ||||
| 		volume := corev1.Volume{ | ||||
| 			Name: "volume-name", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					Optional: &optional, | ||||
| 					LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 						Name: configMap.Name, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		fakeClient := fake.NewFakeClient() | ||||
| 		err := fakeClient.Create(context.TODO(), &configMap) | ||||
| 		assert.NoError(t, err) | ||||
| 		baseReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), | ||||
| 			jenkins, false, false) | ||||
| 
 | ||||
| 		got, err := baseReconcileLoop.validateConfigMapVolume(volume) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.True(t, got) | ||||
| 	}) | ||||
| 	t.Run("missing configmap", func(t *testing.T) { | ||||
| 		optional := false | ||||
| 		configMap := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "configmap-name"}} | ||||
| 		jenkins := &v1alpha1.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}} | ||||
| 		volume := corev1.Volume{ | ||||
| 			Name: "volume-name", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					Optional: &optional, | ||||
| 					LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 						Name: configMap.Name, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		fakeClient := fake.NewFakeClient() | ||||
| 		baseReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), | ||||
| 			jenkins, false, false) | ||||
| 
 | ||||
| 		got, err := baseReconcileLoop.validateConfigMapVolume(volume) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.False(t, got) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestValidateSecretVolume(t *testing.T) { | ||||
| 	namespace := "default" | ||||
| 	t.Run("optional", func(t *testing.T) { | ||||
| 		optional := true | ||||
| 		volume := corev1.Volume{ | ||||
| 			Name: "name", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				Secret: &corev1.SecretVolumeSource{ | ||||
| 					Optional: &optional, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		fakeClient := fake.NewFakeClient() | ||||
| 		baseReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), | ||||
| 			nil, false, false) | ||||
| 
 | ||||
| 		got, err := baseReconcileLoop.validateSecretVolume(volume) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.True(t, got) | ||||
| 	}) | ||||
| 	t.Run("happy, required", func(t *testing.T) { | ||||
| 		optional := false | ||||
| 		secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "secret-name"}} | ||||
| 		jenkins := &v1alpha1.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}} | ||||
| 		volume := corev1.Volume{ | ||||
| 			Name: "volume-name", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				Secret: &corev1.SecretVolumeSource{ | ||||
| 					Optional:   &optional, | ||||
| 					SecretName: secret.Name, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		fakeClient := fake.NewFakeClient() | ||||
| 		err := fakeClient.Create(context.TODO(), &secret) | ||||
| 		assert.NoError(t, err) | ||||
| 		baseReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), | ||||
| 			jenkins, false, false) | ||||
| 
 | ||||
| 		got, err := baseReconcileLoop.validateSecretVolume(volume) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.True(t, got) | ||||
| 	}) | ||||
| 	t.Run("missing secret", func(t *testing.T) { | ||||
| 		optional := false | ||||
| 		secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: "secret-name"}} | ||||
| 		jenkins := &v1alpha1.Jenkins{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}} | ||||
| 		volume := corev1.Volume{ | ||||
| 			Name: "volume-name", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				Secret: &corev1.SecretVolumeSource{ | ||||
| 					Optional:   &optional, | ||||
| 					SecretName: secret.Name, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		fakeClient := fake.NewFakeClient() | ||||
| 		baseReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), | ||||
| 			jenkins, false, false) | ||||
| 
 | ||||
| 		got, err := baseReconcileLoop.validateSecretVolume(volume) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.False(t, got) | ||||
| 	}) | ||||
| } | ||||
|  |  | |||
|  | @ -40,11 +40,31 @@ func TestConfiguration(t *testing.T) { | |||
| 			RepositoryURL:         "https://github.com/jenkinsci/kubernetes-operator.git", | ||||
| 		}, | ||||
| 	} | ||||
| 	volumes := []corev1.Volume{ | ||||
| 		{ | ||||
| 			Name: "test-configmap", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||
| 					LocalObjectReference: corev1.LocalObjectReference{ | ||||
| 						Name: resources.GetUserConfigurationConfigMapName(jenkinsCRName), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "test-secret", | ||||
| 			VolumeSource: corev1.VolumeSource{ | ||||
| 				Secret: &corev1.SecretVolumeSource{ | ||||
| 					SecretName: resources.GetUserConfigurationSecretName(jenkinsCRName), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	// base
 | ||||
| 	createUserConfigurationSecret(t, jenkinsCRName, namespace, systemMessageEnvName, systemMessage) | ||||
| 	createUserConfigurationConfigMap(t, jenkinsCRName, namespace, numberOfExecutors, fmt.Sprintf("${%s}", systemMessageEnvName)) | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &[]v1alpha1.SeedJob{mySeedJob.SeedJob}) | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &[]v1alpha1.SeedJob{mySeedJob.SeedJob}, volumes) | ||||
| 	createDefaultLimitsForContainersInNamespace(t, namespace) | ||||
| 	createKubernetesCredentialsProviderSecret(t, namespace, mySeedJob) | ||||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||
|  | @ -161,6 +181,20 @@ func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *v1alpha1.Jenkins) { | |||
| 		verifyContainer(t, *expectedContainer, actualContainer) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, expectedVolume := range jenkins.Spec.Master.Volumes { | ||||
| 		volumeFound := false | ||||
| 		for _, actualVolume := range jenkinsPod.Spec.Volumes { | ||||
| 			if expectedVolume.Name == actualVolume.Name { | ||||
| 				volumeFound = true | ||||
| 				assert.Equal(t, expectedVolume, actualVolume) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if !volumeFound { | ||||
| 			t.Errorf("Missing volume '+%v', actaul volumes '%+v'", expectedVolume, jenkinsPod.Spec.Volumes) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	t.Log("Jenkins pod attributes are valid") | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ func createJenkinsAPIClient(jenkins *v1alpha1.Jenkins) (jenkinsclient.Jenkins, e | |||
| 	) | ||||
| } | ||||
| 
 | ||||
| func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha1.SeedJob) *v1alpha1.Jenkins { | ||||
| func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha1.SeedJob, volumes []corev1.Volume) *v1alpha1.Jenkins { | ||||
| 	var seedJobs []v1alpha1.SeedJob | ||||
| 	if seedJob != nil { | ||||
| 		seedJobs = append(seedJobs, *seedJob...) | ||||
|  | @ -118,6 +118,7 @@ func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha1.S | |||
| 					"simple-theme-plugin:0.5.1": {}, | ||||
| 				}, | ||||
| 				NodeSelector: map[string]string{"kubernetes.io/hostname": "minikube"}, | ||||
| 				Volumes:      volumes, | ||||
| 			}, | ||||
| 			SeedJobs: seedJobs, | ||||
| 		}, | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ func TestJenkinsMasterPodRestart(t *testing.T) { | |||
| 	// Deletes test namespace
 | ||||
| 	defer ctx.Cleanup() | ||||
| 
 | ||||
| 	jenkins := createJenkinsCR(t, "e2e", namespace, nil) | ||||
| 	jenkins := createJenkinsCR(t, "e2e", namespace, nil, []corev1.Volume{}) | ||||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||
| 	restartJenkinsMasterPod(t, jenkins) | ||||
| 	waitForRecreateJenkinsMasterPod(t, jenkins) | ||||
|  | @ -37,7 +37,7 @@ func TestSafeRestart(t *testing.T) { | |||
| 
 | ||||
| 	jenkinsCRName := "e2e" | ||||
| 	configureAuthorizationToUnSecure(t, jenkinsCRName, namespace) | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, nil) | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, nil, []corev1.Volume{}) | ||||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||
| 	waitForJenkinsUserConfigurationToComplete(t, jenkins) | ||||
| 	jenkinsClient := verifyJenkinsAPIConnection(t, jenkins) | ||||
|  |  | |||
|  | @ -51,7 +51,7 @@ func TestSeedJobs(t *testing.T) { | |||
| 		createKubernetesCredentialsProviderSecret(t, namespace, seedJobConfig) | ||||
| 		seedJobs = append(seedJobs, seedJobConfig.SeedJob) | ||||
| 	} | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &seedJobs) | ||||
| 	jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &seedJobs, []corev1.Volume{}) | ||||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||
| 
 | ||||
| 	verifyJenkinsMasterPodAttributes(t, jenkins) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue