mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 12:18:16 +00:00 
			
		
		
		
	Merge pull request #79176 from verb/debug-iterate-containers
Add helpers for iterating containers in a pod
This commit is contained in:
		@@ -26,6 +26,28 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/security/apparmor"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ContainerVisitor is called with each container spec, and returns true
 | 
			
		||||
// if visiting should continue.
 | 
			
		||||
type ContainerVisitor func(container *api.Container) (shouldContinue bool)
 | 
			
		||||
 | 
			
		||||
// VisitContainers invokes the visitor function with a pointer to the container
 | 
			
		||||
// spec of every container in the given pod spec. If visitor returns false,
 | 
			
		||||
// visiting is short-circuited. VisitContainers returns true if visiting completes,
 | 
			
		||||
// false if visiting was short-circuited.
 | 
			
		||||
func VisitContainers(podSpec *api.PodSpec, visitor ContainerVisitor) bool {
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		if !visitor(&podSpec.InitContainers[i]) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		if !visitor(&podSpec.Containers[i]) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Visitor is called with each object name, and returns true if visiting should continue
 | 
			
		||||
type Visitor func(name string) (shouldContinue bool)
 | 
			
		||||
 | 
			
		||||
@@ -39,16 +61,9 @@ func VisitPodSecretNames(pod *api.Pod, visitor Visitor) bool {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		if !visitContainerSecretNames(&pod.Spec.InitContainers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		if !visitContainerSecretNames(&pod.Spec.Containers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	VisitContainers(&pod.Spec, func(c *api.Container) bool {
 | 
			
		||||
		return visitContainerSecretNames(c, visitor)
 | 
			
		||||
	})
 | 
			
		||||
	var source *api.VolumeSource
 | 
			
		||||
	for i := range pod.Spec.Volumes {
 | 
			
		||||
		source = &pod.Spec.Volumes[i].VolumeSource
 | 
			
		||||
@@ -129,16 +144,9 @@ func visitContainerSecretNames(container *api.Container, visitor Visitor) bool {
 | 
			
		||||
// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
 | 
			
		||||
// Returns true if visiting completed, false if visiting was short-circuited.
 | 
			
		||||
func VisitPodConfigmapNames(pod *api.Pod, visitor Visitor) bool {
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		if !visitContainerConfigmapNames(&pod.Spec.InitContainers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		if !visitContainerConfigmapNames(&pod.Spec.Containers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	VisitContainers(&pod.Spec, func(c *api.Container) bool {
 | 
			
		||||
		return visitContainerConfigmapNames(c, visitor)
 | 
			
		||||
	})
 | 
			
		||||
	var source *api.VolumeSource
 | 
			
		||||
	for i := range pod.Spec.Volumes {
 | 
			
		||||
		source = &pod.Spec.Volumes[i].VolumeSource
 | 
			
		||||
@@ -331,30 +339,22 @@ func dropDisabledFields(
 | 
			
		||||
 | 
			
		||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) && !subpathInUse(oldPodSpec) {
 | 
			
		||||
		// drop subpath from the pod if the feature is disabled and the old spec did not specify subpaths
 | 
			
		||||
		for i := range podSpec.Containers {
 | 
			
		||||
			for j := range podSpec.Containers[i].VolumeMounts {
 | 
			
		||||
				podSpec.Containers[i].VolumeMounts[j].SubPath = ""
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for i := range podSpec.InitContainers {
 | 
			
		||||
			for j := range podSpec.InitContainers[i].VolumeMounts {
 | 
			
		||||
				podSpec.InitContainers[i].VolumeMounts[j].SubPath = ""
 | 
			
		||||
			}
 | 
			
		||||
		VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
			for i := range c.VolumeMounts {
 | 
			
		||||
				c.VolumeMounts[i].SubPath = ""
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) || !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpathEnvExpansion)) && !subpathExprInUse(oldPodSpec) {
 | 
			
		||||
		// drop subpath env expansion from the pod if either of the subpath features is disabled and the old spec did not specify subpath env expansion
 | 
			
		||||
		for i := range podSpec.Containers {
 | 
			
		||||
			for j := range podSpec.Containers[i].VolumeMounts {
 | 
			
		||||
				podSpec.Containers[i].VolumeMounts[j].SubPathExpr = ""
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for i := range podSpec.InitContainers {
 | 
			
		||||
			for j := range podSpec.InitContainers[i].VolumeMounts {
 | 
			
		||||
				podSpec.InitContainers[i].VolumeMounts[j].SubPathExpr = ""
 | 
			
		||||
			}
 | 
			
		||||
		VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
			for i := range c.VolumeMounts {
 | 
			
		||||
				c.VolumeMounts[i].SubPathExpr = ""
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dropDisabledVolumeDevicesFields(podSpec, oldPodSpec)
 | 
			
		||||
@@ -392,16 +392,12 @@ func dropDisabledRunAsGroupField(podSpec, oldPodSpec *api.PodSpec) {
 | 
			
		||||
		if podSpec.SecurityContext != nil {
 | 
			
		||||
			podSpec.SecurityContext.RunAsGroup = nil
 | 
			
		||||
		}
 | 
			
		||||
		for i := range podSpec.Containers {
 | 
			
		||||
			if podSpec.Containers[i].SecurityContext != nil {
 | 
			
		||||
				podSpec.Containers[i].SecurityContext.RunAsGroup = nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for i := range podSpec.InitContainers {
 | 
			
		||||
			if podSpec.InitContainers[i].SecurityContext != nil {
 | 
			
		||||
				podSpec.InitContainers[i].SecurityContext.RunAsGroup = nil
 | 
			
		||||
			}
 | 
			
		||||
		VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
			if c.SecurityContext != nil {
 | 
			
		||||
				c.SecurityContext.RunAsGroup = nil
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -443,26 +439,15 @@ func dropDisabledGMSAFieldsFromContainers(containers []api.Container) {
 | 
			
		||||
func dropDisabledProcMountField(podSpec, oldPodSpec *api.PodSpec) {
 | 
			
		||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) && !procMountInUse(oldPodSpec) {
 | 
			
		||||
		defaultProcMount := api.DefaultProcMount
 | 
			
		||||
		for i := range podSpec.Containers {
 | 
			
		||||
			if podSpec.Containers[i].SecurityContext != nil {
 | 
			
		||||
				if podSpec.Containers[i].SecurityContext.ProcMount != nil {
 | 
			
		||||
		VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
			if c.SecurityContext != nil && c.SecurityContext.ProcMount != nil {
 | 
			
		||||
				// The ProcMount field was improperly forced to non-nil in 1.12.
 | 
			
		||||
				// If the feature is disabled, and the existing object is not using any non-default values, and the ProcMount field is present in the incoming object, force to the default value.
 | 
			
		||||
				// Note: we cannot force the field to nil when the feature is disabled because it causes a diff against previously persisted data.
 | 
			
		||||
					podSpec.Containers[i].SecurityContext.ProcMount = &defaultProcMount
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for i := range podSpec.InitContainers {
 | 
			
		||||
			if podSpec.InitContainers[i].SecurityContext != nil {
 | 
			
		||||
				if podSpec.InitContainers[i].SecurityContext.ProcMount != nil {
 | 
			
		||||
					// The ProcMount field was improperly forced to non-nil in 1.12.
 | 
			
		||||
					// If the feature is disabled, and the existing object is not using any non-default values, and the ProcMount field is present in the incoming object, force to the default value.
 | 
			
		||||
					// Note: we cannot force the field to nil when the feature is disabled because it causes a diff against previously persisted data.
 | 
			
		||||
					podSpec.InitContainers[i].SecurityContext.ProcMount = &defaultProcMount
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
				c.SecurityContext.ProcMount = &defaultProcMount
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -470,12 +455,10 @@ func dropDisabledProcMountField(podSpec, oldPodSpec *api.PodSpec) {
 | 
			
		||||
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a VolumeDevice
 | 
			
		||||
func dropDisabledVolumeDevicesFields(podSpec, oldPodSpec *api.PodSpec) {
 | 
			
		||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) && !volumeDevicesInUse(oldPodSpec) {
 | 
			
		||||
		for i := range podSpec.Containers {
 | 
			
		||||
			podSpec.Containers[i].VolumeDevices = nil
 | 
			
		||||
		}
 | 
			
		||||
		for i := range podSpec.InitContainers {
 | 
			
		||||
			podSpec.InitContainers[i].VolumeDevices = nil
 | 
			
		||||
		}
 | 
			
		||||
		VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
			c.VolumeDevices = nil
 | 
			
		||||
			return true
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -494,21 +477,19 @@ func subpathInUse(podSpec *api.PodSpec) bool {
 | 
			
		||||
	if podSpec == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		for j := range podSpec.Containers[i].VolumeMounts {
 | 
			
		||||
			if len(podSpec.Containers[i].VolumeMounts[j].SubPath) > 0 {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		for j := range podSpec.InitContainers[i].VolumeMounts {
 | 
			
		||||
			if len(podSpec.InitContainers[i].VolumeMounts[j].SubPath) > 0 {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var inUse bool
 | 
			
		||||
	VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
		for i := range c.VolumeMounts {
 | 
			
		||||
			if len(c.VolumeMounts[i].SubPath) > 0 {
 | 
			
		||||
				inUse = true
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return inUse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// runtimeClassInUse returns true if the pod spec is non-nil and has a RuntimeClassName set
 | 
			
		||||
@@ -539,25 +520,20 @@ func procMountInUse(podSpec *api.PodSpec) bool {
 | 
			
		||||
	if podSpec == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		if podSpec.Containers[i].SecurityContext != nil {
 | 
			
		||||
			if podSpec.Containers[i].SecurityContext.ProcMount != nil {
 | 
			
		||||
				if *podSpec.Containers[i].SecurityContext.ProcMount != api.DefaultProcMount {
 | 
			
		||||
 | 
			
		||||
	var inUse bool
 | 
			
		||||
	VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
		if c.SecurityContext == nil || c.SecurityContext.ProcMount == nil {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		if podSpec.InitContainers[i].SecurityContext != nil {
 | 
			
		||||
			if podSpec.InitContainers[i].SecurityContext.ProcMount != nil {
 | 
			
		||||
				if *podSpec.InitContainers[i].SecurityContext.ProcMount != api.DefaultProcMount {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
		if *c.SecurityContext.ProcMount != api.DefaultProcMount {
 | 
			
		||||
			inUse = true
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return inUse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// appArmorInUse returns true if the pod has apparmor related information
 | 
			
		||||
@@ -638,17 +614,17 @@ func volumeDevicesInUse(podSpec *api.PodSpec) bool {
 | 
			
		||||
	if podSpec == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		if podSpec.Containers[i].VolumeDevices != nil {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		if podSpec.InitContainers[i].VolumeDevices != nil {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var inUse bool
 | 
			
		||||
	VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
		if c.VolumeDevices != nil {
 | 
			
		||||
			inUse = true
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return inUse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// runAsGroupInUse returns true if the pod spec is non-nil and has a SecurityContext's RunAsGroup field set
 | 
			
		||||
@@ -660,17 +636,17 @@ func runAsGroupInUse(podSpec *api.PodSpec) bool {
 | 
			
		||||
	if podSpec.SecurityContext != nil && podSpec.SecurityContext.RunAsGroup != nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		if podSpec.Containers[i].SecurityContext != nil && podSpec.Containers[i].SecurityContext.RunAsGroup != nil {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		if podSpec.InitContainers[i].SecurityContext != nil && podSpec.InitContainers[i].SecurityContext.RunAsGroup != nil {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var inUse bool
 | 
			
		||||
	VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
		if c.SecurityContext != nil && c.SecurityContext.RunAsGroup != nil {
 | 
			
		||||
			inUse = true
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return inUse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gMSAFieldsInUse returns true if the pod spec is non-nil and has one of any
 | 
			
		||||
@@ -716,21 +692,19 @@ func subpathExprInUse(podSpec *api.PodSpec) bool {
 | 
			
		||||
	if podSpec == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		for j := range podSpec.Containers[i].VolumeMounts {
 | 
			
		||||
			if len(podSpec.Containers[i].VolumeMounts[j].SubPathExpr) > 0 {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		for j := range podSpec.InitContainers[i].VolumeMounts {
 | 
			
		||||
			if len(podSpec.InitContainers[i].VolumeMounts[j].SubPathExpr) > 0 {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var inUse bool
 | 
			
		||||
	VisitContainers(podSpec, func(c *api.Container) bool {
 | 
			
		||||
		for i := range c.VolumeMounts {
 | 
			
		||||
			if len(c.VolumeMounts[i].SubPathExpr) > 0 {
 | 
			
		||||
				inUse = true
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return inUse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// csiInUse returns true if any pod's spec include inline CSI volumes.
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,92 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/security/apparmor"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestVisitContainers(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		description string
 | 
			
		||||
		haveSpec    *api.PodSpec
 | 
			
		||||
		wantNames   []string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"empty podspec",
 | 
			
		||||
			&api.PodSpec{},
 | 
			
		||||
			[]string{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"regular containers",
 | 
			
		||||
			&api.PodSpec{
 | 
			
		||||
				Containers: []api.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"c1", "c2"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"init containers",
 | 
			
		||||
			&api.PodSpec{
 | 
			
		||||
				InitContainers: []api.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"i1", "i2"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"regular and init containers",
 | 
			
		||||
			&api.PodSpec{
 | 
			
		||||
				Containers: []api.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2"},
 | 
			
		||||
				},
 | 
			
		||||
				InitContainers: []api.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"i1", "i2", "c1", "c2"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"dropping fields",
 | 
			
		||||
			&api.PodSpec{
 | 
			
		||||
				Containers: []api.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2", SecurityContext: &api.SecurityContext{}},
 | 
			
		||||
				},
 | 
			
		||||
				InitContainers: []api.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2", SecurityContext: &api.SecurityContext{}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"i1", "i2", "c1", "c2"},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range testCases {
 | 
			
		||||
		gotNames := []string{}
 | 
			
		||||
		VisitContainers(tc.haveSpec, func(c *api.Container) bool {
 | 
			
		||||
			gotNames = append(gotNames, c.Name)
 | 
			
		||||
			if c.SecurityContext != nil {
 | 
			
		||||
				c.SecurityContext = nil
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		})
 | 
			
		||||
		if !reflect.DeepEqual(gotNames, tc.wantNames) {
 | 
			
		||||
			t.Errorf("VisitContainers() for test case %q visited containers %q, wanted to visit %q", tc.description, gotNames, tc.wantNames)
 | 
			
		||||
		}
 | 
			
		||||
		for _, c := range tc.haveSpec.Containers {
 | 
			
		||||
			if c.SecurityContext != nil {
 | 
			
		||||
				t.Errorf("VisitContainers() for test case %q: got SecurityContext %#v for container %v, wanted nil", tc.description, c.SecurityContext, c.Name)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for _, c := range tc.haveSpec.InitContainers {
 | 
			
		||||
			if c.SecurityContext != nil {
 | 
			
		||||
				t.Errorf("VisitContainers() for test case %q: got SecurityContext %#v for init container %v, wanted nil", tc.description, c.SecurityContext, c.Name)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPodSecrets(t *testing.T) {
 | 
			
		||||
	// Stub containing all possible secret references in a pod.
 | 
			
		||||
	// The names of the referenced secrets match struct paths detected by reflection.
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,28 @@ func FindPort(pod *v1.Pod, svcPort *v1.ServicePort) (int, error) {
 | 
			
		||||
	return 0, fmt.Errorf("no suitable port for manifest: %s", pod.UID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainerVisitor is called with each container spec, and returns true
 | 
			
		||||
// if visiting should continue.
 | 
			
		||||
type ContainerVisitor func(container *v1.Container) (shouldContinue bool)
 | 
			
		||||
 | 
			
		||||
// VisitContainers invokes the visitor function with a pointer to the container
 | 
			
		||||
// spec of every container in the given pod spec. If visitor returns false,
 | 
			
		||||
// visiting is short-circuited. VisitContainers returns true if visiting completes,
 | 
			
		||||
// false if visiting was short-circuited.
 | 
			
		||||
func VisitContainers(podSpec *v1.PodSpec, visitor ContainerVisitor) bool {
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		if !visitor(&podSpec.InitContainers[i]) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		if !visitor(&podSpec.Containers[i]) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Visitor is called with each object name, and returns true if visiting should continue
 | 
			
		||||
type Visitor func(name string) (shouldContinue bool)
 | 
			
		||||
 | 
			
		||||
@@ -61,16 +83,9 @@ func VisitPodSecretNames(pod *v1.Pod, visitor Visitor) bool {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		if !visitContainerSecretNames(&pod.Spec.InitContainers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		if !visitContainerSecretNames(&pod.Spec.Containers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	VisitContainers(&pod.Spec, func(c *v1.Container) bool {
 | 
			
		||||
		return visitContainerSecretNames(c, visitor)
 | 
			
		||||
	})
 | 
			
		||||
	var source *v1.VolumeSource
 | 
			
		||||
 | 
			
		||||
	for i := range pod.Spec.Volumes {
 | 
			
		||||
@@ -152,16 +167,9 @@ func visitContainerSecretNames(container *v1.Container, visitor Visitor) bool {
 | 
			
		||||
// Transitive references (e.g. pod -> pvc -> pv -> secret) are not visited.
 | 
			
		||||
// Returns true if visiting completed, false if visiting was short-circuited.
 | 
			
		||||
func VisitPodConfigmapNames(pod *v1.Pod, visitor Visitor) bool {
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		if !visitContainerConfigmapNames(&pod.Spec.InitContainers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		if !visitContainerConfigmapNames(&pod.Spec.Containers[i], visitor) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	VisitContainers(&pod.Spec, func(c *v1.Container) bool {
 | 
			
		||||
		return visitContainerConfigmapNames(c, visitor)
 | 
			
		||||
	})
 | 
			
		||||
	var source *v1.VolumeSource
 | 
			
		||||
	for i := range pod.Spec.Volumes {
 | 
			
		||||
		source = &pod.Spec.Volumes[i].VolumeSource
 | 
			
		||||
 
 | 
			
		||||
@@ -198,6 +198,92 @@ func TestFindPort(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestVisitContainers(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		description string
 | 
			
		||||
		haveSpec    *v1.PodSpec
 | 
			
		||||
		wantNames   []string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"empty podspec",
 | 
			
		||||
			&v1.PodSpec{},
 | 
			
		||||
			[]string{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"regular containers",
 | 
			
		||||
			&v1.PodSpec{
 | 
			
		||||
				Containers: []v1.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"c1", "c2"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"init containers",
 | 
			
		||||
			&v1.PodSpec{
 | 
			
		||||
				InitContainers: []v1.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"i1", "i2"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"regular and init containers",
 | 
			
		||||
			&v1.PodSpec{
 | 
			
		||||
				Containers: []v1.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2"},
 | 
			
		||||
				},
 | 
			
		||||
				InitContainers: []v1.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"i1", "i2", "c1", "c2"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"dropping fields",
 | 
			
		||||
			&v1.PodSpec{
 | 
			
		||||
				Containers: []v1.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2", SecurityContext: &v1.SecurityContext{}},
 | 
			
		||||
				},
 | 
			
		||||
				InitContainers: []v1.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2", SecurityContext: &v1.SecurityContext{}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"i1", "i2", "c1", "c2"},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range testCases {
 | 
			
		||||
		gotNames := []string{}
 | 
			
		||||
		VisitContainers(tc.haveSpec, func(c *v1.Container) bool {
 | 
			
		||||
			gotNames = append(gotNames, c.Name)
 | 
			
		||||
			if c.SecurityContext != nil {
 | 
			
		||||
				c.SecurityContext = nil
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		})
 | 
			
		||||
		if !reflect.DeepEqual(gotNames, tc.wantNames) {
 | 
			
		||||
			t.Errorf("VisitContainers() for test case %q visited containers %q, wanted to visit %q", tc.description, gotNames, tc.wantNames)
 | 
			
		||||
		}
 | 
			
		||||
		for _, c := range tc.haveSpec.Containers {
 | 
			
		||||
			if c.SecurityContext != nil {
 | 
			
		||||
				t.Errorf("VisitContainers() for test case %q: got SecurityContext %#v for container %v, wanted nil", tc.description, c.SecurityContext, c.Name)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for _, c := range tc.haveSpec.InitContainers {
 | 
			
		||||
			if c.SecurityContext != nil {
 | 
			
		||||
				t.Errorf("VisitContainers() for test case %q: got SecurityContext %#v for init container %v, wanted nil", tc.description, c.SecurityContext, c.Name)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPodSecrets(t *testing.T) {
 | 
			
		||||
	// Stub containing all possible secret references in a pod.
 | 
			
		||||
	// The names of the referenced secrets match struct paths detected by reflection.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,13 +5,21 @@ go_library(
 | 
			
		||||
    srcs = ["helpers.go"],
 | 
			
		||||
    importpath = "k8s.io/kubernetes/pkg/apis/core/pods",
 | 
			
		||||
    visibility = ["//visibility:public"],
 | 
			
		||||
    deps = ["//pkg/fieldpath:go_default_library"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/apis/core:go_default_library",
 | 
			
		||||
        "//pkg/fieldpath:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
go_test(
 | 
			
		||||
    name = "go_default_test",
 | 
			
		||||
    srcs = ["helpers_test.go"],
 | 
			
		||||
    embed = [":go_default_library"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/apis/core:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
filegroup(
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,27 @@ package pods
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/fieldpath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ContainerVisitorWithPath is called with each container and the field.Path to that container
 | 
			
		||||
type ContainerVisitorWithPath func(container *api.Container, path *field.Path)
 | 
			
		||||
 | 
			
		||||
// VisitContainersWithPath invokes the visitor function with a pointer to the spec
 | 
			
		||||
// of every container in the given pod spec and the field.Path to that container.
 | 
			
		||||
func VisitContainersWithPath(podSpec *api.PodSpec, visitor ContainerVisitorWithPath) {
 | 
			
		||||
	path := field.NewPath("spec", "initContainers")
 | 
			
		||||
	for i := range podSpec.InitContainers {
 | 
			
		||||
		visitor(&podSpec.InitContainers[i], path.Index(i))
 | 
			
		||||
	}
 | 
			
		||||
	path = field.NewPath("spec", "containers")
 | 
			
		||||
	for i := range podSpec.Containers {
 | 
			
		||||
		visitor(&podSpec.Containers[i], path.Index(i))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertDownwardAPIFieldLabel converts the specified downward API field label
 | 
			
		||||
// and its value in the pod of the specified version to the internal version,
 | 
			
		||||
// and returns the converted label and value. This function returns an error if
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,71 @@ limitations under the License.
 | 
			
		||||
package pods
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestVisitContainersWithPath(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		description string
 | 
			
		||||
		haveSpec    *api.PodSpec
 | 
			
		||||
		wantNames   []string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			"empty podspec",
 | 
			
		||||
			&api.PodSpec{},
 | 
			
		||||
			[]string{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"regular containers",
 | 
			
		||||
			&api.PodSpec{
 | 
			
		||||
				Containers: []api.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"spec.containers[0]", "spec.containers[1]"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"init containers",
 | 
			
		||||
			&api.PodSpec{
 | 
			
		||||
				InitContainers: []api.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"spec.initContainers[0]", "spec.initContainers[1]"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"regular and init containers",
 | 
			
		||||
			&api.PodSpec{
 | 
			
		||||
				Containers: []api.Container{
 | 
			
		||||
					{Name: "c1"},
 | 
			
		||||
					{Name: "c2"},
 | 
			
		||||
				},
 | 
			
		||||
				InitContainers: []api.Container{
 | 
			
		||||
					{Name: "i1"},
 | 
			
		||||
					{Name: "i2"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			[]string{"spec.initContainers[0]", "spec.initContainers[1]", "spec.containers[0]", "spec.containers[1]"},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range testCases {
 | 
			
		||||
		gotNames := []string{}
 | 
			
		||||
		VisitContainersWithPath(tc.haveSpec, func(c *api.Container, p *field.Path) {
 | 
			
		||||
			gotNames = append(gotNames, p.String())
 | 
			
		||||
		})
 | 
			
		||||
		if !reflect.DeepEqual(gotNames, tc.wantNames) {
 | 
			
		||||
			t.Errorf("VisitContainersWithPath() for test case %q visited containers %q, wanted to visit %q", tc.description, gotNames, tc.wantNames)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestConvertDownwardAPIFieldLabel(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		version       string
 | 
			
		||||
 
 | 
			
		||||
@@ -3434,17 +3434,13 @@ func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.Po
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func podSpecHasContainer(spec *core.PodSpec, containerName string) bool {
 | 
			
		||||
	for _, c := range spec.InitContainers {
 | 
			
		||||
	var hasContainer bool
 | 
			
		||||
	podshelper.VisitContainersWithPath(spec, func(c *core.Container, _ *field.Path) {
 | 
			
		||||
		if c.Name == containerName {
 | 
			
		||||
			return true
 | 
			
		||||
			hasContainer = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, c := range spec.Containers {
 | 
			
		||||
		if c.Name == containerName {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
	})
 | 
			
		||||
	return hasContainer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
 
 | 
			
		||||
@@ -361,17 +361,15 @@ func LogLocation(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func podHasContainerWithName(pod *api.Pod, containerName string) bool {
 | 
			
		||||
	for _, c := range pod.Spec.Containers {
 | 
			
		||||
	var hasContainer bool
 | 
			
		||||
	podutil.VisitContainers(&pod.Spec, func(c *api.Container) bool {
 | 
			
		||||
		if c.Name == containerName {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, c := range pod.Spec.InitContainers {
 | 
			
		||||
		if c.Name == containerName {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
			hasContainer = true
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
	return hasContainer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func streamParams(params url.Values, opts runtime.Object) error {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ go_library(
 | 
			
		||||
    ],
 | 
			
		||||
    importpath = "k8s.io/kubernetes/pkg/security/apparmor",
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/api/v1/pod:go_default_library",
 | 
			
		||||
        "//pkg/features:go_default_library",
 | 
			
		||||
        "//pkg/kubelet/types:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/api/core/v1:go_default_library",
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"k8s.io/api/core/v1"
 | 
			
		||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
			
		||||
	podutil "k8s.io/kubernetes/pkg/api/v1/pod"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/features"
 | 
			
		||||
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
 | 
			
		||||
	utilpath "k8s.io/utils/path"
 | 
			
		||||
@@ -76,18 +77,16 @@ func (v *validator) Validate(pod *v1.Pod) error {
 | 
			
		||||
		return fmt.Errorf("could not read loaded profiles: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, container := range pod.Spec.InitContainers {
 | 
			
		||||
		if err := validateProfile(GetProfileName(pod, container.Name), loadedProfiles); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, container := range pod.Spec.Containers {
 | 
			
		||||
		if err := validateProfile(GetProfileName(pod, container.Name), loadedProfiles); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	var retErr error
 | 
			
		||||
	podutil.VisitContainers(&pod.Spec, func(container *v1.Container) bool {
 | 
			
		||||
		retErr = validateProfile(GetProfileName(pod, container.Name), loadedProfiles)
 | 
			
		||||
		if retErr != nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
	return retErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *validator) ValidateHost() error {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,9 @@ go_library(
 | 
			
		||||
    ],
 | 
			
		||||
    importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy",
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/api/pod:go_default_library",
 | 
			
		||||
        "//pkg/apis/core:go_default_library",
 | 
			
		||||
        "//pkg/apis/core/pods:go_default_library",
 | 
			
		||||
        "//pkg/features:go_default_library",
 | 
			
		||||
        "//pkg/security/podsecuritypolicy/apparmor:go_default_library",
 | 
			
		||||
        "//pkg/security/podsecuritypolicy/capabilities:go_default_library",
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,9 @@ import (
 | 
			
		||||
	policy "k8s.io/api/policy/v1beta1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
			
		||||
	podutil "k8s.io/kubernetes/pkg/api/pod"
 | 
			
		||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/core/pods"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/features"
 | 
			
		||||
	psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/securitycontext"
 | 
			
		||||
@@ -108,19 +110,16 @@ func (s *simpleProvider) MutatePod(pod *api.Pod) error {
 | 
			
		||||
		pod.Spec.RuntimeClassName = s.psp.Spec.RuntimeClass.DefaultRuntimeClassName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		if err := s.mutateContainer(pod, &pod.Spec.InitContainers[i]); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	var retErr error
 | 
			
		||||
	podutil.VisitContainers(&pod.Spec, func(c *api.Container) bool {
 | 
			
		||||
		retErr = s.mutateContainer(pod, c)
 | 
			
		||||
		if retErr != nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		if err := s.mutateContainer(pod, &pod.Spec.Containers[i]); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
	return retErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mutateContainer sets the default values of the required but not filled fields.
 | 
			
		||||
@@ -239,15 +238,9 @@ func (s *simpleProvider) ValidatePod(pod *api.Pod) field.ErrorList {
 | 
			
		||||
		allErrs = append(allErrs, validateRuntimeClassName(pod.Spec.RuntimeClassName, s.psp.Spec.RuntimeClass.AllowedRuntimeClassNames)...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fldPath := field.NewPath("spec", "initContainers")
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		allErrs = append(allErrs, s.validateContainer(pod, &pod.Spec.InitContainers[i], fldPath.Index(i))...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fldPath = field.NewPath("spec", "containers")
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		allErrs = append(allErrs, s.validateContainer(pod, &pod.Spec.Containers[i], fldPath.Index(i))...)
 | 
			
		||||
	}
 | 
			
		||||
	pods.VisitContainersWithPath(&pod.Spec, func(c *api.Container, p *field.Path) {
 | 
			
		||||
		allErrs = append(allErrs, s.validateContainer(pod, c, p)...)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
@@ -281,26 +274,13 @@ func (s *simpleProvider) validatePodVolumes(pod *api.Pod) field.ErrorList {
 | 
			
		||||
						fmt.Sprintf("is not allowed to be used")))
 | 
			
		||||
				} else if mustBeReadOnly {
 | 
			
		||||
					// Ensure all the VolumeMounts that use this volume are read-only
 | 
			
		||||
					for i, c := range pod.Spec.InitContainers {
 | 
			
		||||
						for j, cv := range c.VolumeMounts {
 | 
			
		||||
					pods.VisitContainersWithPath(&pod.Spec, func(c *api.Container, p *field.Path) {
 | 
			
		||||
						for i, cv := range c.VolumeMounts {
 | 
			
		||||
							if cv.Name == v.Name && !cv.ReadOnly {
 | 
			
		||||
								allErrs = append(allErrs, field.Invalid(
 | 
			
		||||
									field.NewPath("spec", "initContainers").Index(i).Child("volumeMounts").Index(j).Child("readOnly"),
 | 
			
		||||
									cv.ReadOnly, "must be read-only"),
 | 
			
		||||
								)
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					for i, c := range pod.Spec.Containers {
 | 
			
		||||
						for j, cv := range c.VolumeMounts {
 | 
			
		||||
							if cv.Name == v.Name && !cv.ReadOnly {
 | 
			
		||||
								allErrs = append(allErrs, field.Invalid(
 | 
			
		||||
									field.NewPath("spec", "containers").Index(i).Child("volumeMounts").Index(j).Child("readOnly"),
 | 
			
		||||
									cv.ReadOnly, "must be read-only"),
 | 
			
		||||
								)
 | 
			
		||||
							}
 | 
			
		||||
								allErrs = append(allErrs, field.Invalid(p.Child("volumeMounts").Index(i).Child("readOnly"), cv.ReadOnly, "must be read-only"))
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			case policy.FlexVolume:
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ go_library(
 | 
			
		||||
    visibility = ["//visibility:public"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/api/legacyscheme:go_default_library",
 | 
			
		||||
        "//pkg/api/v1/pod:go_default_library",
 | 
			
		||||
        "//pkg/apis/core/v1/helper:go_default_library",
 | 
			
		||||
        "//pkg/features:go_default_library",
 | 
			
		||||
        "//pkg/util/mount:go_default_library",
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/api/core/v1"
 | 
			
		||||
	podutil "k8s.io/kubernetes/pkg/api/v1/pod"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// getNestedMountpoints returns a list of mountpoint directories that should be created
 | 
			
		||||
@@ -70,16 +71,19 @@ func getNestedMountpoints(name, baseDir string, pod v1.Pod) ([]string, error) {
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	for _, container := range pod.Spec.InitContainers {
 | 
			
		||||
		if err := checkContainer(&container); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, container := range pod.Spec.Containers {
 | 
			
		||||
		if err := checkContainer(&container); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
 | 
			
		||||
	var retErr error
 | 
			
		||||
	podutil.VisitContainers(&pod.Spec, func(c *v1.Container) bool {
 | 
			
		||||
		retErr = checkContainer(c)
 | 
			
		||||
		if retErr != nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
	if retErr != nil {
 | 
			
		||||
		return nil, retErr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return retval, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ go_library(
 | 
			
		||||
    importpath = "k8s.io/kubernetes/plugin/pkg/admission/alwayspullimages",
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/apis/core:go_default_library",
 | 
			
		||||
        "//pkg/apis/core/pods:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ import (
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	"k8s.io/apiserver/pkg/admission"
 | 
			
		||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/core/pods"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PluginName indicates name of admission plugin.
 | 
			
		||||
@@ -63,13 +64,9 @@ func (a *AlwaysPullImages) Admit(attributes admission.Attributes, o admission.Ob
 | 
			
		||||
		return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		pod.Spec.InitContainers[i].ImagePullPolicy = api.PullAlways
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		pod.Spec.Containers[i].ImagePullPolicy = api.PullAlways
 | 
			
		||||
	}
 | 
			
		||||
	pods.VisitContainersWithPath(&pod.Spec, func(c *api.Container, _ *field.Path) {
 | 
			
		||||
		c.ImagePullPolicy = api.PullAlways
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -85,23 +82,17 @@ func (*AlwaysPullImages) Validate(attributes admission.Attributes, o admission.O
 | 
			
		||||
		return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range pod.Spec.InitContainers {
 | 
			
		||||
		if pod.Spec.InitContainers[i].ImagePullPolicy != api.PullAlways {
 | 
			
		||||
			return admission.NewForbidden(attributes,
 | 
			
		||||
				field.NotSupported(field.NewPath("spec", "initContainers").Index(i).Child("imagePullPolicy"),
 | 
			
		||||
					pod.Spec.InitContainers[i].ImagePullPolicy, []string{string(api.PullAlways)},
 | 
			
		||||
				),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := range pod.Spec.Containers {
 | 
			
		||||
		if pod.Spec.Containers[i].ImagePullPolicy != api.PullAlways {
 | 
			
		||||
			return admission.NewForbidden(attributes,
 | 
			
		||||
				field.NotSupported(field.NewPath("spec", "containers").Index(i).Child("imagePullPolicy"),
 | 
			
		||||
					pod.Spec.Containers[i].ImagePullPolicy, []string{string(api.PullAlways)},
 | 
			
		||||
				),
 | 
			
		||||
			)
 | 
			
		||||
	var allErrs []error
 | 
			
		||||
	pods.VisitContainersWithPath(&pod.Spec, func(c *api.Container, p *field.Path) {
 | 
			
		||||
		if c.ImagePullPolicy != api.PullAlways {
 | 
			
		||||
			allErrs = append(allErrs, admission.NewForbidden(attributes,
 | 
			
		||||
				field.NotSupported(p.Child("imagePullPolicy"), c.ImagePullPolicy, []string{string(api.PullAlways)}),
 | 
			
		||||
			))
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	if len(allErrs) > 0 {
 | 
			
		||||
		// TODO: consider using utilerrors.NewAggregate(allErrs)
 | 
			
		||||
		return allErrs[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ go_library(
 | 
			
		||||
    srcs = ["admission.go"],
 | 
			
		||||
    importpath = "k8s.io/kubernetes/plugin/pkg/admission/exec",
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/api/v1/pod:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/api/core/v1:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ import (
 | 
			
		||||
	genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
 | 
			
		||||
	"k8s.io/client-go/kubernetes"
 | 
			
		||||
	"k8s.io/klog"
 | 
			
		||||
	podutil "k8s.io/kubernetes/pkg/api/v1/pod"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -146,21 +147,16 @@ func (d *DenyExec) Validate(a admission.Attributes, o admission.ObjectInterfaces
 | 
			
		||||
 | 
			
		||||
// isPrivileged will return true a pod has any privileged containers
 | 
			
		||||
func isPrivileged(pod *corev1.Pod) bool {
 | 
			
		||||
	for _, c := range pod.Spec.InitContainers {
 | 
			
		||||
	var privileged bool
 | 
			
		||||
	podutil.VisitContainers(&pod.Spec, func(c *corev1.Container) bool {
 | 
			
		||||
		if c.SecurityContext == nil || c.SecurityContext.Privileged == nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if *c.SecurityContext.Privileged {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, c := range pod.Spec.Containers {
 | 
			
		||||
		if c.SecurityContext == nil || c.SecurityContext.Privileged == nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if *c.SecurityContext.Privileged {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
			privileged = true
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
	return privileged
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,12 +34,14 @@ go_library(
 | 
			
		||||
    importpath = "k8s.io/kubernetes/plugin/pkg/admission/podpreset",
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/apis/core:go_default_library",
 | 
			
		||||
        "//pkg/apis/core/pods:go_default_library",
 | 
			
		||||
        "//pkg/apis/core/v1:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/api/settings/v1alpha1:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
 | 
			
		||||
        "//staging/src/k8s.io/client-go/informers:go_default_library",
 | 
			
		||||
 
 | 
			
		||||
@@ -29,12 +29,14 @@ import (
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/labels"
 | 
			
		||||
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	"k8s.io/apiserver/pkg/admission"
 | 
			
		||||
	genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
 | 
			
		||||
	"k8s.io/client-go/informers"
 | 
			
		||||
	"k8s.io/client-go/kubernetes"
 | 
			
		||||
	settingsv1alpha1listers "k8s.io/client-go/listers/settings/v1alpha1"
 | 
			
		||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/core/pods"
 | 
			
		||||
	apiscorev1 "k8s.io/kubernetes/pkg/apis/core/v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -183,16 +185,11 @@ func safeToApplyPodPresetsOnPod(pod *api.Pod, podPresets []*settingsv1alpha1.Pod
 | 
			
		||||
	if _, err := mergeVolumes(pod.Spec.Volumes, podPresets); err != nil {
 | 
			
		||||
		errs = append(errs, err)
 | 
			
		||||
	}
 | 
			
		||||
	for _, ctr := range pod.Spec.Containers {
 | 
			
		||||
		if err := safeToApplyPodPresetsOnContainer(&ctr, podPresets); err != nil {
 | 
			
		||||
	pods.VisitContainersWithPath(&pod.Spec, func(c *api.Container, _ *field.Path) {
 | 
			
		||||
		if err := safeToApplyPodPresetsOnContainer(c, podPresets); err != nil {
 | 
			
		||||
			errs = append(errs, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, iCtr := range pod.Spec.InitContainers {
 | 
			
		||||
		if err := safeToApplyPodPresetsOnContainer(&iCtr, podPresets); err != nil {
 | 
			
		||||
			errs = append(errs, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return utilerrors.NewAggregate(errs)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
  allowedImports:
 | 
			
		||||
  - k8s.io/apimachinery
 | 
			
		||||
  - k8s.io/apiserver/pkg/util/feature
 | 
			
		||||
  - k8s.io/component-base/featuregate/testing
 | 
			
		||||
  - k8s.io/kubernetes/pkg/apis/core
 | 
			
		||||
  - k8s.io/kubernetes/pkg/features
 | 
			
		||||
  - k8s.io/kubernetes/pkg/fieldpath
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user