mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-20 09:05:26 +00:00
extend pod warning rules for overlapping paths
This commit is contained in:
parent
30c325a3dc
commit
205a026bb1
@ -19,6 +19,8 @@ package pod
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -170,16 +172,11 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
overlappingPathInContainers := warningsForOverlappingVirtualPaths(podSpec)
|
overlappingPathInContainers := warningsForOverlappingVirtualPaths(podSpec.Volumes)
|
||||||
if len(overlappingPathInContainers) > 0 {
|
if len(overlappingPathInContainers) > 0 {
|
||||||
warnings = append(warnings, overlappingPathInContainers...)
|
warnings = append(warnings, overlappingPathInContainers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
overlappingPathInInitContainers := warningsForOverlappingVirtualPaths(podSpec)
|
|
||||||
if len(overlappingPathInInitContainers) > 0 {
|
|
||||||
warnings = append(warnings, overlappingPathInInitContainers...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// duplicate hostAliases (#91670, #58477)
|
// duplicate hostAliases (#91670, #58477)
|
||||||
if len(podSpec.HostAliases) > 1 {
|
if len(podSpec.HostAliases) > 1 {
|
||||||
items := sets.New[string]()
|
items := sets.New[string]()
|
||||||
@ -368,76 +365,84 @@ func warningsForWeightedPodAffinityTerms(terms []api.WeightedPodAffinityTerm, fi
|
|||||||
return warnings
|
return warnings
|
||||||
}
|
}
|
||||||
|
|
||||||
func warningsForOverlappingVirtualPaths(podSpec *api.PodSpec) []string {
|
// warningsForOverlappingVirtualPaths validates that there are no overlapping paths in single ConfigMapVolume, SecretVolume, DownwardAPIVolume and ProjectedVolume.
|
||||||
|
// A volume can try to load different keys to the same path which will result in overwriting of the value from the latest registered key
|
||||||
|
// Another possible scenario is when one of the path contains the other key path. Example:
|
||||||
|
// configMap:
|
||||||
|
//
|
||||||
|
// name: myconfig
|
||||||
|
// items:
|
||||||
|
// - key: key1
|
||||||
|
// path: path
|
||||||
|
// - key: key2
|
||||||
|
// path: path/path2
|
||||||
|
//
|
||||||
|
// In such cases we either get `is directory` or 'file exists' error message.
|
||||||
|
func warningsForOverlappingVirtualPaths(volumes []api.Volume) []string {
|
||||||
warnings := make([]string, 0)
|
warnings := make([]string, 0)
|
||||||
for _, v := range podSpec.Volumes {
|
|
||||||
|
for _, v := range volumes {
|
||||||
if v.ConfigMap != nil && v.ConfigMap.Items != nil {
|
if v.ConfigMap != nil && v.ConfigMap.Items != nil {
|
||||||
a := sets.NewString()
|
w := checkVolumeMappingForOverlap(extractPaths(v.ConfigMap.Items), fmt.Sprintf("volume %q (ConfigMap %q): overlapping path", v.Name, v.ConfigMap.Name))
|
||||||
for _, item := range v.ConfigMap.Items {
|
if len(w) > 0 {
|
||||||
if a.Has(item.Path) {
|
warnings = append(warnings, w...)
|
||||||
warnings = append(warnings, fmt.Sprintf("config map: %q - conflicting duplicate paths", v.ConfigMap.Name))
|
|
||||||
}
|
|
||||||
a.Insert(item.Path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Secret != nil && v.Secret.Items != nil {
|
if v.Secret != nil && v.Secret.Items != nil {
|
||||||
a := sets.NewString()
|
w := checkVolumeMappingForOverlap(extractPaths(v.Secret.Items), fmt.Sprintf("volume %q (Secret %q): overlapping path", v.Name, v.Secret.SecretName))
|
||||||
for _, item := range v.Secret.Items {
|
if len(w) > 0 {
|
||||||
if a.Has(item.Path) {
|
warnings = append(warnings, w...)
|
||||||
warnings = append(warnings, fmt.Sprintf("secret: %q - conflicting duplicate paths", v.Secret.SecretName))
|
|
||||||
}
|
|
||||||
a.Insert(item.Path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.DownwardAPI != nil && v.DownwardAPI.Items != nil {
|
if v.DownwardAPI != nil && v.DownwardAPI.Items != nil {
|
||||||
a := sets.NewString()
|
w := checkVolumeMappingForOverlap(extractPathsDownwardAPI(v.DownwardAPI.Items), fmt.Sprintf("volume %q (DownwardAPI): overlapping path", v.Name))
|
||||||
for _, item := range v.DownwardAPI.Items {
|
if len(w) > 0 {
|
||||||
if a.Has(item.Path) {
|
warnings = append(warnings, w...)
|
||||||
warnings = append(warnings, "downward api - conflicting duplicate paths")
|
|
||||||
}
|
|
||||||
a.Insert(item.Path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Projected != nil {
|
if v.Projected != nil {
|
||||||
a := sets.NewString()
|
var sourcePaths, allPaths []string
|
||||||
for _, item := range v.Projected.Sources {
|
var errorMessage string
|
||||||
if item.ServiceAccountToken != nil {
|
|
||||||
a.Insert(item.ServiceAccountToken.Path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range v.Projected.Sources {
|
for _, source := range v.Projected.Sources {
|
||||||
if item.ConfigMap != nil && item.ConfigMap.Items != nil {
|
switch {
|
||||||
for _, item := range item.ConfigMap.Items {
|
case source.ConfigMap != nil && source.ConfigMap.Items != nil:
|
||||||
if a.Has(item.Path) {
|
sourcePaths = extractPaths(source.ConfigMap.Items)
|
||||||
warnings = append(warnings, fmt.Sprintf("projected volume: %q - conflicting duplicate paths", v.Name))
|
errorMessage = fmt.Sprintf("volume %q (Projected ConfigMap %q): overlapping path", v.Name, source.ConfigMap.Name)
|
||||||
}
|
case source.Secret != nil && source.Secret.Items != nil:
|
||||||
|
sourcePaths = extractPaths(source.Secret.Items)
|
||||||
|
errorMessage = fmt.Sprintf("volume %q (Projected Secret %q): overlapping path", v.Name, source.Secret.Name)
|
||||||
|
case source.DownwardAPI != nil && source.DownwardAPI.Items != nil:
|
||||||
|
sourcePaths = extractPathsDownwardAPI(source.DownwardAPI.Items)
|
||||||
|
errorMessage = fmt.Sprintf("volume %q (Projected DownwardAPI): overlapping path", v.Name)
|
||||||
|
case source.ServiceAccountToken != nil:
|
||||||
|
sourcePaths = []string{source.ServiceAccountToken.Path}
|
||||||
|
errorMessage = fmt.Sprintf("volume %q (Projected ServiceAccountToken): overlapping path", v.Name)
|
||||||
|
case source.ClusterTrustBundle != nil:
|
||||||
|
sourcePaths = []string{source.ClusterTrustBundle.Path}
|
||||||
|
if source.ClusterTrustBundle.Name != nil {
|
||||||
|
errorMessage = fmt.Sprintf("volume %q (Projected ClusterTrustBundle %q): overlapping path", v.Name, *source.ClusterTrustBundle.Name)
|
||||||
|
} else {
|
||||||
|
errorMessage = fmt.Sprintf("volume %q (Projected ClusterTrustBundle %q): overlapping path", v.Name, *source.ClusterTrustBundle.SignerName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.Secret != nil && item.Secret.Items != nil {
|
if len(sourcePaths) == 0 {
|
||||||
for _, item := range item.Secret.Items {
|
continue
|
||||||
if a.Has(item.Path) {
|
|
||||||
warnings = append(warnings, fmt.Sprintf("projected volume: %q - conflicting duplicate paths", v.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.DownwardAPI != nil && item.DownwardAPI.Items != nil {
|
warningsInSource := checkVolumeMappingForOverlap(sourcePaths, errorMessage)
|
||||||
for _, item := range item.DownwardAPI.Items {
|
if len(warningsInSource) > 0 {
|
||||||
if a.Has(item.Path) {
|
warnings = append(warnings, warningsInSource...)
|
||||||
warnings = append(warnings, fmt.Sprintf("projected volume: %q - conflicting duplicate paths", v.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.ClusterTrustBundle != nil {
|
allPaths = append(allPaths, sourcePaths...)
|
||||||
if a.Has(item.ClusterTrustBundle.Path) {
|
warningsInAllPaths := checkVolumeMappingForOverlap(allPaths, errorMessage)
|
||||||
warnings = append(warnings, fmt.Sprintf("projected volume: %q - conflicting duplicate paths", v.Name))
|
if len(warningsInAllPaths) > 0 {
|
||||||
}
|
warnings = append(warnings, warningsInAllPaths...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,3 +450,56 @@ func warningsForOverlappingVirtualPaths(podSpec *api.PodSpec) []string {
|
|||||||
}
|
}
|
||||||
return warnings
|
return warnings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractPaths(mapping []api.KeyToPath) []string {
|
||||||
|
result := make([]string, 0, len(mapping))
|
||||||
|
|
||||||
|
for _, v := range mapping {
|
||||||
|
result = append(result, v.Path)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractPathsDownwardAPI(mapping []api.DownwardAPIVolumeFile) []string {
|
||||||
|
result := make([]string, 0, len(mapping))
|
||||||
|
|
||||||
|
for _, v := range mapping {
|
||||||
|
result = append(result, v.Path)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkVolumeMappingForOverlap(paths []string, warningMessage string) []string {
|
||||||
|
pathSeparator := string(os.PathSeparator)
|
||||||
|
warnings := make([]string, 0)
|
||||||
|
uniquePaths := sets.New[string]()
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
normalizedPath := strings.TrimRight(path, pathSeparator)
|
||||||
|
if collision := checkForOverlap(uniquePaths, normalizedPath); collision != nil {
|
||||||
|
warnings = append(warnings, fmt.Sprintf("%s %q with %q", warningMessage, normalizedPath, *collision))
|
||||||
|
}
|
||||||
|
uniquePaths.Insert(normalizedPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkForOverlap(paths sets.Set[string], path string) *string {
|
||||||
|
pathSeparator := string(os.PathSeparator)
|
||||||
|
p := paths.UnsortedList()
|
||||||
|
sort.Strings(p)
|
||||||
|
|
||||||
|
for _, item := range p {
|
||||||
|
switch {
|
||||||
|
case item == path:
|
||||||
|
return &item
|
||||||
|
case strings.HasPrefix(item+pathSeparator, path):
|
||||||
|
return &item
|
||||||
|
case strings.HasPrefix(path+pathSeparator, item):
|
||||||
|
return &item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -143,6 +143,7 @@ func TestWarnings(t *testing.T) {
|
|||||||
api.ResourceMemory: resource.MustParse("4m"),
|
api.ResourceMemory: resource.MustParse("4m"),
|
||||||
api.ResourceEphemeralStorage: resource.MustParse("4m"),
|
api.ResourceEphemeralStorage: resource.MustParse("4m"),
|
||||||
}
|
}
|
||||||
|
testName := "Test"
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
template *api.PodTemplateSpec
|
template *api.PodTemplateSpec
|
||||||
@ -240,6 +241,7 @@ func TestWarnings(t *testing.T) {
|
|||||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
|
Name: "Test",
|
||||||
VolumeSource: api.VolumeSource{
|
VolumeSource: api.VolumeSource{
|
||||||
ConfigMap: &api.ConfigMapVolumeSource{
|
ConfigMap: &api.ConfigMapVolumeSource{
|
||||||
LocalObjectReference: api.LocalObjectReference{Name: "foo"},
|
LocalObjectReference: api.LocalObjectReference{Name: "foo"},
|
||||||
@ -253,7 +255,51 @@ func TestWarnings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"config map: \"foo\" - conflicting duplicate paths",
|
"volume \"Test\" (ConfigMap \"foo\"): overlapping path \"test\" with \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in a configmap volume - try to mount dir path into a file",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "Test",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
ConfigMap: &api.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "foo"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{Key: "foo", Path: "test"},
|
||||||
|
{Key: "bar", Path: "test/app"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"Test\" (ConfigMap \"foo\"): overlapping path \"test/app\" with \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in a configmap volume - try to mount file into a dir path",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "Test",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
ConfigMap: &api.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "foo"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{Key: "bar", Path: "test/app"},
|
||||||
|
{Key: "foo", Path: "test"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"Test\" (ConfigMap \"foo\"): overlapping path \"test\" with \"test/app\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -261,6 +307,7 @@ func TestWarnings(t *testing.T) {
|
|||||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
|
Name: "Test",
|
||||||
VolumeSource: api.VolumeSource{
|
VolumeSource: api.VolumeSource{
|
||||||
Secret: &api.SecretVolumeSource{
|
Secret: &api.SecretVolumeSource{
|
||||||
SecretName: "foo",
|
SecretName: "foo",
|
||||||
@ -274,7 +321,7 @@ func TestWarnings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"secret: \"foo\" - conflicting duplicate paths",
|
"volume \"Test\" (Secret \"foo\"): overlapping path \"test\" with \"test\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -282,11 +329,12 @@ func TestWarnings(t *testing.T) {
|
|||||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
|
Name: "Test",
|
||||||
VolumeSource: api.VolumeSource{
|
VolumeSource: api.VolumeSource{
|
||||||
DownwardAPI: &api.DownwardAPIVolumeSource{
|
DownwardAPI: &api.DownwardAPIVolumeSource{
|
||||||
Items: []api.DownwardAPIVolumeFile{
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name\n"}, Path: "test"},
|
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name"}, Path: "test"},
|
||||||
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.labels\n"}, Path: "test"},
|
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.labels"}, Path: "test"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -294,11 +342,11 @@ func TestWarnings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"downward api - conflicting duplicate paths",
|
"volume \"Test\" (DownwardAPI): overlapping path \"test\" with \"test\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "overlapping paths in projected volume volume - service account and config",
|
name: "overlapping paths in projected volume - service account and config",
|
||||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
@ -307,6 +355,7 @@ func TestWarnings(t *testing.T) {
|
|||||||
Projected: &api.ProjectedVolumeSource{
|
Projected: &api.ProjectedVolumeSource{
|
||||||
Sources: []api.VolumeProjection{
|
Sources: []api.VolumeProjection{
|
||||||
{ConfigMap: &api.ConfigMapProjection{
|
{ConfigMap: &api.ConfigMapProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "Test"},
|
||||||
Items: []api.KeyToPath{
|
Items: []api.KeyToPath{
|
||||||
{Key: "foo", Path: "test"},
|
{Key: "foo", Path: "test"},
|
||||||
},
|
},
|
||||||
@ -321,11 +370,67 @@ func TestWarnings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"projected volume: \"foo\" - conflicting duplicate paths",
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "overlapping paths in projected volume volume - service account and secret",
|
name: "overlapping paths in projected volume volume - service account dir and config file",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{ConfigMap: &api.ConfigMapProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "Test"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{Key: "foo", Path: "test"},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "test/file",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test/file\" with \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in projected volume - service account file and config dir",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{ConfigMap: &api.ConfigMapProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "Test"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{Key: "foo", Path: "test/file"},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "test",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test/file\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in projected volume - service account and secret",
|
||||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
@ -334,10 +439,12 @@ func TestWarnings(t *testing.T) {
|
|||||||
Projected: &api.ProjectedVolumeSource{
|
Projected: &api.ProjectedVolumeSource{
|
||||||
Sources: []api.VolumeProjection{
|
Sources: []api.VolumeProjection{
|
||||||
{Secret: &api.SecretProjection{
|
{Secret: &api.SecretProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "Test"},
|
||||||
Items: []api.KeyToPath{
|
Items: []api.KeyToPath{
|
||||||
{Key: "foo", Path: "test"},
|
{Key: "foo", Path: "test"},
|
||||||
},
|
},
|
||||||
}},
|
},
|
||||||
|
},
|
||||||
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
Path: "test",
|
Path: "test",
|
||||||
}},
|
}},
|
||||||
@ -348,11 +455,11 @@ func TestWarnings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"projected volume: \"foo\" - conflicting duplicate paths",
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "overlapping paths in projected volume volume - service account and downward api",
|
name: "overlapping paths in projected volume - service account and downward api",
|
||||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
@ -362,7 +469,7 @@ func TestWarnings(t *testing.T) {
|
|||||||
Sources: []api.VolumeProjection{
|
Sources: []api.VolumeProjection{
|
||||||
{DownwardAPI: &api.DownwardAPIProjection{
|
{DownwardAPI: &api.DownwardAPIProjection{
|
||||||
Items: []api.DownwardAPIVolumeFile{
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name\n"}, Path: "test"},
|
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name"}, Path: "test"},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
@ -375,11 +482,11 @@ func TestWarnings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"projected volume: \"foo\" - conflicting duplicate paths",
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "overlapping paths in projected volume volume - service account and cluster trust bundle",
|
name: "overlapping paths in projected volume - service account and cluster trust bundle",
|
||||||
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
@ -388,7 +495,7 @@ func TestWarnings(t *testing.T) {
|
|||||||
Projected: &api.ProjectedVolumeSource{
|
Projected: &api.ProjectedVolumeSource{
|
||||||
Sources: []api.VolumeProjection{
|
Sources: []api.VolumeProjection{
|
||||||
{ClusterTrustBundle: &api.ClusterTrustBundleProjection{
|
{ClusterTrustBundle: &api.ClusterTrustBundleProjection{
|
||||||
Path: "test",
|
Name: &testName, Path: "test",
|
||||||
}},
|
}},
|
||||||
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
Path: "test",
|
Path: "test",
|
||||||
@ -400,7 +507,178 @@ func TestWarnings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"projected volume: \"foo\" - conflicting duplicate paths",
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in projected volume - service account and cluster trust bundle with signer name",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{ClusterTrustBundle: &api.ClusterTrustBundleProjection{
|
||||||
|
SignerName: &testName, Path: "test",
|
||||||
|
}},
|
||||||
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "test",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in projected volume - secret and config map",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{Secret: &api.SecretProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "TestSecret"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "mykey",
|
||||||
|
Path: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
ConfigMap: &api.ConfigMapProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "TestConfigMap"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "mykey",
|
||||||
|
Path: "test/test1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"foo\" (Projected ConfigMap \"TestConfigMap\"): overlapping path \"test/test1\" with \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in projected volume - config map and downward api",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{Secret: &api.SecretProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "TestSecret"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "mykey",
|
||||||
|
Path: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{
|
||||||
|
DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name"}, Path: "test/test2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"foo\" (Projected DownwardAPI): overlapping path \"test/test2\" with \"test\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in projected volume - downward api and downward api",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{
|
||||||
|
DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name"}, Path: "test/test2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ClusterTrustBundle: &api.ClusterTrustBundleProjection{
|
||||||
|
Name: &testName, Path: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"foo\" (Projected ClusterTrustBundle \"Test\"): overlapping path \"test\" with \"test/test2\"",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overlapping paths in projected volume - multiple sources",
|
||||||
|
template: &api.PodTemplateSpec{Spec: api.PodSpec{
|
||||||
|
Volumes: []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{ClusterTrustBundle: &api.ClusterTrustBundleProjection{
|
||||||
|
SignerName: &testName, Path: "test/test",
|
||||||
|
}},
|
||||||
|
{DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{FieldRef: &api.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name"}, Path: "test"},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{Secret: &api.SecretProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{Name: "Test"},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{Key: "foo", Path: "test"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "test",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
expected: []string{
|
||||||
|
"volume \"foo\" (Projected DownwardAPI): overlapping path \"test\" with \"test/test\"",
|
||||||
|
"volume \"foo\" (Projected Secret \"Test\"): overlapping path \"test\" with \"test\"",
|
||||||
|
"volume \"foo\" (Projected Secret \"Test\"): overlapping path \"test\" with \"test/test\"",
|
||||||
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test/test\"",
|
||||||
|
"volume \"foo\" (Projected ServiceAccountToken): overlapping path \"test\" with \"test\"",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1351,3 +1629,36 @@ func TestTemplateOnlyWarnings(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckForOverLap(t *testing.T) {
|
||||||
|
testCase := map[string]struct {
|
||||||
|
checkPaths []string
|
||||||
|
path string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
"exact match": {
|
||||||
|
checkPaths: []string{"path/path1"},
|
||||||
|
path: "path/path1",
|
||||||
|
expected: "path/path1",
|
||||||
|
},
|
||||||
|
"between file and dir": {
|
||||||
|
checkPaths: []string{"path/path1"},
|
||||||
|
path: "path",
|
||||||
|
expected: "path/path1",
|
||||||
|
},
|
||||||
|
"between dir and file": {
|
||||||
|
checkPaths: []string{"path"},
|
||||||
|
path: "path/path1",
|
||||||
|
expected: "path",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range testCase {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
result := checkForOverlap(sets.New(tc.checkPaths...), tc.path)
|
||||||
|
if *result != tc.expected {
|
||||||
|
t.Errorf("expected %v, got %v", tc.expected, *result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user