Skip to content

Commit 6e4e329

Browse files
authored
Merge pull request kubernetes#99576 from marosset/windows-host-process-work
Windows host process work
2 parents 8a70c48 + ae42416 commit 6e4e329

File tree

88 files changed

+15195
-12936
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+15195
-12936
lines changed

api/openapi-spec/swagger.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/api/pod/util.go

+28
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
401401
AllowInvalidPodDeletionCost: !utilfeature.DefaultFeatureGate.Enabled(features.PodDeletionCost),
402402
// Do not allow pod spec to use non-integer multiple of huge page unit size default
403403
AllowIndivisibleHugePagesValues: false,
404+
AllowWindowsHostProcessField: utilfeature.DefaultFeatureGate.Enabled(features.WindowsHostProcessContainers),
404405
}
405406

406407
if oldPodSpec != nil {
@@ -415,6 +416,8 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
415416
return !opts.AllowDownwardAPIHugePages
416417
})
417418
}
419+
// if old spec has Windows Host Process fields set, we must allow it
420+
opts.AllowWindowsHostProcessField = opts.AllowWindowsHostProcessField || setsWindowsHostProcess(oldPodSpec)
418421

419422
// if old spec used non-integer multiple of huge page unit size, we must allow it
420423
opts.AllowIndivisibleHugePagesValues = usesIndivisibleHugePagesValues(oldPodSpec)
@@ -944,3 +947,28 @@ func SeccompFieldForAnnotation(annotation string) *api.SeccompProfile {
944947
// length or if the annotation has an unrecognized value
945948
return nil
946949
}
950+
951+
// setsWindowsHostProcess returns true if WindowsOptions.HostProcess is set (true or false)
952+
// anywhere in the pod spec.
953+
func setsWindowsHostProcess(podSpec *api.PodSpec) bool {
954+
if podSpec == nil {
955+
return false
956+
}
957+
958+
// Check Pod's WindowsOptions.HostProcess
959+
if podSpec.SecurityContext != nil && podSpec.SecurityContext.WindowsOptions != nil && podSpec.SecurityContext.WindowsOptions.HostProcess != nil {
960+
return true
961+
}
962+
963+
// Check WindowsOptions.HostProcess for each container
964+
inUse := false
965+
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
966+
if c.SecurityContext != nil && c.SecurityContext.WindowsOptions != nil && c.SecurityContext.WindowsOptions.HostProcess != nil {
967+
inUse = true
968+
return false
969+
}
970+
return true
971+
})
972+
973+
return inUse
974+
}

pkg/apis/core/types.go

+10
Original file line numberDiff line numberDiff line change
@@ -5357,6 +5357,16 @@ type WindowsSecurityContextOptions struct {
53575357
// PodSecurityContext, the value specified in SecurityContext takes precedence.
53585358
// +optional
53595359
RunAsUserName *string
5360+
5361+
// HostProcess determines if a container should be run as a 'Host Process' container.
5362+
// This field is alpha-level and will only be honored by components that enable the
5363+
// WindowsHostProcessContainers feature flag. Setting this field without the feature
5364+
// flag will result in errors when validating the Pod. All of a Pod's containers must
5365+
// have the same effective HostProcess value (it is not allowed to have a mix of HostProcess
5366+
// containers and non-HostProcess containers). In addition, if HostProcess is true
5367+
// then HostNetwork must also be set to true.
5368+
// +optional
5369+
HostProcess *bool
53605370
}
53615371

53625372
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

pkg/apis/core/v1/zz_generated.conversion.go

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/core/validation/validation.go

+88
Original file line numberDiff line numberDiff line change
@@ -3204,6 +3204,8 @@ type PodValidationOptions struct {
32043204
AllowInvalidPodDeletionCost bool
32053205
// Allow pod spec to use non-integer multiple of huge page unit size
32063206
AllowIndivisibleHugePagesValues bool
3207+
// Allow hostProcess field to be set in windows security context
3208+
AllowWindowsHostProcessField bool
32073209
}
32083210

32093211
// ValidatePodSingleHugePageResources checks if there are multiple huge
@@ -3327,6 +3329,7 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi
33273329
allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"))...)
33283330
allErrs = append(allErrs, validateReadinessGates(spec.ReadinessGates, fldPath.Child("readinessGates"))...)
33293331
allErrs = append(allErrs, validateTopologySpreadConstraints(spec.TopologySpreadConstraints, fldPath.Child("topologySpreadConstraints"))...)
3332+
allErrs = append(allErrs, validateWindowsHostProcessPod(spec, fldPath, opts)...)
33303333
if len(spec.ServiceAccountName) > 0 {
33313334
for _, msg := range ValidateServiceAccountName(spec.ServiceAccountName, false) {
33323335
allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg))
@@ -5974,6 +5977,91 @@ func validateWindowsSecurityContextOptions(windowsOptions *core.WindowsSecurityC
59745977
return allErrs
59755978
}
59765979

