#9 Allow set Jenkins master pod env variables
This commit is contained in:
		
							parent
							
								
									35f1b318bb
								
							
						
					
					
						commit
						2aa96789b4
					
				|  | @ -25,6 +25,7 @@ type JenkinsMaster struct { | |||
| 	NodeSelector map[string]string           `json:"nodeSelector,omitempty"` | ||||
| 	Annotations  map[string]string           `json:"masterAnnotations,omitempty"` | ||||
| 	Resources    corev1.ResourceRequirements `json:"resources,omitempty"` | ||||
| 	Env          []corev1.EnvVar             `json:"env,omitempty"` | ||||
| 	// OperatorPlugins contains plugins required by operator
 | ||||
| 	OperatorPlugins map[string][]string `json:"basePlugins,omitempty"` | ||||
| 	// Plugins contains plugins required by user
 | ||||
|  |  | |||
|  | @ -128,6 +128,13 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) { | |||
| 		} | ||||
| 	} | ||||
| 	in.Resources.DeepCopyInto(&out.Resources) | ||||
| 	if in.Env != nil { | ||||
| 		in, out := &in.Env, &out.Env | ||||
| 		*out = make([]v1.EnvVar, len(*in)) | ||||
| 		for i := range *in { | ||||
| 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||
| 		} | ||||
| 	} | ||||
| 	if in.OperatorPlugins != nil { | ||||
| 		in, out := &in.OperatorPlugins, &out.OperatorPlugins | ||||
| 		*out = make(map[string][]string, len(*in)) | ||||
|  |  | |||
|  | @ -401,7 +401,15 @@ func (r *ReconcileJenkinsBaseConfiguration) isRecreatePodNeeded(currentJenkinsMa | |||
| 
 | ||||
| 	if !reflect.DeepEqual(r.jenkins.Spec.Master.NodeSelector, currentJenkinsMasterPod.Spec.NodeSelector) { | ||||
| 		r.logger.Info(fmt.Sprintf("Jenkins pod node selector has changed, actual '%+v' required '%+v' - recreating pod", | ||||
| 			r.jenkins.Spec.Master.NodeSelector, currentJenkinsMasterPod.Spec.NodeSelector)) | ||||
| 			currentJenkinsMasterPod.Spec.NodeSelector, r.jenkins.Spec.Master.NodeSelector)) | ||||
| 		recreatePod = true | ||||
| 	} | ||||
| 
 | ||||
| 	requiredEnvs := resources.GetJenkinsMasterPodBaseEnvs() | ||||
| 	requiredEnvs = append(requiredEnvs, r.jenkins.Spec.Master.Env...) | ||||
| 	if !reflect.DeepEqual(requiredEnvs, currentJenkinsMasterPod.Spec.Containers[0].Env) { | ||||
| 		r.logger.Info(fmt.Sprintf("Jenkins env have changed, actual '%+v' required '%+v' - recreating pod", | ||||
| 			currentJenkinsMasterPod.Spec.Containers[0].Env, requiredEnvs)) | ||||
| 		recreatePod = true | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,6 +55,24 @@ func buildPodTypeMeta() metav1.TypeMeta { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetJenkinsMasterPodBaseEnvs returns Jenkins master pod envs required by operator
 | ||||
| func GetJenkinsMasterPodBaseEnvs() []corev1.EnvVar { | ||||
| 	return []corev1.EnvVar{ | ||||
| 		{ | ||||
| 			Name:  "JENKINS_HOME", | ||||
| 			Value: jenkinsHomePath, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:  "JAVA_OPTS", | ||||
| 			Value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Djenkins.install.runSetupWizard=false -Djava.awt.headless=true", | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:  "SECRETS", // https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/demos/kubernetes-secrets/README.md
 | ||||
| 			Value: UserConfigurationSecretVolumePath, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewJenkinsMasterPod builds Jenkins Master Kubernetes Pod resource
 | ||||
| func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) *corev1.Pod { | ||||
| 	initialDelaySeconds := int32(30) | ||||
|  | @ -63,6 +81,8 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins | |||
| 	runAsUser := jenkinsUserUID | ||||
| 
 | ||||
| 	objectMeta.Annotations = jenkins.Spec.Master.Annotations | ||||
| 	envs := GetJenkinsMasterPodBaseEnvs() | ||||
| 	envs = append(envs, jenkins.Spec.Master.Env...) | ||||
| 
 | ||||
| 	return &corev1.Pod{ | ||||
| 		TypeMeta:   buildPodTypeMeta(), | ||||
|  | @ -115,20 +135,7 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins | |||
| 							ContainerPort: constants.DefaultSlavePortInt32, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Env: []corev1.EnvVar{ | ||||
| 						{ | ||||
| 							Name:  "JENKINS_HOME", | ||||
| 							Value: jenkinsHomePath, | ||||
| 						}, | ||||
| 						{ | ||||
| 							Name:  "JAVA_OPTS", | ||||
| 							Value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Djenkins.install.runSetupWizard=false -Djava.awt.headless=true", | ||||
| 						}, | ||||
| 						{ | ||||
| 							Name:  "SECRETS", // https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/demos/kubernetes-secrets/README.md
 | ||||
| 							Value: UserConfigurationSecretVolumePath, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Env:       envs, | ||||
| 					Resources: jenkins.Spec.Master.Resources, | ||||
| 					VolumeMounts: []corev1.VolumeMount{ | ||||
| 						{ | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import ( | |||
| 	"regexp" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/log" | ||||
| 
 | ||||
|  | @ -32,9 +33,31 @@ func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha1.Jenkins) | |||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	if !r.validateJenkinsMasterPodEnvs() { | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validateJenkinsMasterPodEnvs() bool { | ||||
| 	baseEnvs := resources.GetJenkinsMasterPodBaseEnvs() | ||||
| 	baseEnvNames := map[string]string{} | ||||
| 	for _, env := range baseEnvs { | ||||
| 		baseEnvNames[env.Name] = env.Value | ||||
| 	} | ||||
| 
 | ||||
| 	valid := true | ||||
| 	for _, userEnv := range r.jenkins.Spec.Master.Env { | ||||
| 		if _, overriding := baseEnvNames[userEnv.Name]; overriding { | ||||
| 			r.logger.V(log.VWarn).Info(fmt.Sprintf("Jenkins Master pod env '%s' cannot be overridden", userEnv.Name)) | ||||
| 			valid = false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return valid | ||||
| } | ||||
| 
 | ||||
| func (r *ReconcileJenkinsBaseConfiguration) validatePlugins(pluginsWithVersionSlice ...map[string][]string) bool { | ||||
| 	valid := true | ||||
| 	allPlugins := map[plugins.Plugin][]plugins.Plugin{} | ||||
|  |  | |||
|  | @ -3,7 +3,10 @@ package base | |||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"k8s.io/api/core/v1" | ||||
| 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" | ||||
| ) | ||||
| 
 | ||||
|  | @ -65,3 +68,42 @@ func TestValidatePlugins(t *testing.T) { | |||
| 	}) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func TestValidateJenkinsMasterPodEnvs(t *testing.T) { | ||||
| 	t.Run("happy", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Env: []v1.EnvVar{ | ||||
| 						{ | ||||
| 							Name:  "SOME_VALUE", | ||||
| 							Value: "", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateJenkinsMasterPodEnvs() | ||||
| 		assert.Equal(t, true, got) | ||||
| 	}) | ||||
| 	t.Run("override JENKINS_HOME env", func(t *testing.T) { | ||||
| 		jenkins := v1alpha1.Jenkins{ | ||||
| 			Spec: v1alpha1.JenkinsSpec{ | ||||
| 				Master: v1alpha1.JenkinsMaster{ | ||||
| 					Env: []v1.EnvVar{ | ||||
| 						{ | ||||
| 							Name:  "JENKINS_HOME", | ||||
| 							Value: "", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||
| 			&jenkins, false, false) | ||||
| 		got := baseReconcileLoop.validateJenkinsMasterPodEnvs() | ||||
| 		assert.Equal(t, false, got) | ||||
| 	}) | ||||
| } | ||||
|  |  | |||
|  | @ -143,6 +143,12 @@ func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *v1alpha1.Jenkins) { | |||
| 		t.Fatalf("Invalid jenkins pod node selector expected '%+v', actual '%+v'", jenkins.Spec.Master.NodeSelector, jenkinsPod.Spec.NodeSelector) | ||||
| 	} | ||||
| 
 | ||||
| 	requiredEnvs := resources.GetJenkinsMasterPodBaseEnvs() | ||||
| 	requiredEnvs = append(requiredEnvs, jenkins.Spec.Master.Env...) | ||||
| 	if !reflect.DeepEqual(jenkinsPod.Spec.Containers[0].Env, requiredEnvs) { | ||||
| 		t.Fatalf("Invalid jenkins pod continer resources expected '%+v', actual '%+v'", requiredEnvs, jenkinsPod.Spec.Containers[0].Env) | ||||
| 	} | ||||
| 
 | ||||
| 	t.Log("Jenkins pod attributes are valid") | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -73,6 +73,12 @@ func createJenkinsCR(t *testing.T, name, namespace string) *v1alpha1.Jenkins { | |||
| 					"simple-theme-plugin:0.5.1": {}, | ||||
| 				}, | ||||
| 				NodeSelector: map[string]string{"kubernetes.io/hostname": "minikube"}, | ||||
| 				Env: []v1.EnvVar{ | ||||
| 					{ | ||||
| 						Name:  "TEST_ENV", | ||||
| 						Value: "test_env_value", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			//TODO(bantoniak) add seed job with private key
 | ||||
| 			SeedJobs: []v1alpha1.SeedJob{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue