You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-11-06 09:09:19 +02:00
Add support for volume mounts (#4673)
* Add support for volume mounts * Adatpt unit test to include VolumeMounts Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com> * Only accept volumeMounts with the name volume --------- Co-authored-by: Johannes Dillmann <j.dillmann@sap.com> Co-authored-by: Philipp Stehle <philipp.stehle@sap.com> Co-authored-by: Anil Keshav <anil.keshav@sap.com>
This commit is contained in:
@@ -13,6 +13,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const SupportedVolumeName = "volume"
|
||||
|
||||
// StepData defines the metadata for a step, like step descriptions, parameters, ...
|
||||
type StepData struct {
|
||||
Metadata StepMetadata `json:"metadata"`
|
||||
@@ -105,25 +107,25 @@ type StepOutputs struct {
|
||||
// Container defines an execution container
|
||||
type Container struct {
|
||||
//ToDo: check dockerOptions, dockerVolumeBind, containerPortMappings, sidecarOptions, sidecarVolumeBind
|
||||
Command []string `json:"command"`
|
||||
EnvVars []EnvVar `json:"env"`
|
||||
Image string `json:"image"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy"`
|
||||
Name string `json:"name"`
|
||||
ReadyCommand string `json:"readyCommand"`
|
||||
Shell string `json:"shell"`
|
||||
WorkingDir string `json:"workingDir"`
|
||||
Conditions []Condition `json:"conditions,omitempty"`
|
||||
Options []Option `json:"options,omitempty"`
|
||||
//VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
Command []string `json:"command"`
|
||||
EnvVars []EnvVar `json:"env"`
|
||||
Image string `json:"image"`
|
||||
ImagePullPolicy string `json:"imagePullPolicy"`
|
||||
Name string `json:"name"`
|
||||
ReadyCommand string `json:"readyCommand"`
|
||||
Shell string `json:"shell"`
|
||||
WorkingDir string `json:"workingDir"`
|
||||
Conditions []Condition `json:"conditions,omitempty"`
|
||||
Options []Option `json:"options,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
}
|
||||
|
||||
// ToDo: Add the missing Volumes part to enable the volume mount completely
|
||||
// VolumeMount defines a mount path
|
||||
// type VolumeMount struct {
|
||||
// MountPath string `json:"mountPath"`
|
||||
// Name string `json:"name"`
|
||||
//}
|
||||
type VolumeMount struct {
|
||||
Name string `json:"name"`
|
||||
MountPath string `json:"mountPath"`
|
||||
}
|
||||
|
||||
// Option defines an docker option
|
||||
type Option struct {
|
||||
@@ -385,7 +387,7 @@ func (container *Container) commonConfiguration(keyPrefix string, config *map[st
|
||||
}
|
||||
putStringIfNotEmpty(*config, keyPrefix+"Workspace", container.WorkingDir)
|
||||
putSliceIfNotEmpty(*config, keyPrefix+"Options", OptionsAsStringSlice(container.Options))
|
||||
//putSliceIfNotEmpty(*config, keyPrefix+"VolumeBind", volumeMountsAsStringSlice(container.VolumeMounts))
|
||||
putSliceIfNotEmpty(*config, keyPrefix+"VolumeBind", volumeMountsAsStringSlice(container.VolumeMounts))
|
||||
|
||||
}
|
||||
|
||||
@@ -518,11 +520,14 @@ func ResolveMetadata(gitHubTokens map[string]string, metaDataResolver func() map
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
//ToDo: Enable this when the Volumes part is also implemented
|
||||
//func volumeMountsAsStringSlice(volumeMounts []VolumeMount) []string {
|
||||
// e := []string{}
|
||||
// for _, v := range volumeMounts {
|
||||
// e = append(e, fmt.Sprintf("%v:%v", v.Name, v.MountPath))
|
||||
// }
|
||||
// return e
|
||||
//}
|
||||
func volumeMountsAsStringSlice(volumeMounts []VolumeMount) []string {
|
||||
e := []string{}
|
||||
for _, v := range volumeMounts {
|
||||
if v.Name != SupportedVolumeName {
|
||||
log.Entry().Warningf("Unsupported volume name: %q, only %q is supported", v.Name, SupportedVolumeName)
|
||||
continue
|
||||
}
|
||||
e = append(e, fmt.Sprintf("%v:%v", v.Name, v.MountPath))
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -397,10 +397,10 @@ func TestGetContextDefaults(t *testing.T) {
|
||||
{Name: "opt1", Value: "optValue1"},
|
||||
{Name: "opt2", Value: "optValue2"},
|
||||
},
|
||||
//VolumeMounts: []VolumeMount{
|
||||
// {MountPath: "mp1", Name: "mn1"},
|
||||
// {MountPath: "mp2", Name: "mn2"},
|
||||
//},
|
||||
VolumeMounts: []VolumeMount{
|
||||
{MountPath: "mp1", Name: "volume"},
|
||||
{MountPath: "mp2", Name: "mn2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Sidecars: []Container{
|
||||
@@ -419,10 +419,10 @@ func TestGetContextDefaults(t *testing.T) {
|
||||
{Name: "opt3", Value: "optValue3"},
|
||||
{Name: "opt4", Value: "optValue4"},
|
||||
},
|
||||
//VolumeMounts: []VolumeMount{
|
||||
// {MountPath: "mp3", Name: "mn3"},
|
||||
// {MountPath: "mp4", Name: "mn4"},
|
||||
//},
|
||||
VolumeMounts: []VolumeMount{
|
||||
{MountPath: "mp3", Name: "mn3"},
|
||||
{MountPath: "mp4", Name: "volume"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -451,7 +451,7 @@ func TestGetContextDefaults(t *testing.T) {
|
||||
assert.Equal(t, true, d.Defaults[0].Steps["testStep"]["dockerPullImage"], "dockerPullImage default not available")
|
||||
assert.Equal(t, "/test/dir", d.Defaults[0].Steps["testStep"]["dockerWorkspace"], "dockerWorkspace default not available")
|
||||
assert.Equal(t, []interface{}{"opt1 optValue1", "opt2 optValue2"}, d.Defaults[0].Steps["testStep"]["dockerOptions"], "dockerOptions default not available")
|
||||
//assert.Equal(t, []interface{}{"mn1:mp1", "mn2:mp2"}, d.Defaults[0].Steps["testStep"]["dockerVolumeBind"], "dockerVolumeBind default not available")
|
||||
assert.Equal(t, []interface{}{"volume:mp1"}, d.Defaults[0].Steps["testStep"]["dockerVolumeBind"], "dockerVolumeBind default not available")
|
||||
|
||||
assert.Equal(t, "/sidecar/command", d.Defaults[0].Steps["testStep"]["sidecarCommand"], "sidecarCommand default not available")
|
||||
assert.Equal(t, map[string]interface{}{"env3": "val3", "env4": "val4"}, d.Defaults[0].Steps["testStep"]["sidecarEnvVars"], "sidecarEnvVars default not available")
|
||||
@@ -461,7 +461,7 @@ func TestGetContextDefaults(t *testing.T) {
|
||||
assert.Equal(t, "/sidecar/command", d.Defaults[0].Steps["testStep"]["sidecarReadyCommand"], "sidecarReadyCommand default not available")
|
||||
assert.Equal(t, "/sidecar/dir", d.Defaults[0].Steps["testStep"]["sidecarWorkspace"], "sidecarWorkspace default not available")
|
||||
assert.Equal(t, []interface{}{"opt3 optValue3", "opt4 optValue4"}, d.Defaults[0].Steps["testStep"]["sidecarOptions"], "sidecarOptions default not available")
|
||||
//assert.Equal(t, []interface{}{"mn3:mp3", "mn4:mp4"}, d.Defaults[0].Steps["testStep"]["sidecarVolumeBind"], "sidecarVolumeBind default not available")
|
||||
assert.Equal(t, []interface{}{"volume:mp4"}, d.Defaults[0].Steps["testStep"]["sidecarVolumeBind"], "sidecarVolumeBind default not available")
|
||||
})
|
||||
|
||||
t.Run("Container conditions", func(t *testing.T) {
|
||||
|
||||
@@ -183,6 +183,7 @@ void call(Map parameters = [:], body) {
|
||||
}
|
||||
|
||||
def securityContext = securityContextFromOptions(config.dockerOptions)
|
||||
def containerMountPath = containerMountPathFromVolumeBind(config.dockerVolumeBind)
|
||||
if (env.POD_NAME && isContainerDefined(config)) {
|
||||
container(getContainerDefined(config)) {
|
||||
withEnv(dockerEnvVars) {
|
||||
@@ -208,6 +209,7 @@ void call(Map parameters = [:], body) {
|
||||
stashContent: config.stashContent,
|
||||
stashNoDefaultExcludes: config.stashNoDefaultExcludes,
|
||||
securityContext: securityContext,
|
||||
containerMountPath: containerMountPath,
|
||||
]
|
||||
|
||||
if (config.sidecarImage) {
|
||||
@@ -379,6 +381,17 @@ def securityContextFromOptions(dockerOptions) {
|
||||
return securityContext
|
||||
}
|
||||
|
||||
/*
|
||||
* Picks the first volumeBind option and translates it into containerMountPath, currently only one fix volume is supported
|
||||
*/
|
||||
@NonCPS
|
||||
def containerMountPathFromVolumeBind(dockerVolumeBind) {
|
||||
if (dockerVolumeBind) {
|
||||
return dockerVolumeBind[0].split(":")[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
boolean isContainerDefined(config) {
|
||||
Map containerMap = ContainerMap.instance.getMap()
|
||||
|
||||
|
||||
@@ -582,9 +582,12 @@ private List getContainerList(config) {
|
||||
command : []
|
||||
]
|
||||
def resources = getResources(sideCarContainerName, config)
|
||||
if(resources) {
|
||||
if (resources) {
|
||||
containerSpec.resources = resources
|
||||
}
|
||||
if (config.containerMountPath) {
|
||||
containerSpec.volumeMounts = [[name: "volume", mountPath: config.containerMountPath]]
|
||||
}
|
||||
result.push(containerSpec)
|
||||
}
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user