5980+
func validateWindowsHostProcessPod(podSpec *core.PodSpec, fieldPath *field.Path, opts PodValidationOptions) field.ErrorList {
5981+
allErrs := field.ErrorList{}
5982+
5983+
// Keep track of container and hostProcess container count for validate
5984+
containerCount := 0
5985+
hostProcessContainerCount := 0
5986+
5987+
var podHostProcess *bool
5988+
if podSpec.SecurityContext != nil && podSpec.SecurityContext.WindowsOptions != nil {
5989+
podHostProcess = podSpec.SecurityContext.WindowsOptions.HostProcess
5990+
}
5991+
5992+
if !opts.AllowWindowsHostProcessField && podHostProcess != nil {
5993+
// Do not allow pods to persist data that sets hostProcess (true or false)
5994+
errMsg := "not allowed when feature gate 'WindowsHostProcessContainers' is not enabled"
5995+
allErrs = append(allErrs, field.Forbidden(fieldPath.Child("securityContext", "windowsOptions", "hostProcess"), errMsg))
5996+
return allErrs
5997+
}
5998+
5999+
hostNetwork := false
6000+
if podSpec.SecurityContext != nil {
6001+
hostNetwork = podSpec.SecurityContext.HostNetwork
6002+
}
6003+
6004+
podshelper.VisitContainersWithPath(podSpec, fieldPath, func(c *core.Container, cFieldPath *field.Path) bool {
6005+
containerCount++
6006+
6007+
var containerHostProcess *bool = nil
6008+
if c.SecurityContext != nil && c.SecurityContext.WindowsOptions != nil {
6009+
containerHostProcess = c.SecurityContext.WindowsOptions.HostProcess
6010+
}
6011+
6012+
if !opts.AllowWindowsHostProcessField && containerHostProcess != nil {
6013+
// Do not allow pods to persist data that sets hostProcess (true or false)
6014+
errMsg := "not allowed when feature gate 'WindowsHostProcessContainers' is not enabled"
6015+
allErrs = append(allErrs, field.Forbidden(cFieldPath.Child("securityContext", "windowsOptions", "hostProcess"), errMsg))
6016+
}
6017+
6018+
if podHostProcess != nil && containerHostProcess != nil && *podHostProcess != *containerHostProcess {
6019+
errMsg := fmt.Sprintf("pod hostProcess value must be identical if both are specified, was %v", *podHostProcess)
6020+
allErrs = append(allErrs, field.Invalid(cFieldPath.Child("securityContext", "windowsOptions", "hostProcess"), *containerHostProcess, errMsg))
6021+
}
6022+
6023+
switch {
6024+
case containerHostProcess != nil && *containerHostProcess:
6025+
// Container explitly sets hostProcess=true
6026+
hostProcessContainerCount++
6027+
case containerHostProcess == nil && podHostProcess != nil && *podHostProcess:
6028+
// Container inherits hostProcess=true from pod settings
6029+
hostProcessContainerCount++
6030+
}
6031+
6032+
return true
6033+
})
6034+
6035+
if hostProcessContainerCount > 0 {
6036+
// Fail Pod validation if feature is not enabled (unless podspec already exists and contains HostProcess fields) instead of dropping fields based on PRR reivew.
6037+
if !opts.AllowWindowsHostProcessField {
6038+
errMsg := "pod must not contain Windows hostProcess containers when feature gate 'WindowsHostProcessContainers' is not enabled"
6039+
allErrs = append(allErrs, field.Forbidden(fieldPath, errMsg))
6040+
return allErrs
6041+
}
6042+
6043+
// At present, if a Windows Pods contains any HostProcess containers than all containers must be
6044+
// HostProcess containers (explicitly set or inherited).
6045+
if hostProcessContainerCount != containerCount {
6046+
errMsg := "If pod contains any hostProcess containers then all containers must be HostProcess containers"
6047+
allErrs = append(allErrs, field.Invalid(fieldPath, "", errMsg))
6048+
}
6049+
6050+
// At present Windows Pods which contain HostProcess containers must also set HostNetwork.
6051+
if hostNetwork != true {
6052+
errMsg := "hostNetwork must be true if pod contains any hostProcess containers"
6053+
allErrs = append(allErrs, field.Invalid(fieldPath.Child("hostNetwork"), hostNetwork, errMsg))
6054+
}
6055+
6056+
if !capabilities.Get().AllowPrivileged {
6057+
errMsg := "hostProcess containers are disallowed by cluster policy"
6058+
allErrs = append(allErrs, field.Forbidden(fieldPath, errMsg))
6059+
}
6060+
}
6061+
6062+
return allErrs
6063+
}
6064+
59776065
func ValidatePodLogOptions(opts *core.PodLogOptions) field.ErrorList {
59786066
allErrs := field.ErrorList{}
59796067
if opts.TailLines != nil && *opts.TailLines < 0 {

0 commit comments

Comments
 (0)