initial ephemeral home implementation

This commit is contained in:
brokenpip3 2023-05-05 16:09:01 +02:00
parent a690c7cc6c
commit 2e8fd0ea7a
No known key found for this signature in database
GPG Key ID: 1D9BDC803797B4B6
3 changed files with 157 additions and 7 deletions

View File

@ -343,6 +343,11 @@ type JenkinsMaster struct {
// +optional
Volumes []corev1.Volume `json:"volumes,omitempty"`
// Storage settings for the jenkins home directory
// Can be tempDir or ephemeral
// +optional
StorageSettings StorageSettings `json:"storage,omitempty"`
// If specified, the pod's tolerations.
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
@ -387,6 +392,14 @@ type JenkinsMaster struct {
HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"`
}
// StorageSettings defines Jenkins master pod persistance attributes.
type StorageSettings struct {
UseTempDir bool `json:"useTempDir"`
UseEphemeralStorage bool `json:"useEphemeralStorage"`
StorageClassName string `json:"storageClassName"`
StorageRequest string `json:"storageRequest"`
}
// Service defines Kubernetes service attributes
type Service struct {
// Annotations is an unstructured key value map stored with a resource that may be

View File

@ -8,6 +8,7 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -88,18 +89,67 @@ func getJenkinsHomePath(jenkins *v1alpha2.Jenkins) string {
return defaultJenkinsHomePath
}
func validateStorageSize(storageSize string) bool {
if strings.TrimSpace(storageSize) == "" {
return false
}
_, err := resource.ParseQuantity(storageSize)
if err != nil {
return false
}
return true
}
// get Jenkins home storage settings from the CRD
func getJenkinsHomeStorageSettings(jenkins *v1alpha2.Jenkins) corev1.Volume {
JenkinsHomeVolume := corev1.Volume{}
emptyDirVol := corev1.Volume{
Name: JenkinsHomeVolumeName,
VolumeSource: corev1.VolumeSource{
// Create empty dir for Jenkins home
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
}
if jenkins.Spec.Master.StorageSettings.UseEphemeralStorage {
if !validateStorageSize(jenkins.Spec.Master.StorageSettings.StorageRequest) {
fmt.Println("Invalid storage size %s, falling back to empty dir" + jenkins.Spec.Master.StorageSettings.StorageRequest)
JenkinsHomeVolume = emptyDirVol
return JenkinsHomeVolume
}
JenkinsHomeVolume = corev1.Volume{
Name: JenkinsHomeVolumeName,
VolumeSource: corev1.VolumeSource{
// Create ephemeral storage for Jenkins home
Ephemeral: &corev1.EphemeralVolumeSource{
VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{
Spec: corev1.PersistentVolumeClaimSpec{
StorageClassName: &jenkins.Spec.Master.StorageSettings.StorageClassName,
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse(jenkins.Spec.Master.StorageSettings.StorageRequest),
},
},
},
},
},
},
}
} else {
JenkinsHomeVolume = emptyDirVol
}
return JenkinsHomeVolume
}
// GetJenkinsMasterPodBaseVolumes returns Jenkins master pod volumes required by operator
func GetJenkinsMasterPodBaseVolumes(jenkins *v1alpha2.Jenkins) []corev1.Volume {
configMapVolumeSourceDefaultMode := corev1.ConfigMapVolumeSourceDefaultMode
secretVolumeSourceDefaultMode := corev1.SecretVolumeSourceDefaultMode
var scriptsVolumeDefaultMode int32 = 0777
volumes := []corev1.Volume{
{
Name: JenkinsHomeVolumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
getJenkinsHomeStorageSettings(jenkins),
{
Name: jenkinsScriptsVolumeName,
VolumeSource: corev1.VolumeSource{

View File

@ -4,7 +4,6 @@ import (
"testing"
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
"github.com/stretchr/testify/assert"
)
@ -144,6 +143,42 @@ func TestGetJenkinsMasterPodBaseVolumes(t *testing.T) {
assert.True(t, groovyExists)
assert.True(t, cascExists)
})
t.Run("home volume is present and is Tempdir", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
StorageSettings: v1alpha2.StorageSettings{
UseTempDir: true,
},
},
},
}
HomeExist, HomeTempdirExist, HomeEphemeralStorageExist := checkHomeVolumesPresence(jenkins)
assert.True(t, HomeExist)
assert.True(t, HomeTempdirExist)
assert.False(t, HomeEphemeralStorageExist)
})
t.Run("home volume is present and it's ephemeral", func(t *testing.T) {
jenkins := &v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
StorageSettings: v1alpha2.StorageSettings{
UseEphemeralStorage: true,
StorageClassName: "",
StorageRequest: "1Gi",
},
},
},
}
HomeExist, HomeTempdirExist, HomeEphemeralStorageExist := checkHomeVolumesPresence(jenkins)
assert.True(t, HomeExist)
assert.False(t, HomeTempdirExist)
assert.True(t, HomeEphemeralStorageExist)
})
}
func checkSecretVolumesPresence(jenkins *v1alpha2.Jenkins) (groovyExists bool, cascExists bool) {
@ -156,3 +191,55 @@ func checkSecretVolumesPresence(jenkins *v1alpha2.Jenkins) (groovyExists bool, c
}
return groovyExists, cascExists
}
func checkHomeVolumesPresence(jenkins *v1alpha2.Jenkins) (HomeExist bool, HomeTempdirExist bool, HomeEphemeralStorageExist bool) {
for _, volume := range GetJenkinsMasterPodBaseVolumes(jenkins) {
if volume.Name == ("jenkins-home") {
HomeExist = true
// check if the volume is an emptyDir
if volume.VolumeSource.EmptyDir != nil {
HomeTempdirExist = true
} else if volume.VolumeSource.Ephemeral != nil {
HomeEphemeralStorageExist = true
}
} else {
HomeExist = false
HomeTempdirExist = false
HomeEphemeralStorageExist = false
}
}
return HomeExist, HomeTempdirExist, HomeEphemeralStorageExist
}
func Test_validateStorageSize(t *testing.T) {
type args struct {
storageSize string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "1Gi",
args: args{
storageSize: "1Gi",
},
want: true,
},
{
name: "1Gi1",
args: args{
storageSize: "1Gi1",
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := validateStorageSize(tt.args.storageSize); got != tt.want {
t.Errorf("validateStorageSize() = %v, want %v", got, tt.want)
}
})
}
}