initial ephemeral home implementation
This commit is contained in:
parent
a690c7cc6c
commit
2e8fd0ea7a
|
|
@ -343,6 +343,11 @@ type JenkinsMaster struct {
|
||||||
// +optional
|
// +optional
|
||||||
Volumes []corev1.Volume `json:"volumes,omitempty"`
|
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.
|
// If specified, the pod's tolerations.
|
||||||
// +optional
|
// +optional
|
||||||
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
||||||
|
|
@ -387,6 +392,14 @@ type JenkinsMaster struct {
|
||||||
HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"`
|
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
|
// Service defines Kubernetes service attributes
|
||||||
type Service struct {
|
type Service struct {
|
||||||
// Annotations is an unstructured key value map stored with a resource that may be
|
// Annotations is an unstructured key value map stored with a resource that may be
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -88,18 +89,67 @@ func getJenkinsHomePath(jenkins *v1alpha2.Jenkins) string {
|
||||||
return defaultJenkinsHomePath
|
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
|
// GetJenkinsMasterPodBaseVolumes returns Jenkins master pod volumes required by operator
|
||||||
func GetJenkinsMasterPodBaseVolumes(jenkins *v1alpha2.Jenkins) []corev1.Volume {
|
func GetJenkinsMasterPodBaseVolumes(jenkins *v1alpha2.Jenkins) []corev1.Volume {
|
||||||
configMapVolumeSourceDefaultMode := corev1.ConfigMapVolumeSourceDefaultMode
|
configMapVolumeSourceDefaultMode := corev1.ConfigMapVolumeSourceDefaultMode
|
||||||
secretVolumeSourceDefaultMode := corev1.SecretVolumeSourceDefaultMode
|
secretVolumeSourceDefaultMode := corev1.SecretVolumeSourceDefaultMode
|
||||||
var scriptsVolumeDefaultMode int32 = 0777
|
var scriptsVolumeDefaultMode int32 = 0777
|
||||||
volumes := []corev1.Volume{
|
volumes := []corev1.Volume{
|
||||||
{
|
getJenkinsHomeStorageSettings(jenkins),
|
||||||
Name: JenkinsHomeVolumeName,
|
|
||||||
VolumeSource: corev1.VolumeSource{
|
|
||||||
EmptyDir: &corev1.EmptyDirVolumeSource{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: jenkinsScriptsVolumeName,
|
Name: jenkinsScriptsVolumeName,
|
||||||
VolumeSource: corev1.VolumeSource{
|
VolumeSource: corev1.VolumeSource{
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -144,6 +143,42 @@ func TestGetJenkinsMasterPodBaseVolumes(t *testing.T) {
|
||||||
assert.True(t, groovyExists)
|
assert.True(t, groovyExists)
|
||||||
assert.True(t, cascExists)
|
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) {
|
func checkSecretVolumesPresence(jenkins *v1alpha2.Jenkins) (groovyExists bool, cascExists bool) {
|
||||||
|
|
@ -156,3 +191,55 @@ 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) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue