mirror of https://github.com/k3s-io/k3s
validation: improve ProjectedVolume validation errors
* only report "may not specify more than 1 volume type" once * fix incorrectly reported field paths * continue to traverse into projections to report further errors.pull/8/head
parent
500893cf99
commit
a5d2ca8c55
|
@ -984,74 +984,64 @@ func validateProjectionSources(projection *core.ProjectedVolumeSource, projectio
|
|||
allErrs := field.ErrorList{}
|
||||
allPaths := sets.String{}
|
||||
|
||||
for _, source := range projection.Sources {
|
||||
for i, source := range projection.Sources {
|
||||
numSources := 0
|
||||
if source.Secret != nil {
|
||||
if numSources > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("secret"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numSources++
|
||||
if len(source.Secret.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
|
||||
}
|
||||
itemsPath := fldPath.Child("items")
|
||||
for i, kp := range source.Secret.Items {
|
||||
itemPath := itemsPath.Index(i)
|
||||
allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
|
||||
if len(kp.Path) > 0 {
|
||||
curPath := kp.Path
|
||||
if !allPaths.Has(curPath) {
|
||||
allPaths.Insert(curPath)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, source.Secret.Name, "conflicting duplicate paths"))
|
||||
}
|
||||
srcPath := fldPath.Child("sources").Index(i)
|
||||
if projPath := srcPath.Child("secret"); source.Secret != nil {
|
||||
numSources++
|
||||
if len(source.Secret.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(projPath.Child("name"), ""))
|
||||
}
|
||||
itemsPath := projPath.Child("items")
|
||||
for i, kp := range source.Secret.Items {
|
||||
itemPath := itemsPath.Index(i)
|
||||
allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
|
||||
if len(kp.Path) > 0 {
|
||||
curPath := kp.Path
|
||||
if !allPaths.Has(curPath) {
|
||||
allPaths.Insert(curPath)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, source.Secret.Name, "conflicting duplicate paths"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if source.ConfigMap != nil {
|
||||
if numSources > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("configMap"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numSources++
|
||||
if len(source.ConfigMap.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
|
||||
}
|
||||
itemsPath := fldPath.Child("items")
|
||||
for i, kp := range source.ConfigMap.Items {
|
||||
itemPath := itemsPath.Index(i)
|
||||
allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
|
||||
if len(kp.Path) > 0 {
|
||||
curPath := kp.Path
|
||||
if !allPaths.Has(curPath) {
|
||||
allPaths.Insert(curPath)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, source.ConfigMap.Name, "conflicting duplicate paths"))
|
||||
}
|
||||
|
||||
if projPath := srcPath.Child("configMap"); source.ConfigMap != nil {
|
||||
numSources++
|
||||
if len(source.ConfigMap.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(projPath.Child("name"), ""))
|
||||
}
|
||||
itemsPath := projPath.Child("items")
|
||||
for i, kp := range source.ConfigMap.Items {
|
||||
itemPath := itemsPath.Index(i)
|
||||
allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
|
||||
if len(kp.Path) > 0 {
|
||||
curPath := kp.Path
|
||||
if !allPaths.Has(curPath) {
|
||||
allPaths.Insert(curPath)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, source.ConfigMap.Name, "conflicting duplicate paths"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if source.DownwardAPI != nil {
|
||||
if numSources > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("downwardAPI"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numSources++
|
||||
for _, file := range source.DownwardAPI.Items {
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, fldPath.Child("downwardAPI"))...)
|
||||
if len(file.Path) > 0 {
|
||||
curPath := file.Path
|
||||
if !allPaths.Has(curPath) {
|
||||
allPaths.Insert(curPath)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, curPath, "conflicting duplicate paths"))
|
||||
}
|
||||
|
||||
if projPath := srcPath.Child("downwardAPI"); source.DownwardAPI != nil {
|
||||
numSources++
|
||||
for _, file := range source.DownwardAPI.Items {
|
||||
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, projPath)...)
|
||||
if len(file.Path) > 0 {
|
||||
curPath := file.Path
|
||||
if !allPaths.Has(curPath) {
|
||||
allPaths.Insert(curPath)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, curPath, "conflicting duplicate paths"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if numSources > 1 {
|
||||
allErrs = append(allErrs, field.Forbidden(srcPath, "may not specify more than 1 volume type"))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
@ -3542,6 +3542,71 @@ func TestValidateVolumes(t *testing.T) {
|
|||
field: "scaleIO.system",
|
||||
}},
|
||||
},
|
||||
// ProjectedVolumeSource
|
||||
{
|
||||
name: "ProjectedVolumeSource more than one projection in a source",
|
||||
vol: core.Volume{
|
||||
Name: "projected-volume",
|
||||
VolumeSource: core.VolumeSource{
|
||||
Projected: &core.ProjectedVolumeSource{
|
||||
Sources: []core.VolumeProjection{
|
||||
{
|
||||
Secret: &core.SecretProjection{
|
||||
LocalObjectReference: core.LocalObjectReference{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Secret: &core.SecretProjection{
|
||||
LocalObjectReference: core.LocalObjectReference{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
DownwardAPI: &core.DownwardAPIProjection{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
errs: []verr{{
|
||||
etype: field.ErrorTypeForbidden,
|
||||
field: "projected.sources[1]",
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "ProjectedVolumeSource more than one projection in a source",
|
||||
vol: core.Volume{
|
||||
Name: "projected-volume",
|
||||
VolumeSource: core.VolumeSource{
|
||||
Projected: &core.ProjectedVolumeSource{
|
||||
Sources: []core.VolumeProjection{
|
||||
{
|
||||
Secret: &core.SecretProjection{},
|
||||
},
|
||||
{
|
||||
Secret: &core.SecretProjection{},
|
||||
DownwardAPI: &core.DownwardAPIProjection{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
errs: []verr{
|
||||
{
|
||||
etype: field.ErrorTypeRequired,
|
||||
field: "projected.sources[0].secret.name",
|
||||
},
|
||||
{
|
||||
etype: field.ErrorTypeRequired,
|
||||
field: "projected.sources[1].secret.name",
|
||||
},
|
||||
{
|
||||
etype: field.ErrorTypeForbidden,
|
||||
field: "projected.sources[1]",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
Loading…
Reference in New Issue