wip tests and chart values for ephemeral home

This commit is contained in:
Luigi Operoso 2023-05-06 16:43:26 +00:00
parent 4727c06c87
commit 4e9050d276
10 changed files with 152 additions and 55 deletions

View File

@ -346,7 +346,7 @@ type JenkinsMaster struct {
// Storage settings for the jenkins home directory // Storage settings for the jenkins home directory
// Can be tempDir or ephemeral // Can be tempDir or ephemeral
// +optional // +optional
StorageSettings StorageSettings `json:"storage,omitempty"` StorageSettings StorageSettings `json:"storageSettings,omitempty"`
// If specified, the pod's tolerations. // If specified, the pod's tolerations.
// +optional // +optional
@ -392,11 +392,16 @@ type JenkinsMaster struct {
HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"` HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"`
} }
// StorageSettings defines Jenkins master pod persistance attributes. // StorageSettings defines Jenkins master pod persistence attributes.
// +optional
type StorageSettings struct { type StorageSettings struct {
UseTempDir bool `json:"useTempDir"` // UseEmptyDir allows you to create an emptydir as jenkins-home, also this is the default
UseEmptyDir bool `json:"useEmptyDir"`
// UseEphemeralStorage allows you to create kubernetes ephemeral pvc, see "https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes"
UseEphemeralStorage bool `json:"useEphemeralStorage"` UseEphemeralStorage bool `json:"useEphemeralStorage"`
// StorageClassName in case of ephemeral pvc, can be empty
StorageClassName string `json:"storageClassName"` StorageClassName string `json:"storageClassName"`
// StorageRequest allows you to specify the storage request, required in case of ephemeral pvc
StorageRequest string `json:"storageRequest"` StorageRequest string `json:"storageRequest"`
} }

View File

@ -1,4 +1,3 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated // +build !ignore_autogenerated
/* /*
@ -23,7 +22,7 @@ package v1alpha2
import ( import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1" "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -340,6 +339,7 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
} }
out.StorageSettings = in.StorageSettings
if in.Tolerations != nil { if in.Tolerations != nil {
in, out := &in.Tolerations, &out.Tolerations in, out := &in.Tolerations, &out.Tolerations
*out = make([]corev1.Toleration, len(*in)) *out = make([]corev1.Toleration, len(*in))
@ -400,7 +400,7 @@ func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) {
in.ConfigurationAsCode.DeepCopyInto(&out.ConfigurationAsCode) in.ConfigurationAsCode.DeepCopyInto(&out.ConfigurationAsCode)
if in.Roles != nil { if in.Roles != nil {
in, out := &in.Roles, &out.Roles in, out := &in.Roles, &out.Roles
*out = make([]rbacv1.RoleRef, len(*in)) *out = make([]v1.RoleRef, len(*in))
copy(*out, *in) copy(*out, *in)
} }
in.ServiceAccount.DeepCopyInto(&out.ServiceAccount) in.ServiceAccount.DeepCopyInto(&out.ServiceAccount)
@ -763,6 +763,21 @@ func (in *Slack) DeepCopy() *Slack {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StorageSettings) DeepCopyInto(out *StorageSettings) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageSettings.
func (in *StorageSettings) DeepCopy() *StorageSettings {
if in == nil {
return nil
}
out := new(StorageSettings)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Version) DeepCopyInto(out *Version) { func (in *Version) DeepCopyInto(out *Version) {
*out = *in *out = *in

View File

@ -157,11 +157,11 @@ spec:
type: object type: object
basePlugins: basePlugins:
description: 'BasePlugins contains plugins required by operator description: 'BasePlugins contains plugins required by operator
Defaults to : - name: kubernetes version: "1.31.3" - name: Defaults to : - name: configuration-as-code version: "1625.v27444588cc3d"
workflow-job version: "1145.v7f2433caa07f" - name: workflow-aggregator version: - name: git version: "5.0.0" - name: job-dsl version: "1.83"
"2.6" - name: git version: "4.11.3" - name: job-dsl version: - name: kubernetes version: "3909.v1f2c633e8590" - name: kubernetes-credentials-provider
"1.78.1" - name: configuration-as-code version: "1346.ve8cfa_3473c94" - name: version: "1.211.vc236a_f5a_2f3c" - name: workflow-aggregator
kubernetes-credentials-provider version: "0.20"' version: "596.v8c21c963d92d" - name: workflow-job version: "1289.vd1c337fd5354"'
items: items:
description: Plugin defines Jenkins plugin. description: Plugin defines Jenkins plugin.
properties: properties:
@ -1100,11 +1100,6 @@ spec:
- resources - resources
type: object type: object
type: array type: array
latestPlugins:
description: 'Allow to override jenkins-plugin-cli default behavior
while downloading the plugin and dependencies, see:
https://github.com/jenkinsci/plugin-installation-manager-tool#cli-options'
type: boolean
disableCSRFProtection: disableCSRFProtection:
description: DisableCSRFProtection allows you to toggle CSRF Protection description: DisableCSRFProtection allows you to toggle CSRF Protection
on Jenkins on Jenkins
@ -1150,6 +1145,10 @@ spec:
selectors of replication controllers and services. More info: selectors of replication controllers and services. More info:
http://kubernetes.io/docs/user-guide/labels' http://kubernetes.io/docs/user-guide/labels'
type: object type: object
latestPlugins:
description: 'Allow to override jenkins-plugin-cli default behavior
while downloading the plugin and dependencies see: https://github.com/jenkinsci/plugin-installation-manager-tool#cli-options'
type: boolean
nodeSelector: nodeSelector:
additionalProperties: additionalProperties:
type: string type: string
@ -1331,6 +1330,32 @@ spec:
type: string type: string
type: object type: object
type: object type: object
storageSettings:
description: Storage settings for the jenkins home directory Can
be tempDir or ephemeral
properties:
storageClassName:
description: StorageClassName in case of ephemeral pvc, can
be empty
type: string
storageRequest:
description: StorageRequest allows you to specify the storage
request, required in case of ephemeral pvc
type: string
useEmptyDir:
description: UseEmptyDir allows you to create an emptydir
as jenkins-home, also this is the default
type: boolean
useEphemeralStorage:
description: UseEphemeralStorage allows you to create kubernetes
ephemeral pvc, see "https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes"
type: boolean
required:
- storageClassName
- storageRequest
- useEmptyDir
- useEphemeralStorage
type: object
tolerations: tolerations:
description: If specified, the pod's tolerations. description: If specified, the pod's tolerations.
items: items:
@ -2864,6 +2889,7 @@ spec:
type: array type: array
required: required:
- disableCSRFProtection - disableCSRFProtection
- latestPlugins
type: object type: object
notifications: notifications:
description: Notifications defines list of a services which are used description: Notifications defines list of a services which are used
@ -3124,8 +3150,10 @@ spec:
type: object type: object
type: array type: array
seedJobAgentImage: seedJobAgentImage:
description: SeedJobAgentImage defines the image that will be used
by the seed job agent. If not defined jenkins/inbound-agent:4.9-1
will be used.
type: string type: string
description: 'SeedJobAgentImage defines the image that will be used by the seed job agent. If not defined jenkins/inbound-agent:4.10-3 will be used.'
seedJobs: seedJobs:
description: 'SeedJobs defines list of Jenkins Seed Job configurations description: 'SeedJobs defines list of Jenkins Seed Job configurations
More info: https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuration#configure-seed-jobs-and-pipelines' More info: https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuration#configure-seed-jobs-and-pipelines'

View File

@ -146,6 +146,9 @@ spec:
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- with .Values.jenkins.volumes }} {{- with .Values.jenkins.volumes }}
storageSettings: {{- toYaml . | nindent 6 }}
{{- end }}
{{- with .Values.jenkins.storageSettings }}
volumes: {{- toYaml . | nindent 4 }} volumes: {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
{{- with .Values.jenkins.imagePullSecrets }} {{- with .Values.jenkins.imagePullSecrets }}

View File

@ -158,6 +158,18 @@ jenkins:
# See https://jenkinsci.github.io/kubernetes-operator/docs/installation/#note-on-restricted-jenkins-controller-pod-volumemounts for details # See https://jenkinsci.github.io/kubernetes-operator/docs/installation/#note-on-restricted-jenkins-controller-pod-volumemounts for details
volumeMounts: [] volumeMounts: []
# Storage for Jenkins
# By default emptyDir
# See https://kubernetes.io/docs/concepts/storage/volumes/#emptydir for details
storageSettings:
useEmptyDir: true
# Alternative storage settings
# An ephemeral pvc can be used see https://kubernetes.io/docs/concepts/storage/volumes/#ephemeral-volume
# In case is true we also need to pass the storageRequest and optionally the storageClassName
ephemeralStorage: false
storageClassName: ""
storageRequest: ""
# defines authorization strategy of the operator for the Jenkins API # defines authorization strategy of the operator for the Jenkins API
authorizationStrategy: createUser authorizationStrategy: createUser

View File

@ -157,11 +157,11 @@ spec:
type: object type: object
basePlugins: basePlugins:
description: 'BasePlugins contains plugins required by operator description: 'BasePlugins contains plugins required by operator
Defaults to : - name: kubernetes version: "1.31.3" - name: Defaults to : - name: configuration-as-code version: "1625.v27444588cc3d"
workflow-job version: "1145.v7f2433caa07f" - name: workflow-aggregator version: - name: git version: "5.0.0" - name: job-dsl version: "1.83"
"2.6" - name: git version: "4.11.3" - name: job-dsl version: - name: kubernetes version: "3909.v1f2c633e8590" - name: kubernetes-credentials-provider
"1.78.1" - name: configuration-as-code version: "1346.ve8cfa_3473c94" - name: version: "1.211.vc236a_f5a_2f3c" - name: workflow-aggregator
kubernetes-credentials-provider version: "0.20"' version: "596.v8c21c963d92d" - name: workflow-job version: "1289.vd1c337fd5354"'
items: items:
description: Plugin defines Jenkins plugin. description: Plugin defines Jenkins plugin.
properties: properties:
@ -1100,11 +1100,6 @@ spec:
- resources - resources
type: object type: object
type: array type: array
latestPlugins:
description: 'Allow to override jenkins-plugin-cli default behavior
while downloading the plugin and dependencies, see:
https://github.com/jenkinsci/plugin-installation-manager-tool#cli-options'
type: boolean
disableCSRFProtection: disableCSRFProtection:
description: DisableCSRFProtection allows you to toggle CSRF Protection description: DisableCSRFProtection allows you to toggle CSRF Protection
on Jenkins on Jenkins
@ -1150,6 +1145,10 @@ spec:
selectors of replication controllers and services. More info: selectors of replication controllers and services. More info:
http://kubernetes.io/docs/user-guide/labels' http://kubernetes.io/docs/user-guide/labels'
type: object type: object
latestPlugins:
description: 'Allow to override jenkins-plugin-cli default behavior
while downloading the plugin and dependencies see: https://github.com/jenkinsci/plugin-installation-manager-tool#cli-options'
type: boolean
nodeSelector: nodeSelector:
additionalProperties: additionalProperties:
type: string type: string
@ -1331,6 +1330,32 @@ spec:
type: string type: string
type: object type: object
type: object type: object
storageSettings:
description: Storage settings for the jenkins home directory Can
be tempDir or ephemeral
properties:
storageClassName:
description: StorageClassName in case of ephemeral pvc, can
be empty
type: string
storageRequest:
description: StorageRequest allows you to specify the storage
request, required in case of ephemeral pvc
type: string
useEmptyDir:
description: UseEmptyDir allows you to create an emptydir
as jenkins-home, also this is the default
type: boolean
useEphemeralStorage:
description: UseEphemeralStorage allows you to create kubernetes
ephemeral pvc, see "https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes"
type: boolean
required:
- storageClassName
- storageRequest
- useEmptyDir
- useEphemeralStorage
type: object
tolerations: tolerations:
description: If specified, the pod's tolerations. description: If specified, the pod's tolerations.
items: items:
@ -2864,6 +2889,7 @@ spec:
type: array type: array
required: required:
- disableCSRFProtection - disableCSRFProtection
- latestPlugins
type: object type: object
notifications: notifications:
description: Notifications defines list of a services which are used description: Notifications defines list of a services which are used
@ -3124,8 +3150,10 @@ spec:
type: object type: object
type: array type: array
seedJobAgentImage: seedJobAgentImage:
description: SeedJobAgentImage defines the image that will be used
by the seed job agent. If not defined jenkins/inbound-agent:4.9-1
will be used.
type: string type: string
description: 'SeedJobAgentImage defines the image that will be used by the seed job agent. If not defined jenkins/inbound-agent:4.10-3 will be used.'
seedJobs: seedJobs:
description: 'SeedJobs defines list of Jenkins Seed Job configurations description: 'SeedJobs defines list of Jenkins Seed Job configurations
More info: https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuration#configure-seed-jobs-and-pipelines' More info: https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuration#configure-seed-jobs-and-pipelines'

View File

@ -94,16 +94,11 @@ func validateStorageSize(storageSize string) bool {
return false return false
} }
_, err := resource.ParseQuantity(storageSize) _, err := resource.ParseQuantity(storageSize)
if err != nil { return err == nil
return false
}
return true
} }
// get Jenkins home storage settings from the CRD // get Jenkins home storage settings from the CRD
func getJenkinsHomeStorageSettings(jenkins *v1alpha2.Jenkins) corev1.Volume { func getJenkinsHomeStorageSettings(jenkins *v1alpha2.Jenkins) corev1.Volume {
JenkinsHomeVolume := corev1.Volume{}
emptyDirVol := corev1.Volume{ emptyDirVol := corev1.Volume{
Name: JenkinsHomeVolumeName, Name: JenkinsHomeVolumeName,
VolumeSource: corev1.VolumeSource{ VolumeSource: corev1.VolumeSource{
@ -111,7 +106,7 @@ func getJenkinsHomeStorageSettings(jenkins *v1alpha2.Jenkins) corev1.Volume {
EmptyDir: &corev1.EmptyDirVolumeSource{}, EmptyDir: &corev1.EmptyDirVolumeSource{},
}, },
} }
var JenkinsHomeVolume corev1.Volume
if jenkins.Spec.Master.StorageSettings.UseEphemeralStorage { if jenkins.Spec.Master.StorageSettings.UseEphemeralStorage {
if !validateStorageSize(jenkins.Spec.Master.StorageSettings.StorageRequest) { if !validateStorageSize(jenkins.Spec.Master.StorageSettings.StorageRequest) {
fmt.Println("Invalid storage size %s, falling back to empty dir" + jenkins.Spec.Master.StorageSettings.StorageRequest) fmt.Println("Invalid storage size %s, falling back to empty dir" + jenkins.Spec.Master.StorageSettings.StorageRequest)

View File

@ -1,6 +1,7 @@
package resources package resources
import ( import (
"fmt"
"testing" "testing"
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2" "github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
@ -143,22 +144,23 @@ func TestGetJenkinsMasterPodBaseVolumes(t *testing.T) {
assert.True(t, groovyExists) assert.True(t, groovyExists)
assert.True(t, cascExists) assert.True(t, cascExists)
}) })
// TODO: fix me
t.Run("home volume is present and is Tempdir", func(t *testing.T) { t.Run("home volume is present and is Tempdir", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{ jenkins := &v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{ Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{ Master: v1alpha2.JenkinsMaster{
StorageSettings: v1alpha2.StorageSettings{ StorageSettings: v1alpha2.StorageSettings{
UseTempDir: true, UseEmptyDir: true,
}, },
}, },
}, },
} }
HomeExist, HomeTempdirExist, HomeEphemeralStorageExist := checkHomeVolumesPresence(jenkins) homeExist, homeTempdirExist, homeEphemeralStorageExist := checkHomeVolumesPresence(jenkins)
assert.True(t, HomeExist) assert.True(t, homeExist)
assert.True(t, HomeTempdirExist) assert.True(t, homeTempdirExist)
assert.False(t, HomeEphemeralStorageExist) assert.False(t, homeEphemeralStorageExist)
}) })
t.Run("home volume is present and it's ephemeral", func(t *testing.T) { t.Run("home volume is present and it's ephemeral", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{ jenkins := &v1alpha2.Jenkins{
@ -166,18 +168,27 @@ func TestGetJenkinsMasterPodBaseVolumes(t *testing.T) {
Master: v1alpha2.JenkinsMaster{ Master: v1alpha2.JenkinsMaster{
StorageSettings: v1alpha2.StorageSettings{ StorageSettings: v1alpha2.StorageSettings{
UseEphemeralStorage: true, UseEphemeralStorage: true,
StorageClassName: "", StorageClassName: "default",
StorageRequest: "1Gi", StorageRequest: "1Gi",
}, },
}, },
}, },
} }
HomeExist, HomeTempdirExist, HomeEphemeralStorageExist := checkHomeVolumesPresence(jenkins) homeExist, homeTempdirExist, homeEphemeralStorageExist := checkHomeVolumesPresence(jenkins)
assert.True(t, HomeExist) assert.True(t, homeExist)
assert.False(t, HomeTempdirExist) assert.False(t, homeTempdirExist)
assert.True(t, HomeEphemeralStorageExist) assert.True(t, homeEphemeralStorageExist)
})
t.Run("home volume is default and should be an empty dir", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{}
homeExist, homeTempdirExist, homeEphemeralStorageExist := checkHomeVolumesPresence(jenkins)
assert.True(t, homeExist)
assert.True(t, homeTempdirExist)
assert.False(t, homeEphemeralStorageExist)
}) })
} }
@ -192,23 +203,23 @@ func checkSecretVolumesPresence(jenkins *v1alpha2.Jenkins) (groovyExists bool, c
return groovyExists, cascExists return groovyExists, cascExists
} }
func checkHomeVolumesPresence(jenkins *v1alpha2.Jenkins) (HomeExist bool, HomeTempdirExist bool, HomeEphemeralStorageExist bool) { func checkHomeVolumesPresence(jenkins *v1alpha2.Jenkins) (homeExist bool, homeTempdirExist bool, homeEphemeralStorageExist bool) {
for _, volume := range GetJenkinsMasterPodBaseVolumes(jenkins) { for _, volume := range GetJenkinsMasterPodBaseVolumes(jenkins) {
if volume.Name == ("jenkins-home") { if volume.Name == ("jenkins-home") {
HomeExist = true homeExist = true
// check if the volume is an emptyDir // check if the volume is an emptyDir
if volume.VolumeSource.EmptyDir != nil { if volume.VolumeSource.EmptyDir != nil {
HomeTempdirExist = true homeTempdirExist = true
} else if volume.VolumeSource.Ephemeral != nil { } else if volume.VolumeSource.Ephemeral != nil {
HomeEphemeralStorageExist = true homeEphemeralStorageExist = true
} }
} else { } else {
HomeExist = false homeExist = false
HomeTempdirExist = false homeTempdirExist = false
HomeEphemeralStorageExist = false homeEphemeralStorageExist = false
} }
} }
return HomeExist, HomeTempdirExist, HomeEphemeralStorageExist return homeExist, homeTempdirExist, homeEphemeralStorageExist
} }
func Test_validateStorageSize(t *testing.T) { func Test_validateStorageSize(t *testing.T) {

View File

@ -2,7 +2,7 @@ package plugins
const ( const (
configurationAsCodePlugin = "configuration-as-code:1625.v27444588cc3d" configurationAsCodePlugin = "configuration-as-code:1625.v27444588cc3d"
gitPlugin = "git:5.0.0" gitPlugin = "git:5.0.1"
jobDslPlugin = "job-dsl:1.83" jobDslPlugin = "job-dsl:1.83"
kubernetesPlugin = "kubernetes:3909.v1f2c633e8590" kubernetesPlugin = "kubernetes:3909.v1f2c633e8590"
kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:1.211.vc236a_f5a_2f3c" kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:1.211.vc236a_f5a_2f3c"

View File

@ -25,7 +25,7 @@ const e2e = "e2e"
var expectedBasePluginsList = []plugins.Plugin{ var expectedBasePluginsList = []plugins.Plugin{
plugins.Must(plugins.New("configuration-as-code:1625.v27444588cc3d")), plugins.Must(plugins.New("configuration-as-code:1625.v27444588cc3d")),
plugins.Must(plugins.New("git:5.0.0")), plugins.Must(plugins.New("git:5.0.1")),
plugins.Must(plugins.New("kubernetes:3909.v1f2c633e8590")), plugins.Must(plugins.New("kubernetes:3909.v1f2c633e8590")),
plugins.Must(plugins.New("kubernetes-credentials-provider:1.211.vc236a_f5a_2f3c")), plugins.Must(plugins.New("kubernetes-credentials-provider:1.211.vc236a_f5a_2f3c")),
plugins.Must(plugins.New("job-dsl:1.83")), plugins.Must(plugins.New("job-dsl:1.83")),