From 3a1f9e1ccc747bf0266b615693dac8dca36d9556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20S=C4=99k?= Date: Fri, 23 Aug 2019 13:43:18 +0200 Subject: [PATCH] #76 Allow configure JAVA_OPTS variable in Jenkins container --- .../configuration/base/resources/pod.go | 4 -- .../jenkins/configuration/base/validate.go | 27 +++++++++- .../configuration/base/validate_test.go | 54 +++++++++++++++++++ pkg/controller/jenkins/constants/constants.go | 2 + pkg/controller/jenkins/jenkins_controller.go | 17 ++++++ 5 files changed, 99 insertions(+), 5 deletions(-) diff --git a/pkg/controller/jenkins/configuration/base/resources/pod.go b/pkg/controller/jenkins/configuration/base/resources/pod.go index 6dcbf6fb..7f4146c1 100644 --- a/pkg/controller/jenkins/configuration/base/resources/pod.go +++ b/pkg/controller/jenkins/configuration/base/resources/pod.go @@ -67,10 +67,6 @@ func GetJenkinsMasterContainerBaseEnvs(jenkins *v1alpha2.Jenkins) []corev1.EnvVa Name: "JENKINS_HOME", Value: jenkinsHomePath, }, - { - Name: "JAVA_OPTS", - Value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Djenkins.install.runSetupWizard=false -Djava.awt.headless=true", - }, } if len(jenkins.Spec.ConfigurationAsCode.Secret.Name) > 0 { diff --git a/pkg/controller/jenkins/configuration/base/validate.go b/pkg/controller/jenkins/configuration/base/validate.go index d6f8d4ab..31a2a803 100644 --- a/pkg/controller/jenkins/configuration/base/validate.go +++ b/pkg/controller/jenkins/configuration/base/validate.go @@ -4,9 +4,11 @@ import ( "context" "fmt" "regexp" + "strings" "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" + "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" "github.com/jenkinsci/kubernetes-operator/pkg/log" @@ -254,14 +256,37 @@ func (r *ReconcileJenkinsBaseConfiguration) validateJenkinsMasterPodEnvs() bool baseEnvNames[env.Name] = env.Value } + javaOpts := corev1.EnvVar{} valid := true for _, userEnv := range r.jenkins.Spec.Master.Containers[0].Env { + if userEnv.Name == constants.JavaOpsVariableName { + javaOpts = userEnv + } if _, overriding := baseEnvNames[userEnv.Name]; overriding { - r.logger.V(log.VWarn).Info(fmt.Sprintf("Jenkins Master pod env '%s' cannot be overridden", userEnv.Name)) + r.logger.V(log.VWarn).Info(fmt.Sprintf("Jenkins Master container env '%s' cannot be overridden", userEnv.Name)) valid = false } } + requiredFlags := map[string]bool{ + "-Djenkins.install.runSetupWizard=false": false, + "-Djava.awt.headless=true": false, + } + for _, setFlag := range strings.Split(javaOpts.Value, " ") { + for requiredFlag := range requiredFlags { + if setFlag == requiredFlag { + requiredFlags[requiredFlag] = true + break + } + } + } + for requiredFlag, set := range requiredFlags { + if !set { + valid = false + r.logger.V(log.VWarn).Info(fmt.Sprintf("Jenkins Master container env '%s' doesn't have required flag '%s'", constants.JavaOpsVariableName, requiredFlag)) + } + } + return valid } diff --git a/pkg/controller/jenkins/configuration/base/validate_test.go b/pkg/controller/jenkins/configuration/base/validate_test.go index 3dcb258c..08d409c5 100644 --- a/pkg/controller/jenkins/configuration/base/validate_test.go +++ b/pkg/controller/jenkins/configuration/base/validate_test.go @@ -6,6 +6,7 @@ import ( "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" + "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" "github.com/jenkinsci/kubernetes-operator/pkg/log" @@ -322,6 +323,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T } func TestValidateJenkinsMasterPodEnvs(t *testing.T) { + validJenkinsOps := "-Djenkins.install.runSetupWizard=false -Djava.awt.headless=true" t.Run("happy", func(t *testing.T) { jenkins := v1alpha2.Jenkins{ Spec: v1alpha2.JenkinsSpec{ @@ -333,6 +335,10 @@ func TestValidateJenkinsMasterPodEnvs(t *testing.T) { Name: "SOME_VALUE", Value: "", }, + { + Name: constants.JavaOpsVariableName, + Value: validJenkinsOps, + }, }, }, }, @@ -355,6 +361,54 @@ func TestValidateJenkinsMasterPodEnvs(t *testing.T) { Name: "JENKINS_HOME", Value: "", }, + { + Name: constants.JavaOpsVariableName, + Value: validJenkinsOps, + }, + }, + }, + }, + }, + }, + } + baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), + &jenkins, false, false, nil, nil) + got := baseReconcileLoop.validateJenkinsMasterPodEnvs() + assert.Equal(t, false, got) + }) + t.Run("missing -Djava.awt.headless=true in JAVA_OPTS env", func(t *testing.T) { + jenkins := v1alpha2.Jenkins{ + Spec: v1alpha2.JenkinsSpec{ + Master: v1alpha2.JenkinsMaster{ + Containers: []v1alpha2.Container{ + { + Env: []v1.EnvVar{ + { + Name: constants.JavaOpsVariableName, + Value: "-Djenkins.install.runSetupWizard=false", + }, + }, + }, + }, + }, + }, + } + baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), + &jenkins, false, false, nil, nil) + got := baseReconcileLoop.validateJenkinsMasterPodEnvs() + assert.Equal(t, false, got) + }) + t.Run("missing -Djenkins.install.runSetupWizard=false in JAVA_OPTS env", func(t *testing.T) { + jenkins := v1alpha2.Jenkins{ + Spec: v1alpha2.JenkinsSpec{ + Master: v1alpha2.JenkinsMaster{ + Containers: []v1alpha2.Container{ + { + Env: []v1.EnvVar{ + { + Name: constants.JavaOpsVariableName, + Value: "-Djava.awt.headless=true", + }, }, }, }, diff --git a/pkg/controller/jenkins/constants/constants.go b/pkg/controller/jenkins/constants/constants.go index fbf5434b..dc83a1d2 100644 --- a/pkg/controller/jenkins/constants/constants.go +++ b/pkg/controller/jenkins/constants/constants.go @@ -17,4 +17,6 @@ const ( DefaultHTTPPortInt32 = int32(8080) // DefaultSlavePortInt32 is the default Jenkins port for slaves DefaultSlavePortInt32 = int32(50000) + // JavaOpsVariableName is the name of environment variable which consists Jenkins Java options + JavaOpsVariableName = "JAVA_OPTS" ) diff --git a/pkg/controller/jenkins/jenkins_controller.go b/pkg/controller/jenkins/jenkins_controller.go index ea56a719..9aaeeaa7 100644 --- a/pkg/controller/jenkins/jenkins_controller.go +++ b/pkg/controller/jenkins/jenkins_controller.go @@ -334,6 +334,14 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha2.Jenkins, logger logr.Lo changed = true jenkinsContainer.Command = resources.GetJenkinsMasterContainerBaseCommand() } + if isJavaOpsVariableNotSet(jenkinsContainer) { + logger.Info("Setting default Jenkins container JAVA_OPTS environment variable") + changed = true + jenkinsContainer.Env = append(jenkinsContainer.Env, corev1.EnvVar{ + Name: constants.JavaOpsVariableName, + Value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Djenkins.install.runSetupWizard=false -Djava.awt.headless=true", + }) + } if len(jenkins.Spec.Master.BasePlugins) == 0 { logger.Info("Setting default operator plugins") changed = true @@ -426,6 +434,15 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha2.Jenkins, logger logr.Lo return nil } +func isJavaOpsVariableNotSet(container v1alpha2.Container) bool { + for _, env := range container.Env { + if env.Name == constants.JavaOpsVariableName { + return false + } + } + return true +} + func setDefaultsForContainer(jenkins *v1alpha2.Jenkins, containerIndex int, logger logr.Logger) bool { changed := false