mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	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.
This commit is contained in:
		@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user