Support handling of pod failures with respect to the specified rules
This commit is contained in:
@@ -110,6 +110,119 @@ const (
|
||||
IndexedCompletion CompletionMode = "Indexed"
|
||||
)
|
||||
|
||||
// PodFailurePolicyAction specifies how a Pod failure is handled.
|
||||
// +enum
|
||||
type PodFailurePolicyAction string
|
||||
|
||||
const (
|
||||
// This is an action which might be taken on a pod failure - mark the
|
||||
// pod's job as Failed and terminate all running pods.
|
||||
PodFailurePolicyActionFailJob PodFailurePolicyAction = "FailJob"
|
||||
|
||||
// This is an action which might be taken on a pod failure - the counter towards
|
||||
// .backoffLimit, represented by the job's .status.failed field, is not
|
||||
// incremented and a replacement pod is created.
|
||||
PodFailurePolicyActionIgnore PodFailurePolicyAction = "Ignore"
|
||||
|
||||
// This is an action which might be taken on a pod failure - the pod failure
|
||||
// is handled in the default way - the counter towards .backoffLimit,
|
||||
// represented by the job's .status.failed field, is incremented.
|
||||
PodFailurePolicyActionCount PodFailurePolicyAction = "Count"
|
||||
)
|
||||
|
||||
// +enum
|
||||
type PodFailurePolicyOnExitCodesOperator string
|
||||
|
||||
const (
|
||||
PodFailurePolicyOnExitCodesOpIn PodFailurePolicyOnExitCodesOperator = "In"
|
||||
PodFailurePolicyOnExitCodesOpNotIn PodFailurePolicyOnExitCodesOperator = "NotIn"
|
||||
)
|
||||
|
||||
// PodFailurePolicyOnExitCodesRequirement describes the requirement for handling
|
||||
// a failed pod based on its container exit codes. In particular, it lookups the
|
||||
// .state.terminated.exitCode for each app container and init container status,
|
||||
// represented by the .status.containerStatuses and .status.initContainerStatuses
|
||||
// fields in the Pod status, respectively. Containers completed with success
|
||||
// (exit code 0) are excluded from the requirement check.
|
||||
type PodFailurePolicyOnExitCodesRequirement struct {
|
||||
// Restricts the check for exit codes to the container with the
|
||||
// specified name. When null, the rule applies to all containers.
|
||||
// When specified, it should match one the container or initContainer
|
||||
// names in the pod template.
|
||||
// +optional
|
||||
ContainerName *string
|
||||
|
||||
// Represents the relationship between the container exit code(s) and the
|
||||
// specified values. Containers completed with success (exit code 0) are
|
||||
// excluded from the requirement check. Possible values are:
|
||||
// - In: the requirement is satisfied if at least one container exit code
|
||||
// (might be multiple if there are multiple containers not restricted
|
||||
// by the 'containerName' field) is in the set of specified values.
|
||||
// - NotIn: the requirement is satisfied if at least one container exit code
|
||||
// (might be multiple if there are multiple containers not restricted
|
||||
// by the 'containerName' field) is not in the set of specified values.
|
||||
// Additional values are considered to be added in the future. Clients should
|
||||
// react to an unknown operator by assuming the requirement is not satisfied.
|
||||
Operator PodFailurePolicyOnExitCodesOperator
|
||||
|
||||
// Specifies the set of values. Each returned container exit code (might be
|
||||
// multiple in case of multiple containers) is checked against this set of
|
||||
// values with respect to the operator. The list of values must be ordered
|
||||
// and must not contain duplicates. Value '0' cannot be used for the In operator.
|
||||
// At least one element is required. At most 255 elements are allowed.
|
||||
// +listType=set
|
||||
Values []int32
|
||||
}
|
||||
|
||||
// PodFailurePolicyOnPodConditionsPattern describes a pattern for matching
|
||||
// an actual pod condition type.
|
||||
type PodFailurePolicyOnPodConditionsPattern struct {
|
||||
// Specifies the required Pod condition type. To match a pod condition
|
||||
// it is required that specified type equals the pod condition type.
|
||||
Type api.PodConditionType
|
||||
// Specifies the required Pod condition status. To match a pod condition
|
||||
// it is required that the specified status equals the pod condition status.
|
||||
// Defaults to True.
|
||||
Status api.ConditionStatus
|
||||
}
|
||||
|
||||
// PodFailurePolicyRule describes how a pod failure is handled when the requirements are met.
|
||||
// One of OnExitCodes and onPodConditions, but not both, can be used in each rule.
|
||||
type PodFailurePolicyRule struct {
|
||||
// Specifies the action taken on a pod failure when the requirements are satisfied.
|
||||
// Possible values are:
|
||||
// - FailJob: indicates that the pod's job is marked as Failed and all
|
||||
// running pods are terminated.
|
||||
// - Ignore: indicates that the counter towards the .backoffLimit is not
|
||||
// incremented and a replacement pod is created.
|
||||
// - Count: indicates that the pod is handled in the default way - the
|
||||
// counter towards the .backoffLimit is incremented.
|
||||
// Additional values are considered to be added in the future. Clients should
|
||||
// react to an unknown action by skipping the rule.
|
||||
Action PodFailurePolicyAction
|
||||
|
||||
// Represents the requirement on the container exit codes.
|
||||
// +optional
|
||||
OnExitCodes *PodFailurePolicyOnExitCodesRequirement
|
||||
|
||||
// Represents the requirement on the pod conditions. The requirement is represented
|
||||
// as a list of pod condition patterns. The requirement is satisfied if at
|
||||
// least one pattern matches an actual pod condition. At most 20 elements are allowed.
|
||||
// +listType=atomic
|
||||
OnPodConditions []PodFailurePolicyOnPodConditionsPattern
|
||||
}
|
||||
|
||||
// PodFailurePolicy describes how failed pods influence the backoffLimit.
|
||||
type PodFailurePolicy struct {
|
||||
// A list of pod failure policy rules. The rules are evaluated in order.
|
||||
// Once a rule matches a Pod failure, the remaining of the rules are ignored.
|
||||
// When no rule matches the Pod failure, the default handling applies - the
|
||||
// counter of pod failures is incremented and it is checked against
|
||||
// the backoffLimit. At most 20 elements are allowed.
|
||||
// +listType=atomic
|
||||
Rules []PodFailurePolicyRule
|
||||
}
|
||||
|
||||
// JobSpec describes how the job execution will look like.
|
||||
type JobSpec struct {
|
||||
|
||||
@@ -128,6 +241,19 @@ type JobSpec struct {
|
||||
// +optional
|
||||
Completions *int32
|
||||
|
||||
// Specifies the policy of handling failed pods. In particular, it allows to
|
||||
// specify the set of actions and conditions which need to be
|
||||
// satisfied to take the associated action.
|
||||
// If empty, the default behaviour applies - the counter of failed pods,
|
||||
// represented by the jobs's .status.failed field, is incremented and it is
|
||||
// checked against the backoffLimit. This field cannot be used in combination
|
||||
// with .spec.podTemplate.spec.restartPolicy=OnFailure.
|
||||
//
|
||||
// This field is alpha-level. To use this field, you must enable the
|
||||
// `JobPodFailurePolicy` feature gate (disabled by default).
|
||||
// +optional
|
||||
PodFailurePolicy *PodFailurePolicy
|
||||
|
||||
// Specifies the duration in seconds relative to the startTime that the job
|
||||
// may be continuously active before the system tries to terminate it; value
|
||||
// must be positive integer. If a Job is suspended (at creation or through an
|
||||
@@ -313,6 +439,9 @@ const (
|
||||
JobComplete JobConditionType = "Complete"
|
||||
// JobFailed means the job has failed its execution.
|
||||
JobFailed JobConditionType = "Failed"
|
||||
// FailureTarget means the job is about to fail its execution.
|
||||
// The constant is to be renamed once the name is accepted within the KEP-3329.
|
||||
AlphaNoCompatGuaranteeJobFailureTarget JobConditionType = "FailureTarget"
|
||||
)
|
||||
|
||||
// JobCondition describes current state of a job.
|
||||
|
@@ -18,6 +18,7 @@ package v1
|
||||
|
||||
import (
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
@@ -50,6 +51,17 @@ func SetDefaults_Job(obj *batchv1.Job) {
|
||||
if obj.Spec.Suspend == nil {
|
||||
obj.Spec.Suspend = utilpointer.BoolPtr(false)
|
||||
}
|
||||
if obj.Spec.PodFailurePolicy != nil {
|
||||
for _, rule := range obj.Spec.PodFailurePolicy.Rules {
|
||||
if rule.OnPodConditions != nil {
|
||||
for i, pattern := range rule.OnPodConditions {
|
||||
if pattern.Status == "" {
|
||||
rule.OnPodConditions[i].Status = corev1.ConditionTrue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_CronJob(obj *batchv1.CronJob) {
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
@@ -40,6 +40,97 @@ func TestSetDefaultJob(t *testing.T) {
|
||||
expected *batchv1.Job
|
||||
expectLabels bool
|
||||
}{
|
||||
"Pod failure policy with some field values unspecified -> set default values": {
|
||||
original: &batchv1.Job{
|
||||
Spec: batchv1.JobSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
|
||||
},
|
||||
PodFailurePolicy: &batchv1.PodFailurePolicy{
|
||||
Rules: []batchv1.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batchv1.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: v1.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: v1.ConditionTrue,
|
||||
},
|
||||
{
|
||||
Type: v1.PodConditionType("MemoryLimitExceeded"),
|
||||
Status: v1.ConditionFalse,
|
||||
},
|
||||
{
|
||||
Type: v1.PodConditionType("DiskLimitExceeded"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batchv1.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batchv1.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batchv1.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batchv1.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: v1.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &batchv1.Job{
|
||||
Spec: batchv1.JobSpec{
|
||||
Completions: pointer.Int32Ptr(1),
|
||||
Parallelism: pointer.Int32Ptr(1),
|
||||
BackoffLimit: pointer.Int32Ptr(6),
|
||||
CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
|
||||
Suspend: pointer.BoolPtr(false),
|
||||
PodFailurePolicy: &batchv1.PodFailurePolicy{
|
||||
Rules: []batchv1.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batchv1.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: v1.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: v1.ConditionTrue,
|
||||
},
|
||||
{
|
||||
Type: v1.PodConditionType("MemoryLimitExceeded"),
|
||||
Status: v1.ConditionFalse,
|
||||
},
|
||||
{
|
||||
Type: v1.PodConditionType("DiskLimitExceeded"),
|
||||
Status: v1.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batchv1.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batchv1.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batchv1.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batchv1.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: v1.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: v1.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectLabels: true,
|
||||
},
|
||||
"All unspecified -> sets all to default values": {
|
||||
original: &batchv1.Job{
|
||||
Spec: batchv1.JobSpec{
|
||||
@@ -267,6 +358,9 @@ func TestSetDefaultJob(t *testing.T) {
|
||||
validateDefaultInt32(t, "Parallelism", actual.Spec.Parallelism, expected.Spec.Parallelism)
|
||||
validateDefaultInt32(t, "BackoffLimit", actual.Spec.BackoffLimit, expected.Spec.BackoffLimit)
|
||||
|
||||
if diff := cmp.Diff(expected.Spec.PodFailurePolicy, actual.Spec.PodFailurePolicy); diff != "" {
|
||||
t.Errorf("unexpected diff in errors (-want, +got):\n%s", diff)
|
||||
}
|
||||
if test.expectLabels != reflect.DeepEqual(actual.Labels, actual.Spec.Template.Labels) {
|
||||
if test.expectLabels {
|
||||
t.Errorf("Expected labels: %v, got: %v", actual.Spec.Template.Labels, actual.Labels)
|
||||
|
132
pkg/apis/batch/v1/zz_generated.conversion.go
generated
132
pkg/apis/batch/v1/zz_generated.conversion.go
generated
@@ -132,6 +132,46 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.PodFailurePolicy)(nil), (*batch.PodFailurePolicy)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_PodFailurePolicy_To_batch_PodFailurePolicy(a.(*v1.PodFailurePolicy), b.(*batch.PodFailurePolicy), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*batch.PodFailurePolicy)(nil), (*v1.PodFailurePolicy)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_batch_PodFailurePolicy_To_v1_PodFailurePolicy(a.(*batch.PodFailurePolicy), b.(*v1.PodFailurePolicy), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.PodFailurePolicyOnExitCodesRequirement)(nil), (*batch.PodFailurePolicyOnExitCodesRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_PodFailurePolicyOnExitCodesRequirement_To_batch_PodFailurePolicyOnExitCodesRequirement(a.(*v1.PodFailurePolicyOnExitCodesRequirement), b.(*batch.PodFailurePolicyOnExitCodesRequirement), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*batch.PodFailurePolicyOnExitCodesRequirement)(nil), (*v1.PodFailurePolicyOnExitCodesRequirement)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_batch_PodFailurePolicyOnExitCodesRequirement_To_v1_PodFailurePolicyOnExitCodesRequirement(a.(*batch.PodFailurePolicyOnExitCodesRequirement), b.(*v1.PodFailurePolicyOnExitCodesRequirement), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.PodFailurePolicyOnPodConditionsPattern)(nil), (*batch.PodFailurePolicyOnPodConditionsPattern)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_PodFailurePolicyOnPodConditionsPattern_To_batch_PodFailurePolicyOnPodConditionsPattern(a.(*v1.PodFailurePolicyOnPodConditionsPattern), b.(*batch.PodFailurePolicyOnPodConditionsPattern), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*batch.PodFailurePolicyOnPodConditionsPattern)(nil), (*v1.PodFailurePolicyOnPodConditionsPattern)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_batch_PodFailurePolicyOnPodConditionsPattern_To_v1_PodFailurePolicyOnPodConditionsPattern(a.(*batch.PodFailurePolicyOnPodConditionsPattern), b.(*v1.PodFailurePolicyOnPodConditionsPattern), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.PodFailurePolicyRule)(nil), (*batch.PodFailurePolicyRule)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_PodFailurePolicyRule_To_batch_PodFailurePolicyRule(a.(*v1.PodFailurePolicyRule), b.(*batch.PodFailurePolicyRule), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*batch.PodFailurePolicyRule)(nil), (*v1.PodFailurePolicyRule)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_batch_PodFailurePolicyRule_To_v1_PodFailurePolicyRule(a.(*batch.PodFailurePolicyRule), b.(*v1.PodFailurePolicyRule), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.UncountedTerminatedPods)(nil), (*batch.UncountedTerminatedPods)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_UncountedTerminatedPods_To_batch_UncountedTerminatedPods(a.(*v1.UncountedTerminatedPods), b.(*batch.UncountedTerminatedPods), scope)
|
||||
}); err != nil {
|
||||
@@ -399,6 +439,7 @@ func autoConvert_v1_JobSpec_To_batch_JobSpec(in *v1.JobSpec, out *batch.JobSpec,
|
||||
out.Parallelism = (*int32)(unsafe.Pointer(in.Parallelism))
|
||||
out.Completions = (*int32)(unsafe.Pointer(in.Completions))
|
||||
out.ActiveDeadlineSeconds = (*int64)(unsafe.Pointer(in.ActiveDeadlineSeconds))
|
||||
out.PodFailurePolicy = (*batch.PodFailurePolicy)(unsafe.Pointer(in.PodFailurePolicy))
|
||||
out.BackoffLimit = (*int32)(unsafe.Pointer(in.BackoffLimit))
|
||||
out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector))
|
||||
out.ManualSelector = (*bool)(unsafe.Pointer(in.ManualSelector))
|
||||
@@ -414,6 +455,7 @@ func autoConvert_v1_JobSpec_To_batch_JobSpec(in *v1.JobSpec, out *batch.JobSpec,
|
||||
func autoConvert_batch_JobSpec_To_v1_JobSpec(in *batch.JobSpec, out *v1.JobSpec, s conversion.Scope) error {
|
||||
out.Parallelism = (*int32)(unsafe.Pointer(in.Parallelism))
|
||||
out.Completions = (*int32)(unsafe.Pointer(in.Completions))
|
||||
out.PodFailurePolicy = (*v1.PodFailurePolicy)(unsafe.Pointer(in.PodFailurePolicy))
|
||||
out.ActiveDeadlineSeconds = (*int64)(unsafe.Pointer(in.ActiveDeadlineSeconds))
|
||||
out.BackoffLimit = (*int32)(unsafe.Pointer(in.BackoffLimit))
|
||||
out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector))
|
||||
@@ -489,6 +531,96 @@ func Convert_batch_JobTemplateSpec_To_v1_JobTemplateSpec(in *batch.JobTemplateSp
|
||||
return autoConvert_batch_JobTemplateSpec_To_v1_JobTemplateSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_PodFailurePolicy_To_batch_PodFailurePolicy(in *v1.PodFailurePolicy, out *batch.PodFailurePolicy, s conversion.Scope) error {
|
||||
out.Rules = *(*[]batch.PodFailurePolicyRule)(unsafe.Pointer(&in.Rules))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_PodFailurePolicy_To_batch_PodFailurePolicy is an autogenerated conversion function.
|
||||
func Convert_v1_PodFailurePolicy_To_batch_PodFailurePolicy(in *v1.PodFailurePolicy, out *batch.PodFailurePolicy, s conversion.Scope) error {
|
||||
return autoConvert_v1_PodFailurePolicy_To_batch_PodFailurePolicy(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_batch_PodFailurePolicy_To_v1_PodFailurePolicy(in *batch.PodFailurePolicy, out *v1.PodFailurePolicy, s conversion.Scope) error {
|
||||
out.Rules = *(*[]v1.PodFailurePolicyRule)(unsafe.Pointer(&in.Rules))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_batch_PodFailurePolicy_To_v1_PodFailurePolicy is an autogenerated conversion function.
|
||||
func Convert_batch_PodFailurePolicy_To_v1_PodFailurePolicy(in *batch.PodFailurePolicy, out *v1.PodFailurePolicy, s conversion.Scope) error {
|
||||
return autoConvert_batch_PodFailurePolicy_To_v1_PodFailurePolicy(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_PodFailurePolicyOnExitCodesRequirement_To_batch_PodFailurePolicyOnExitCodesRequirement(in *v1.PodFailurePolicyOnExitCodesRequirement, out *batch.PodFailurePolicyOnExitCodesRequirement, s conversion.Scope) error {
|
||||
out.ContainerName = (*string)(unsafe.Pointer(in.ContainerName))
|
||||
out.Operator = batch.PodFailurePolicyOnExitCodesOperator(in.Operator)
|
||||
out.Values = *(*[]int32)(unsafe.Pointer(&in.Values))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_PodFailurePolicyOnExitCodesRequirement_To_batch_PodFailurePolicyOnExitCodesRequirement is an autogenerated conversion function.
|
||||
func Convert_v1_PodFailurePolicyOnExitCodesRequirement_To_batch_PodFailurePolicyOnExitCodesRequirement(in *v1.PodFailurePolicyOnExitCodesRequirement, out *batch.PodFailurePolicyOnExitCodesRequirement, s conversion.Scope) error {
|
||||
return autoConvert_v1_PodFailurePolicyOnExitCodesRequirement_To_batch_PodFailurePolicyOnExitCodesRequirement(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_batch_PodFailurePolicyOnExitCodesRequirement_To_v1_PodFailurePolicyOnExitCodesRequirement(in *batch.PodFailurePolicyOnExitCodesRequirement, out *v1.PodFailurePolicyOnExitCodesRequirement, s conversion.Scope) error {
|
||||
out.ContainerName = (*string)(unsafe.Pointer(in.ContainerName))
|
||||
out.Operator = v1.PodFailurePolicyOnExitCodesOperator(in.Operator)
|
||||
out.Values = *(*[]int32)(unsafe.Pointer(&in.Values))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_batch_PodFailurePolicyOnExitCodesRequirement_To_v1_PodFailurePolicyOnExitCodesRequirement is an autogenerated conversion function.
|
||||
func Convert_batch_PodFailurePolicyOnExitCodesRequirement_To_v1_PodFailurePolicyOnExitCodesRequirement(in *batch.PodFailurePolicyOnExitCodesRequirement, out *v1.PodFailurePolicyOnExitCodesRequirement, s conversion.Scope) error {
|
||||
return autoConvert_batch_PodFailurePolicyOnExitCodesRequirement_To_v1_PodFailurePolicyOnExitCodesRequirement(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_PodFailurePolicyOnPodConditionsPattern_To_batch_PodFailurePolicyOnPodConditionsPattern(in *v1.PodFailurePolicyOnPodConditionsPattern, out *batch.PodFailurePolicyOnPodConditionsPattern, s conversion.Scope) error {
|
||||
out.Type = core.PodConditionType(in.Type)
|
||||
out.Status = core.ConditionStatus(in.Status)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_PodFailurePolicyOnPodConditionsPattern_To_batch_PodFailurePolicyOnPodConditionsPattern is an autogenerated conversion function.
|
||||
func Convert_v1_PodFailurePolicyOnPodConditionsPattern_To_batch_PodFailurePolicyOnPodConditionsPattern(in *v1.PodFailurePolicyOnPodConditionsPattern, out *batch.PodFailurePolicyOnPodConditionsPattern, s conversion.Scope) error {
|
||||
return autoConvert_v1_PodFailurePolicyOnPodConditionsPattern_To_batch_PodFailurePolicyOnPodConditionsPattern(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_batch_PodFailurePolicyOnPodConditionsPattern_To_v1_PodFailurePolicyOnPodConditionsPattern(in *batch.PodFailurePolicyOnPodConditionsPattern, out *v1.PodFailurePolicyOnPodConditionsPattern, s conversion.Scope) error {
|
||||
out.Type = corev1.PodConditionType(in.Type)
|
||||
out.Status = corev1.ConditionStatus(in.Status)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_batch_PodFailurePolicyOnPodConditionsPattern_To_v1_PodFailurePolicyOnPodConditionsPattern is an autogenerated conversion function.
|
||||
func Convert_batch_PodFailurePolicyOnPodConditionsPattern_To_v1_PodFailurePolicyOnPodConditionsPattern(in *batch.PodFailurePolicyOnPodConditionsPattern, out *v1.PodFailurePolicyOnPodConditionsPattern, s conversion.Scope) error {
|
||||
return autoConvert_batch_PodFailurePolicyOnPodConditionsPattern_To_v1_PodFailurePolicyOnPodConditionsPattern(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_PodFailurePolicyRule_To_batch_PodFailurePolicyRule(in *v1.PodFailurePolicyRule, out *batch.PodFailurePolicyRule, s conversion.Scope) error {
|
||||
out.Action = batch.PodFailurePolicyAction(in.Action)
|
||||
out.OnExitCodes = (*batch.PodFailurePolicyOnExitCodesRequirement)(unsafe.Pointer(in.OnExitCodes))
|
||||
out.OnPodConditions = *(*[]batch.PodFailurePolicyOnPodConditionsPattern)(unsafe.Pointer(&in.OnPodConditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_PodFailurePolicyRule_To_batch_PodFailurePolicyRule is an autogenerated conversion function.
|
||||
func Convert_v1_PodFailurePolicyRule_To_batch_PodFailurePolicyRule(in *v1.PodFailurePolicyRule, out *batch.PodFailurePolicyRule, s conversion.Scope) error {
|
||||
return autoConvert_v1_PodFailurePolicyRule_To_batch_PodFailurePolicyRule(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_batch_PodFailurePolicyRule_To_v1_PodFailurePolicyRule(in *batch.PodFailurePolicyRule, out *v1.PodFailurePolicyRule, s conversion.Scope) error {
|
||||
out.Action = v1.PodFailurePolicyAction(in.Action)
|
||||
out.OnExitCodes = (*v1.PodFailurePolicyOnExitCodesRequirement)(unsafe.Pointer(in.OnExitCodes))
|
||||
out.OnPodConditions = *(*[]v1.PodFailurePolicyOnPodConditionsPattern)(unsafe.Pointer(&in.OnPodConditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_batch_PodFailurePolicyRule_To_v1_PodFailurePolicyRule is an autogenerated conversion function.
|
||||
func Convert_batch_PodFailurePolicyRule_To_v1_PodFailurePolicyRule(in *batch.PodFailurePolicyRule, out *v1.PodFailurePolicyRule, s conversion.Scope) error {
|
||||
return autoConvert_batch_PodFailurePolicyRule_To_v1_PodFailurePolicyRule(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_UncountedTerminatedPods_To_batch_UncountedTerminatedPods(in *v1.UncountedTerminatedPods, out *batch.UncountedTerminatedPods, s conversion.Scope) error {
|
||||
out.Succeeded = *(*[]types.UID)(unsafe.Pointer(&in.Succeeded))
|
||||
out.Failed = *(*[]types.UID)(unsafe.Pointer(&in.Failed))
|
||||
|
@@ -22,6 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@@ -39,6 +40,33 @@ import (
|
||||
// .status.completedIndexes.
|
||||
const maxParallelismForIndexedJob = 100000
|
||||
|
||||
const (
|
||||
// maximum number of rules in pod failure policy
|
||||
maxPodFailurePolicyRules = 20
|
||||
|
||||
// maximum number of values for a OnExitCodes requirement in pod failure policy
|
||||
maxPodFailurePolicyOnExitCodesValues = 255
|
||||
|
||||
// maximum number of patterns for a OnPodConditions requirement in pod failure policy
|
||||
maxPodFailurePolicyOnPodConditionsPatterns = 20
|
||||
)
|
||||
|
||||
var (
|
||||
supportedPodFailurePolicyActions sets.String = sets.NewString(
|
||||
string(batch.PodFailurePolicyActionCount),
|
||||
string(batch.PodFailurePolicyActionFailJob),
|
||||
string(batch.PodFailurePolicyActionIgnore))
|
||||
|
||||
supportedPodFailurePolicyOnExitCodesOperator sets.String = sets.NewString(
|
||||
string(batch.PodFailurePolicyOnExitCodesOpIn),
|
||||
string(batch.PodFailurePolicyOnExitCodesOpNotIn))
|
||||
|
||||
supportedPodFailurePolicyOnPodConditionsStatus sets.String = sets.NewString(
|
||||
string(v1.ConditionFalse),
|
||||
string(v1.ConditionTrue),
|
||||
string(v1.ConditionUnknown))
|
||||
)
|
||||
|
||||
// ValidateGeneratedSelector validates that the generated selector on a controller object match the controller object
|
||||
// metadata, and the labels on the pod template are as generated.
|
||||
//
|
||||
@@ -168,6 +196,10 @@ func validateJobSpec(spec *batch.JobSpec, fldPath *field.Path, opts apivalidatio
|
||||
}
|
||||
}
|
||||
|
||||
if spec.PodFailurePolicy != nil {
|
||||
allErrs = append(allErrs, validatePodFailurePolicy(spec, fldPath.Child("podFailurePolicy"))...)
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(&spec.Template, fldPath.Child("template"), opts)...)
|
||||
|
||||
// spec.Template.Spec.RestartPolicy can be defaulted as RestartPolicyAlways
|
||||
@@ -179,10 +211,113 @@ func validateJobSpec(spec *batch.JobSpec, fldPath *field.Path, opts apivalidatio
|
||||
} else if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure && spec.Template.Spec.RestartPolicy != api.RestartPolicyNever {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"),
|
||||
spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)}))
|
||||
} else if spec.PodFailurePolicy != nil && spec.Template.Spec.RestartPolicy != api.RestartPolicyNever {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("template", "spec", "restartPolicy"),
|
||||
spec.Template.Spec.RestartPolicy, fmt.Sprintf("only %q is supported when podFailurePolicy is specified", api.RestartPolicyNever)))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePodFailurePolicy(spec *batch.JobSpec, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
rulesPath := fldPath.Child("rules")
|
||||
if len(spec.PodFailurePolicy.Rules) > maxPodFailurePolicyRules {
|
||||
allErrs = append(allErrs, field.TooMany(rulesPath, len(spec.PodFailurePolicy.Rules), maxPodFailurePolicyRules))
|
||||
}
|
||||
containerNames := sets.NewString()
|
||||
for _, containerSpec := range spec.Template.Spec.Containers {
|
||||
containerNames.Insert(containerSpec.Name)
|
||||
}
|
||||
for _, containerSpec := range spec.Template.Spec.InitContainers {
|
||||
containerNames.Insert(containerSpec.Name)
|
||||
}
|
||||
for i, rule := range spec.PodFailurePolicy.Rules {
|
||||
allErrs = append(allErrs, validatePodFailurePolicyRule(&rule, rulesPath.Index(i), containerNames)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePodFailurePolicyRule(rule *batch.PodFailurePolicyRule, rulePath *field.Path, containerNames sets.String) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
actionPath := rulePath.Child("action")
|
||||
if rule.Action == "" {
|
||||
allErrs = append(allErrs, field.Required(actionPath, fmt.Sprintf("valid values: %q", supportedPodFailurePolicyActions.List())))
|
||||
} else if !supportedPodFailurePolicyActions.Has(string(rule.Action)) {
|
||||
allErrs = append(allErrs, field.NotSupported(actionPath, rule.Action, supportedPodFailurePolicyActions.List()))
|
||||
}
|
||||
if rule.OnExitCodes != nil {
|
||||
allErrs = append(allErrs, validatePodFailurePolicyRuleOnExitCodes(rule.OnExitCodes, rulePath.Child("onExitCodes"), containerNames)...)
|
||||
}
|
||||
if len(rule.OnPodConditions) > 0 {
|
||||
allErrs = append(allErrs, validatePodFailurePolicyRuleOnPodConditions(rule.OnPodConditions, rulePath.Child("onPodConditions"))...)
|
||||
}
|
||||
if rule.OnExitCodes != nil && len(rule.OnPodConditions) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(rulePath, field.OmitValueType{}, "specifying both OnExitCodes and OnPodConditions is not supported"))
|
||||
}
|
||||
if rule.OnExitCodes == nil && len(rule.OnPodConditions) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(rulePath, field.OmitValueType{}, "specifying one of OnExitCodes and OnPodConditions is required"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePodFailurePolicyRuleOnPodConditions(onPodConditions []batch.PodFailurePolicyOnPodConditionsPattern, onPodConditionsPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if len(onPodConditions) > maxPodFailurePolicyOnPodConditionsPatterns {
|
||||
allErrs = append(allErrs, field.TooMany(onPodConditionsPath, len(onPodConditions), maxPodFailurePolicyOnPodConditionsPatterns))
|
||||
}
|
||||
for j, pattern := range onPodConditions {
|
||||
patternPath := onPodConditionsPath.Index(j)
|
||||
statusPath := patternPath.Child("status")
|
||||
allErrs = append(allErrs, apivalidation.ValidateQualifiedName(string(pattern.Type), patternPath.Child("type"))...)
|
||||
if pattern.Status == "" {
|
||||
allErrs = append(allErrs, field.Required(statusPath, fmt.Sprintf("valid values: %q", supportedPodFailurePolicyOnPodConditionsStatus.List())))
|
||||
} else if !supportedPodFailurePolicyOnPodConditionsStatus.Has(string(pattern.Status)) {
|
||||
allErrs = append(allErrs, field.NotSupported(statusPath, pattern.Status, supportedPodFailurePolicyOnPodConditionsStatus.List()))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePodFailurePolicyRuleOnExitCodes(onExitCode *batch.PodFailurePolicyOnExitCodesRequirement, onExitCodesPath *field.Path, containerNames sets.String) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
operatorPath := onExitCodesPath.Child("operator")
|
||||
if onExitCode.Operator == "" {
|
||||
allErrs = append(allErrs, field.Required(operatorPath, fmt.Sprintf("valid values: %q", supportedPodFailurePolicyOnExitCodesOperator.List())))
|
||||
} else if !supportedPodFailurePolicyOnExitCodesOperator.Has(string(onExitCode.Operator)) {
|
||||
allErrs = append(allErrs, field.NotSupported(operatorPath, onExitCode.Operator, supportedPodFailurePolicyOnExitCodesOperator.List()))
|
||||
}
|
||||
if onExitCode.ContainerName != nil && !containerNames.Has(*onExitCode.ContainerName) {
|
||||
allErrs = append(allErrs, field.Invalid(onExitCodesPath.Child("containerName"), *onExitCode.ContainerName, "must be one of the container or initContainer names in the pod template"))
|
||||
}
|
||||
valuesPath := onExitCodesPath.Child("values")
|
||||
if len(onExitCode.Values) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(valuesPath, onExitCode.Values, "at least one value is required"))
|
||||
} else if len(onExitCode.Values) > maxPodFailurePolicyOnExitCodesValues {
|
||||
allErrs = append(allErrs, field.TooMany(valuesPath, len(onExitCode.Values), maxPodFailurePolicyOnExitCodesValues))
|
||||
}
|
||||
isOrdered := true
|
||||
uniqueValues := sets.NewInt32()
|
||||
for j, exitCodeValue := range onExitCode.Values {
|
||||
valuePath := valuesPath.Index(j)
|
||||
if onExitCode.Operator == batch.PodFailurePolicyOnExitCodesOpIn && exitCodeValue == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(valuePath, exitCodeValue, "must not be 0 for the In operator"))
|
||||
}
|
||||
if uniqueValues.Has(exitCodeValue) {
|
||||
allErrs = append(allErrs, field.Duplicate(valuePath, exitCodeValue))
|
||||
} else {
|
||||
uniqueValues.Insert(exitCodeValue)
|
||||
}
|
||||
if j > 0 && onExitCode.Values[j-1] > exitCodeValue {
|
||||
isOrdered = false
|
||||
}
|
||||
}
|
||||
if !isOrdered {
|
||||
allErrs = append(allErrs, field.Invalid(valuesPath, onExitCode.Values, "must be ordered"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validateJobStatus validates a JobStatus and returns an ErrorList with any errors.
|
||||
func validateJobStatus(status *batch.JobStatus, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
@@ -241,6 +376,7 @@ func ValidateJobSpecUpdate(spec, oldSpec batch.JobSpec, fldPath *field.Path, opt
|
||||
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Selector, oldSpec.Selector, fldPath.Child("selector"))...)
|
||||
allErrs = append(allErrs, validatePodTemplateUpdate(spec, oldSpec, fldPath, opts)...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.CompletionMode, oldSpec.CompletionMode, fldPath.Child("completionMode"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.PodFailurePolicy, oldSpec.PodFailurePolicy, fldPath.Child("podFailurePolicy"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@ package validation
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -80,23 +81,85 @@ func getValidPodTemplateSpecForGenerated(selector *metav1.LabelSelector) api.Pod
|
||||
Labels: selector.MatchLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
InitContainers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateJob(t *testing.T) {
|
||||
validJobObjectMeta := metav1.ObjectMeta{
|
||||
Name: "myjob",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
UID: types.UID("1a2b3c"),
|
||||
}
|
||||
validManualSelector := getValidManualSelector()
|
||||
validPodTemplateSpecForManual := getValidPodTemplateSpecForManual(validManualSelector)
|
||||
validGeneratedSelector := getValidGeneratedSelector()
|
||||
validPodTemplateSpecForGenerated := getValidPodTemplateSpecForGenerated(validGeneratedSelector)
|
||||
validPodTemplateSpecForGeneratedRestartPolicyNever := getValidPodTemplateSpecForGenerated(validGeneratedSelector)
|
||||
validPodTemplateSpecForGeneratedRestartPolicyNever.Spec.RestartPolicy = api.RestartPolicyNever
|
||||
|
||||
successCases := map[string]struct {
|
||||
opts JobValidationOptions
|
||||
job batch.Job
|
||||
}{
|
||||
"valid pod failure policy": {
|
||||
job: batch.Job{
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.PodConditionType("CustomConditionType"),
|
||||
Status: api.ConditionFalse,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionCount,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("def"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{4},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpNotIn,
|
||||
Values: []int32{5, 6, 7},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"valid manual selector": {
|
||||
job: batch.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -185,6 +248,402 @@ func TestValidateJob(t *testing.T) {
|
||||
negative := int32(-1)
|
||||
negative64 := int64(-1)
|
||||
errorCases := map[string]batch.Job{
|
||||
`spec.podFailurePolicy.rules[0]: Invalid value: specifying one of OnExitCodes and OnPodConditions is required`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.values[1]: Duplicate value: 11`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{11, 11},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.values: Too many: 256: must have at most 255 items`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: func() (values []int32) {
|
||||
tooManyValues := make([]int32, maxPodFailurePolicyOnExitCodesValues+1)
|
||||
for i := range tooManyValues {
|
||||
tooManyValues[i] = int32(i)
|
||||
}
|
||||
return tooManyValues
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules: Too many: 21: must have at most 20 items`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: func() []batch.PodFailurePolicyRule {
|
||||
tooManyRules := make([]batch.PodFailurePolicyRule, maxPodFailurePolicyRules+1)
|
||||
for i := range tooManyRules {
|
||||
tooManyRules[i] = batch.PodFailurePolicyRule{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{int32(i + 1)},
|
||||
},
|
||||
}
|
||||
}
|
||||
return tooManyRules
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onPodConditions: Too many: 21: must have at most 20 items`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnPodConditions: func() []batch.PodFailurePolicyOnPodConditionsPattern {
|
||||
tooManyPatterns := make([]batch.PodFailurePolicyOnPodConditionsPattern, maxPodFailurePolicyOnPodConditionsPatterns+1)
|
||||
for i := range tooManyPatterns {
|
||||
tooManyPatterns[i] = batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
Type: api.PodConditionType(fmt.Sprintf("CustomType_%d", i)),
|
||||
Status: api.ConditionTrue,
|
||||
}
|
||||
}
|
||||
return tooManyPatterns
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.values[2]: Duplicate value: 13`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{12, 13, 13, 13},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.values: Invalid value: []int32{19, 11}: must be ordered`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{19, 11},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.values: Invalid value: []int32{}: at least one value is required`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].action: Required value: valid values: ["Count" "FailJob" "Ignore"]`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: "",
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.operator: Required value: valid values: ["In" "NotIn"]`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: "",
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0]: Invalid value: specifying both OnExitCodes and OnPodConditions is not supported`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.values[1]: Invalid value: 0: must not be 0 for the In operator`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 0, 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[1].onExitCodes.containerName: Invalid value: "xyz": must be one of the container or initContainer names in the pod template`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionFailJob,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("xyz"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{5, 6, 7},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].action: Unsupported value: "UnknownAction": supported values: "Count", "FailJob", "Ignore"`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: "UnknownAction",
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
ContainerName: pointer.String("abc"),
|
||||
Operator: batch.PodFailurePolicyOnExitCodesOpIn,
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onExitCodes.operator: Unsupported value: "UnknownOperator": supported values: "In", "NotIn"`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnExitCodes: &batch.PodFailurePolicyOnExitCodesRequirement{
|
||||
Operator: "UnknownOperator",
|
||||
Values: []int32{1, 2, 3},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onPodConditions[0].status: Required value: valid values: ["False" "True" "Unknown"]`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onPodConditions[0].status: Unsupported value: "UnknownStatus": supported values: "False", "True", "Unknown"`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: "UnknownStatus",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onPodConditions[0].type: Invalid value: "": name part must be non-empty`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.podFailurePolicy.rules[0].onPodConditions[0].type: Invalid value: "Invalid Condition Type": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.PodConditionType("Invalid Condition Type"),
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`spec.template.spec.restartPolicy: Invalid value: "OnFailure": only "Never" is supported when podFailurePolicy is specified`: {
|
||||
ObjectMeta: validJobObjectMeta,
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: validGeneratedSelector.MatchLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}},
|
||||
},
|
||||
},
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{},
|
||||
},
|
||||
},
|
||||
},
|
||||
"spec.parallelism:must be greater than or equal to 0": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myjob",
|
||||
@@ -388,6 +847,9 @@ func TestValidateJob(t *testing.T) {
|
||||
func TestValidateJobUpdate(t *testing.T) {
|
||||
validGeneratedSelector := getValidGeneratedSelector()
|
||||
validPodTemplateSpecForGenerated := getValidPodTemplateSpecForGenerated(validGeneratedSelector)
|
||||
validPodTemplateSpecForGeneratedRestartPolicyNever := getValidPodTemplateSpecForGenerated(validGeneratedSelector)
|
||||
validPodTemplateSpecForGeneratedRestartPolicyNever.Spec.RestartPolicy = api.RestartPolicyNever
|
||||
|
||||
validNodeAffinity := &api.Affinity{
|
||||
NodeAffinity: &api.NodeAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||
@@ -491,6 +953,100 @@ func TestValidateJobUpdate(t *testing.T) {
|
||||
Field: "spec.selector",
|
||||
},
|
||||
},
|
||||
"add pod failure policy": {
|
||||
old: batch.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
},
|
||||
},
|
||||
update: func(job *batch.Job) {
|
||||
job.Spec.PodFailurePolicy = &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
err: &field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "spec.podFailurePolicy",
|
||||
},
|
||||
},
|
||||
"remove pod failure policy": {
|
||||
old: batch.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
update: func(job *batch.Job) {
|
||||
job.Spec.PodFailurePolicy.Rules = append(job.Spec.PodFailurePolicy.Rules, batch.PodFailurePolicyRule{
|
||||
Action: batch.PodFailurePolicyActionCount,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
})
|
||||
},
|
||||
err: &field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "spec.podFailurePolicy",
|
||||
},
|
||||
},
|
||||
"update pod failure policy": {
|
||||
old: batch.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
||||
Spec: batch.JobSpec{
|
||||
Selector: validGeneratedSelector,
|
||||
Template: validPodTemplateSpecForGeneratedRestartPolicyNever,
|
||||
PodFailurePolicy: &batch.PodFailurePolicy{
|
||||
Rules: []batch.PodFailurePolicyRule{
|
||||
{
|
||||
Action: batch.PodFailurePolicyActionIgnore,
|
||||
OnPodConditions: []batch.PodFailurePolicyOnPodConditionsPattern{
|
||||
{
|
||||
Type: api.AlphaNoCompatGuaranteeDisruptionTarget,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
update: func(job *batch.Job) {
|
||||
job.Spec.PodFailurePolicy = nil
|
||||
},
|
||||
err: &field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "spec.podFailurePolicy",
|
||||
},
|
||||
},
|
||||
"immutable pod template": {
|
||||
old: batch.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
||||
|
96
pkg/apis/batch/zz_generated.deepcopy.go
generated
96
pkg/apis/batch/zz_generated.deepcopy.go
generated
@@ -252,6 +252,11 @@ func (in *JobSpec) DeepCopyInto(out *JobSpec) {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
if in.PodFailurePolicy != nil {
|
||||
in, out := &in.PodFailurePolicy, &out.PodFailurePolicy
|
||||
*out = new(PodFailurePolicy)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ActiveDeadlineSeconds != nil {
|
||||
in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds
|
||||
*out = new(int64)
|
||||
@@ -387,6 +392,97 @@ func (in *JobTemplateSpec) DeepCopy() *JobTemplateSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PodFailurePolicy) DeepCopyInto(out *PodFailurePolicy) {
|
||||
*out = *in
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PodFailurePolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodFailurePolicy.
|
||||
func (in *PodFailurePolicy) DeepCopy() *PodFailurePolicy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PodFailurePolicy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PodFailurePolicyOnExitCodesRequirement) DeepCopyInto(out *PodFailurePolicyOnExitCodesRequirement) {
|
||||
*out = *in
|
||||
if in.ContainerName != nil {
|
||||
in, out := &in.ContainerName, &out.ContainerName
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = make([]int32, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodFailurePolicyOnExitCodesRequirement.
|
||||
func (in *PodFailurePolicyOnExitCodesRequirement) DeepCopy() *PodFailurePolicyOnExitCodesRequirement {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PodFailurePolicyOnExitCodesRequirement)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PodFailurePolicyOnPodConditionsPattern) DeepCopyInto(out *PodFailurePolicyOnPodConditionsPattern) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodFailurePolicyOnPodConditionsPattern.
|
||||
func (in *PodFailurePolicyOnPodConditionsPattern) DeepCopy() *PodFailurePolicyOnPodConditionsPattern {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PodFailurePolicyOnPodConditionsPattern)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PodFailurePolicyRule) DeepCopyInto(out *PodFailurePolicyRule) {
|
||||
*out = *in
|
||||
if in.OnExitCodes != nil {
|
||||
in, out := &in.OnExitCodes, &out.OnExitCodes
|
||||
*out = new(PodFailurePolicyOnExitCodesRequirement)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.OnPodConditions != nil {
|
||||
in, out := &in.OnPodConditions, &out.OnPodConditions
|
||||
*out = make([]PodFailurePolicyOnPodConditionsPattern, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodFailurePolicyRule.
|
||||
func (in *PodFailurePolicyRule) DeepCopy() *PodFailurePolicyRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PodFailurePolicyRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UncountedTerminatedPods) DeepCopyInto(out *UncountedTerminatedPods) {
|
||||
*out = *in
|
||||
|
Reference in New Issue
Block a user