@@ -3319,17 +3319,48 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod) field.ErrorList {
3319
3319
return allErrs
3320
3320
}
3321
3321
3322
+ // ValidateContainerStateTransition test to if any illegal container state transitions are being attempted
3323
+ func ValidateContainerStateTransition (newStatuses , oldStatuses []core.ContainerStatus , fldpath * field.Path , restartPolicy core.RestartPolicy ) field.ErrorList {
3324
+ allErrs := field.ErrorList {}
3325
+ // If we should always restart, containers are allowed to leave the terminated state
3326
+ if restartPolicy == core .RestartPolicyAlways {
3327
+ return allErrs
3328
+ }
3329
+ for i , oldStatus := range oldStatuses {
3330
+ // Skip any container that is not terminated
3331
+ if oldStatus .State .Terminated == nil {
3332
+ continue
3333
+ }
3334
+ // Skip any container that failed but is allowed to restart
3335
+ if oldStatus .State .Terminated .ExitCode != 0 && restartPolicy == core .RestartPolicyOnFailure {
3336
+ continue
3337
+ }
3338
+ for _ , newStatus := range newStatuses {
3339
+ if oldStatus .Name == newStatus .Name && newStatus .State .Terminated == nil {
3340
+ allErrs = append (allErrs , field .Forbidden (fldpath .Index (i ).Child ("state" ), "may not be transitioned to non-terminated state" ))
3341
+ }
3342
+ }
3343
+ }
3344
+ return allErrs
3345
+ }
3346
+
3322
3347
// ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
3323
3348
// that cannot be changed.
3324
3349
func ValidatePodStatusUpdate (newPod , oldPod * core.Pod ) field.ErrorList {
3325
3350
fldPath := field .NewPath ("metadata" )
3326
3351
allErrs := ValidateObjectMetaUpdate (& newPod .ObjectMeta , & oldPod .ObjectMeta , fldPath )
3327
3352
allErrs = append (allErrs , ValidatePodSpecificAnnotationUpdates (newPod , oldPod , fldPath .Child ("annotations" ))... )
3328
3353
3354
+ fldPath = field .NewPath ("status" )
3329
3355
if newPod .Spec .NodeName != oldPod .Spec .NodeName {
3330
- allErrs = append (allErrs , field .Forbidden (field . NewPath ( "status" , "nodeName" ), "may not be changed directly" ))
3356
+ allErrs = append (allErrs , field .Forbidden (fldPath . Child ( "nodeName" ), "may not be changed directly" ))
3331
3357
}
3332
3358
3359
+ // If pod should not restart, make sure the status update does not transition
3360
+ // any terminated containers to a non-terminated state.
3361
+ allErrs = append (allErrs , ValidateContainerStateTransition (newPod .Status .ContainerStatuses , oldPod .Status .ContainerStatuses , fldPath .Child ("containerStatuses" ), oldPod .Spec .RestartPolicy )... )
3362
+ allErrs = append (allErrs , ValidateContainerStateTransition (newPod .Status .InitContainerStatuses , oldPod .Status .InitContainerStatuses , fldPath .Child ("initContainerStatuses" ), oldPod .Spec .RestartPolicy )... )
3363
+
3333
3364
// For status update we ignore changes to pod spec.
3334
3365
newPod .Spec = oldPod .Spec
3335
3366
0 commit comments