Adjust the validation to the current state
This commit is contained in:
2
api/openapi-spec/swagger.json
generated
2
api/openapi-spec/swagger.json
generated
@@ -4821,7 +4821,7 @@
|
|||||||
"description": "Represents time when the job was completed. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC. The completion time is set when the job finishes successfully, and only then. The value cannot be updated or removed. The value indicates the same or later point in time as the startTime field."
|
"description": "Represents time when the job was completed. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC. The completion time is set when the job finishes successfully, and only then. The value cannot be updated or removed. The value indicates the same or later point in time as the startTime field."
|
||||||
},
|
},
|
||||||
"conditions": {
|
"conditions": {
|
||||||
"description": "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". Job cannot be both in the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
"description": "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". A Job cannot have both the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/io.k8s.api.batch.v1.JobCondition"
|
"$ref": "#/definitions/io.k8s.api.batch.v1.JobCondition"
|
||||||
},
|
},
|
||||||
|
@@ -435,7 +435,7 @@
|
|||||||
"description": "Represents time when the job was completed. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC. The completion time is set when the job finishes successfully, and only then. The value cannot be updated or removed. The value indicates the same or later point in time as the startTime field."
|
"description": "Represents time when the job was completed. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC. The completion time is set when the job finishes successfully, and only then. The value cannot be updated or removed. The value indicates the same or later point in time as the startTime field."
|
||||||
},
|
},
|
||||||
"conditions": {
|
"conditions": {
|
||||||
"description": "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". Job cannot be both in the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
"description": "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". A Job cannot have both the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
||||||
"items": {
|
"items": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
|
@@ -495,7 +495,7 @@ type JobStatus struct {
|
|||||||
// type "Complete" and status true.
|
// type "Complete" and status true.
|
||||||
//
|
//
|
||||||
// A job is considered finished when it is in a terminal condition, either
|
// A job is considered finished when it is in a terminal condition, either
|
||||||
// "Complete" or "Failed". Job cannot be both in the "Complete" and "Failed" conditions.
|
// "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions.
|
||||||
// Additionally, it cannot be in the "Complete" and "FailureTarget" conditions.
|
// Additionally, it cannot be in the "Complete" and "FailureTarget" conditions.
|
||||||
// The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled.
|
// The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled.
|
||||||
//
|
//
|
||||||
|
@@ -524,11 +524,6 @@ func validateJobStatus(job *batch.Job, fldPath *field.Path, opts JobStatusValida
|
|||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("active"), status.Active, "active>0 is invalid for finished job"))
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("active"), status.Active, "active>0 is invalid for finished job"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if opts.RejectFinishedJobWithTerminatingPods {
|
|
||||||
if status.Terminating != nil && *status.Terminating > 0 && isJobFinished {
|
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("terminating"), status.Terminating, "terminating>0 is invalid for finished job"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if opts.RejectFinishedJobWithoutStartTime {
|
if opts.RejectFinishedJobWithoutStartTime {
|
||||||
if status.StartTime == nil && isJobFinished {
|
if status.StartTime == nil && isJobFinished {
|
||||||
allErrs = append(allErrs, field.Required(fldPath.Child("startTime"), "startTime is required for finished job"))
|
allErrs = append(allErrs, field.Required(fldPath.Child("startTime"), "startTime is required for finished job"))
|
||||||
@@ -566,11 +561,6 @@ func validateJobStatus(job *batch.Job, fldPath *field.Path, opts JobStatusValida
|
|||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("failedIndexes"), *status.FailedIndexes, "cannot set non-null failedIndexes when backoffLimitPerIndex is null"))
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("failedIndexes"), *status.FailedIndexes, "cannot set non-null failedIndexes when backoffLimitPerIndex is null"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if opts.RejectMoreReadyThanActivePods {
|
|
||||||
if status.Ready != nil && *status.Ready > status.Active {
|
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("ready"), *status.Ready, "cannot set more ready pods than active"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if opts.RejectFailedIndexesOverlappingCompleted {
|
if opts.RejectFailedIndexesOverlappingCompleted {
|
||||||
if job.Spec.Completions != nil && status.FailedIndexes != nil {
|
if job.Spec.Completions != nil && status.FailedIndexes != nil {
|
||||||
if err := validateFailedIndexesNotOverlapCompleted(status.CompletedIndexes, *status.FailedIndexes, int32(*job.Spec.Completions)); err != nil {
|
if err := validateFailedIndexesNotOverlapCompleted(status.CompletedIndexes, *status.FailedIndexes, int32(*job.Spec.Completions)); err != nil {
|
||||||
@@ -1023,9 +1013,7 @@ type JobStatusValidationOptions struct {
|
|||||||
RejectFailedIndexesOverlappingCompleted bool
|
RejectFailedIndexesOverlappingCompleted bool
|
||||||
RejectCompletedIndexesForNonIndexedJob bool
|
RejectCompletedIndexesForNonIndexedJob bool
|
||||||
RejectFailedIndexesForNoBackoffLimitPerIndex bool
|
RejectFailedIndexesForNoBackoffLimitPerIndex bool
|
||||||
RejectMoreReadyThanActivePods bool
|
|
||||||
RejectFinishedJobWithActivePods bool
|
RejectFinishedJobWithActivePods bool
|
||||||
RejectFinishedJobWithTerminatingPods bool
|
|
||||||
RejectFinishedJobWithoutStartTime bool
|
RejectFinishedJobWithoutStartTime bool
|
||||||
RejectFinishedJobWithUncountedTerminatedPods bool
|
RejectFinishedJobWithUncountedTerminatedPods bool
|
||||||
RejectStartTimeUpdateForUnsuspendedJob bool
|
RejectStartTimeUpdateForUnsuspendedJob bool
|
||||||
|
2
pkg/generated/openapi/zz_generated.openapi.go
generated
2
pkg/generated/openapi/zz_generated.openapi.go
generated
@@ -17191,7 +17191,7 @@ func schema_k8sio_api_batch_v1_JobStatus(ref common.ReferenceCallback) common.Op
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". Job cannot be both in the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
Description: "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". A Job cannot have both the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
||||||
Type: []string{"array"},
|
Type: []string{"array"},
|
||||||
Items: &spec.SchemaOrArray{
|
Items: &spec.SchemaOrArray{
|
||||||
Schema: &spec.Schema{
|
Schema: &spec.Schema{
|
||||||
|
@@ -380,8 +380,6 @@ func getStatusValidationOptions(newJob, oldJob *batch.Job) batchvalidation.JobSt
|
|||||||
isCompletedIndexesChanged := oldJob.Status.CompletedIndexes != newJob.Status.CompletedIndexes
|
isCompletedIndexesChanged := oldJob.Status.CompletedIndexes != newJob.Status.CompletedIndexes
|
||||||
isFailedIndexesChanged := !ptr.Equal(oldJob.Status.FailedIndexes, newJob.Status.FailedIndexes)
|
isFailedIndexesChanged := !ptr.Equal(oldJob.Status.FailedIndexes, newJob.Status.FailedIndexes)
|
||||||
isActiveChanged := oldJob.Status.Active != newJob.Status.Active
|
isActiveChanged := oldJob.Status.Active != newJob.Status.Active
|
||||||
isReadyChanged := !ptr.Equal(oldJob.Status.Ready, newJob.Status.Ready)
|
|
||||||
isTerminatingChanged := !ptr.Equal(oldJob.Status.Terminating, newJob.Status.Terminating)
|
|
||||||
isStartTimeChanged := !ptr.Equal(oldJob.Status.StartTime, newJob.Status.StartTime)
|
isStartTimeChanged := !ptr.Equal(oldJob.Status.StartTime, newJob.Status.StartTime)
|
||||||
isCompletionTimeChanged := !ptr.Equal(oldJob.Status.CompletionTime, newJob.Status.CompletionTime)
|
isCompletionTimeChanged := !ptr.Equal(oldJob.Status.CompletionTime, newJob.Status.CompletionTime)
|
||||||
isUncountedTerminatedPodsChanged := !apiequality.Semantic.DeepEqual(oldJob.Status.UncountedTerminatedPods, newJob.Status.UncountedTerminatedPods)
|
isUncountedTerminatedPodsChanged := !apiequality.Semantic.DeepEqual(oldJob.Status.UncountedTerminatedPods, newJob.Status.UncountedTerminatedPods)
|
||||||
@@ -397,9 +395,7 @@ func getStatusValidationOptions(newJob, oldJob *batch.Job) batchvalidation.JobSt
|
|||||||
RejectCompletedIndexesForNonIndexedJob: isCompletedIndexesChanged,
|
RejectCompletedIndexesForNonIndexedJob: isCompletedIndexesChanged,
|
||||||
RejectFailedIndexesForNoBackoffLimitPerIndex: isFailedIndexesChanged,
|
RejectFailedIndexesForNoBackoffLimitPerIndex: isFailedIndexesChanged,
|
||||||
RejectFailedIndexesOverlappingCompleted: isFailedIndexesChanged || isCompletedIndexesChanged,
|
RejectFailedIndexesOverlappingCompleted: isFailedIndexesChanged || isCompletedIndexesChanged,
|
||||||
RejectMoreReadyThanActivePods: isReadyChanged || isActiveChanged,
|
|
||||||
RejectFinishedJobWithActivePods: isJobFinishedChanged || isActiveChanged,
|
RejectFinishedJobWithActivePods: isJobFinishedChanged || isActiveChanged,
|
||||||
RejectFinishedJobWithTerminatingPods: isJobFinishedChanged || isTerminatingChanged,
|
|
||||||
RejectFinishedJobWithoutStartTime: isJobFinishedChanged || isStartTimeChanged,
|
RejectFinishedJobWithoutStartTime: isJobFinishedChanged || isStartTimeChanged,
|
||||||
RejectFinishedJobWithUncountedTerminatedPods: isJobFinishedChanged || isUncountedTerminatedPodsChanged,
|
RejectFinishedJobWithUncountedTerminatedPods: isJobFinishedChanged || isUncountedTerminatedPodsChanged,
|
||||||
RejectStartTimeUpdateForUnsuspendedJob: isStartTimeChanged,
|
RejectStartTimeUpdateForUnsuspendedJob: isStartTimeChanged,
|
||||||
|
@@ -2271,7 +2271,7 @@ func TestStatusStrategy_ValidateUpdate(t *testing.T) {
|
|||||||
{Type: field.ErrorTypeInvalid, Field: "status.active"},
|
{Type: field.ErrorTypeInvalid, Field: "status.active"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"invalid attempt to transition to Complete=True with terminating > 0": {
|
"transition to Failed condition with terminating>0 and ready>0": {
|
||||||
enableJobManagedBy: true,
|
enableJobManagedBy: true,
|
||||||
job: &batch.Job{
|
job: &batch.Job{
|
||||||
ObjectMeta: validObjectMeta,
|
ObjectMeta: validObjectMeta,
|
||||||
@@ -2280,19 +2280,16 @@ func TestStatusStrategy_ValidateUpdate(t *testing.T) {
|
|||||||
ObjectMeta: validObjectMeta,
|
ObjectMeta: validObjectMeta,
|
||||||
Status: batch.JobStatus{
|
Status: batch.JobStatus{
|
||||||
StartTime: &now,
|
StartTime: &now,
|
||||||
CompletionTime: &now,
|
|
||||||
Terminating: ptr.To[int32](1),
|
|
||||||
Conditions: []batch.JobCondition{
|
Conditions: []batch.JobCondition{
|
||||||
{
|
{
|
||||||
Type: batch.JobComplete,
|
Type: batch.JobFailed,
|
||||||
Status: api.ConditionTrue,
|
Status: api.ConditionTrue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Terminating: ptr.To[int32](1),
|
||||||
|
Ready: ptr.To[int32](1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErrs: field.ErrorList{
|
|
||||||
{Type: field.ErrorTypeInvalid, Field: "status.terminating"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"invalid attempt to transition to Failed=True with uncountedTerminatedPods.Failed>0": {
|
"invalid attempt to transition to Failed=True with uncountedTerminatedPods.Failed>0": {
|
||||||
enableJobManagedBy: true,
|
enableJobManagedBy: true,
|
||||||
@@ -2929,28 +2926,6 @@ func TestStatusStrategy_ValidateUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"invalid attempt to set more ready pods than active": {
|
|
||||||
enableJobManagedBy: true,
|
|
||||||
job: &batch.Job{
|
|
||||||
ObjectMeta: validObjectMeta,
|
|
||||||
Spec: batch.JobSpec{
|
|
||||||
Completions: ptr.To[int32](5),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
newJob: &batch.Job{
|
|
||||||
ObjectMeta: validObjectMeta,
|
|
||||||
Spec: batch.JobSpec{
|
|
||||||
Completions: ptr.To[int32](5),
|
|
||||||
},
|
|
||||||
Status: batch.JobStatus{
|
|
||||||
Active: 1,
|
|
||||||
Ready: ptr.To[int32](2),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErrs: field.ErrorList{
|
|
||||||
{Type: field.ErrorTypeInvalid, Field: "status.ready"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"more ready pods than active, but allowed": {
|
"more ready pods than active, but allowed": {
|
||||||
enableJobManagedBy: true,
|
enableJobManagedBy: true,
|
||||||
job: &batch.Job{
|
job: &batch.Job{
|
||||||
|
@@ -367,7 +367,7 @@ message JobStatus {
|
|||||||
// type "Complete" and status true.
|
// type "Complete" and status true.
|
||||||
//
|
//
|
||||||
// A job is considered finished when it is in a terminal condition, either
|
// A job is considered finished when it is in a terminal condition, either
|
||||||
// "Complete" or "Failed". Job cannot be both in the "Complete" and "Failed" conditions.
|
// "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions.
|
||||||
// Additionally, it cannot be in the "Complete" and "FailureTarget" conditions.
|
// Additionally, it cannot be in the "Complete" and "FailureTarget" conditions.
|
||||||
// The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled.
|
// The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled.
|
||||||
//
|
//
|
||||||
|
@@ -495,7 +495,7 @@ type JobStatus struct {
|
|||||||
// type "Complete" and status true.
|
// type "Complete" and status true.
|
||||||
//
|
//
|
||||||
// A job is considered finished when it is in a terminal condition, either
|
// A job is considered finished when it is in a terminal condition, either
|
||||||
// "Complete" or "Failed". Job cannot be both in the "Complete" and "Failed" conditions.
|
// "Complete" or "Failed". A Job cannot have both the "Complete" and "Failed" conditions.
|
||||||
// Additionally, it cannot be in the "Complete" and "FailureTarget" conditions.
|
// Additionally, it cannot be in the "Complete" and "FailureTarget" conditions.
|
||||||
// The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled.
|
// The "Complete", "Failed" and "FailureTarget" conditions cannot be disabled.
|
||||||
//
|
//
|
||||||
|
@@ -136,7 +136,7 @@ func (JobSpec) SwaggerDoc() map[string]string {
|
|||||||
|
|
||||||
var map_JobStatus = map[string]string{
|
var map_JobStatus = map[string]string{
|
||||||
"": "JobStatus represents the current state of a Job.",
|
"": "JobStatus represents the current state of a Job.",
|
||||||
"conditions": "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". Job cannot be both in the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
"conditions": "The latest available observations of an object's current state. When a Job fails, one of the conditions will have type \"Failed\" and status true. When a Job is suspended, one of the conditions will have type \"Suspended\" and status true; when the Job is resumed, the status of this condition will become false. When a Job is completed, one of the conditions will have type \"Complete\" and status true.\n\nA job is considered finished when it is in a terminal condition, either \"Complete\" or \"Failed\". A Job cannot have both the \"Complete\" and \"Failed\" conditions. Additionally, it cannot be in the \"Complete\" and \"FailureTarget\" conditions. The \"Complete\", \"Failed\" and \"FailureTarget\" conditions cannot be disabled.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
||||||
"startTime": "Represents time when the job controller started processing a job. When a Job is created in the suspended state, this field is not set until the first time it is resumed. This field is reset every time a Job is resumed from suspension. It is represented in RFC3339 form and is in UTC.\n\nOnce set, the field can only be removed when the job is suspended. The field cannot be modified while the job is unsuspended or finished.",
|
"startTime": "Represents time when the job controller started processing a job. When a Job is created in the suspended state, this field is not set until the first time it is resumed. This field is reset every time a Job is resumed from suspension. It is represented in RFC3339 form and is in UTC.\n\nOnce set, the field can only be removed when the job is suspended. The field cannot be modified while the job is unsuspended or finished.",
|
||||||
"completionTime": "Represents time when the job was completed. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC. The completion time is set when the job finishes successfully, and only then. The value cannot be updated or removed. The value indicates the same or later point in time as the startTime field.",
|
"completionTime": "Represents time when the job was completed. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC. The completion time is set when the job finishes successfully, and only then. The value cannot be updated or removed. The value indicates the same or later point in time as the startTime field.",
|
||||||
"active": "The number of pending and running pods which are not terminating (without a deletionTimestamp). The value is zero for finished jobs.",
|
"active": "The number of pending and running pods which are not terminating (without a deletionTimestamp). The value is zero for finished jobs.",
|
||||||
|
Reference in New Issue
Block a user