#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"`
|
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
||||||
Annotations map[string]string `json:"masterAnnotations,omitempty"`
|
Annotations map[string]string `json:"masterAnnotations,omitempty"`
|
||||||
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
|
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
|
||||||
|
Env []corev1.EnvVar `json:"env,omitempty"`
|
||||||
// OperatorPlugins contains plugins required by operator
|
// OperatorPlugins contains plugins required by operator
|
||||||
OperatorPlugins map[string][]string `json:"basePlugins,omitempty"`
|
OperatorPlugins map[string][]string `json:"basePlugins,omitempty"`
|
||||||
// Plugins contains plugins required by user
|
// Plugins contains plugins required by user
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,13 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in.Resources.DeepCopyInto(&out.Resources)
|
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 {
|
if in.OperatorPlugins != nil {
|
||||||
in, out := &in.OperatorPlugins, &out.OperatorPlugins
|
in, out := &in.OperatorPlugins, &out.OperatorPlugins
|
||||||
*out = make(map[string][]string, len(*in))
|
*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) {
|
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.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
|
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
|
// NewJenkinsMasterPod builds Jenkins Master Kubernetes Pod resource
|
||||||
func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) *corev1.Pod {
|
func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) *corev1.Pod {
|
||||||
initialDelaySeconds := int32(30)
|
initialDelaySeconds := int32(30)
|
||||||
|
|
@ -63,6 +81,8 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins
|
||||||
runAsUser := jenkinsUserUID
|
runAsUser := jenkinsUserUID
|
||||||
|
|
||||||
objectMeta.Annotations = jenkins.Spec.Master.Annotations
|
objectMeta.Annotations = jenkins.Spec.Master.Annotations
|
||||||
|
envs := GetJenkinsMasterPodBaseEnvs()
|
||||||
|
envs = append(envs, jenkins.Spec.Master.Env...)
|
||||||
|
|
||||||
return &corev1.Pod{
|
return &corev1.Pod{
|
||||||
TypeMeta: buildPodTypeMeta(),
|
TypeMeta: buildPodTypeMeta(),
|
||||||
|
|
@ -115,20 +135,7 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins
|
||||||
ContainerPort: constants.DefaultSlavePortInt32,
|
ContainerPort: constants.DefaultSlavePortInt32,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Env: []corev1.EnvVar{
|
Env: envs,
|
||||||
{
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Resources: jenkins.Spec.Master.Resources,
|
Resources: jenkins.Spec.Master.Resources,
|
||||||
VolumeMounts: []corev1.VolumeMount{
|
VolumeMounts: []corev1.VolumeMount{
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
"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/controller/jenkins/plugins"
|
||||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||||
|
|
||||||
|
|
@ -32,9 +33,31 @@ func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha1.Jenkins)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !r.validateJenkinsMasterPodEnvs() {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
return true, 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 {
|
func (r *ReconcileJenkinsBaseConfiguration) validatePlugins(pluginsWithVersionSlice ...map[string][]string) bool {
|
||||||
valid := true
|
valid := true
|
||||||
allPlugins := map[plugins.Plugin][]plugins.Plugin{}
|
allPlugins := map[plugins.Plugin][]plugins.Plugin{}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ package base
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
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)
|
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")
|
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": {},
|
"simple-theme-plugin:0.5.1": {},
|
||||||
},
|
},
|
||||||
NodeSelector: map[string]string{"kubernetes.io/hostname": "minikube"},
|
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
|
//TODO(bantoniak) add seed job with private key
|
||||||
SeedJobs: []v1alpha1.SeedJob{
|
SeedJobs: []v1alpha1.SeedJob{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue