Skip to content

Commit

Permalink
Create helpers for iterating containers in a pod
Browse files Browse the repository at this point in the history
  • Loading branch information
verb committed Jun 21, 2019
1 parent 4683054 commit ee821e2
Show file tree
Hide file tree
Showing 15 changed files with 467 additions and 271 deletions.
244 changes: 109 additions & 135 deletions pkg/api/pod/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -338,30 +346,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 = ""
VisitContainers(podSpec, func(c *api.Container) bool {
for i := range c.VolumeMounts {
c.VolumeMounts[i].SubPathExpr = ""
}
}
for i := range podSpec.InitContainers {
for j := range podSpec.InitContainers[i].VolumeMounts {
podSpec.InitContainers[i].VolumeMounts[j].SubPathExpr = ""
}
}
return true
})
}

dropDisabledVolumeDevicesFields(podSpec, oldPodSpec)
Expand Down Expand Up @@ -399,16 +399,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
VisitContainers(podSpec, func(c *api.Container) bool {
if c.SecurityContext != nil {
c.SecurityContext.RunAsGroup = nil
}
}
for i := range podSpec.InitContainers {
if podSpec.InitContainers[i].SecurityContext != nil {
podSpec.InitContainers[i].SecurityContext.RunAsGroup = nil
}
}
return true
})
}
}

Expand Down Expand Up @@ -450,39 +446,26 @@ 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 {
// 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
}
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.
c.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
}
}
}
return true
})
}
}

// dropDisabledVolumeDevicesFields removes disabled fields from []VolumeDevice if it has not been already populated.
// 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
})
}
}

Expand All @@ -501,21 +484,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 false
return true
})

return inUse
}

// runtimeClassInUse returns true if the pod spec is non-nil and has a RuntimeClassName set
Expand Down Expand Up @@ -546,25 +527,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 {
return true
}
}

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 false
return true
})

return inUse
}

// appArmorInUse returns true if the pod has apparmor related information
Expand Down Expand Up @@ -645,17 +621,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 false
return true
})

return inUse
}

// runAsGroupInUse returns true if the pod spec is non-nil and has a SecurityContext's RunAsGroup field set
Expand All @@ -667,17 +643,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 false
return true
})

return inUse
}

// gMSAFieldsInUse returns true if the pod spec is non-nil and has one of any
Expand Down Expand Up @@ -723,21 +699,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 false
return true
})

return inUse
}

// csiInUse returns true if any pod's spec include inline CSI volumes.
Expand Down
Loading

0 comments on commit ee821e2

Please sign in to comment.