Skip to content

Commit

Permalink
jobset startup policy implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
kannon92 committed Aug 18, 2023
1 parent b0dfb42 commit 234a87b
Show file tree
Hide file tree
Showing 47 changed files with 2,119 additions and 30 deletions.
38 changes: 38 additions & 0 deletions api/jobset/v1alpha2/jobset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ type JobSetSpec struct {
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
FailurePolicy *FailurePolicy `json:"failurePolicy,omitempty"`

// StartupPolicy, if set, configures in what order jobs must be started
// The targed status of each job is also configurable.
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
StartupPolicy *StartupPolicy `json:"startupPolicy,omitempty"`

// Suspend suspends all running child Jobs when set to true.
Suspend *bool `json:"suspend,omitempty"`
}
Expand Down Expand Up @@ -95,6 +100,7 @@ type ReplicatedJobStatus struct {
Succeeded int32 `json:"succeeded"`
Failed int32 `json:"failed"`
Active int32 `json:"active"`
Suspended int32 `json:"suspended"`
}

// +genclient
Expand Down Expand Up @@ -177,6 +183,38 @@ type SuccessPolicy struct {
TargetReplicatedJobs []string `json:"targetReplicatedJobs,omitempty"`
}

// Status string
type Status string

const (
// Ready means that the job is ready
Ready Status = "Ready"

// Succeeded means that the job was successful
Succeeded Status = "Succeeded"
)

type StartupPolicy struct {
// TargetReplicatedJobStatuses is a list of rules for applying StartupPolicy.
// +optional
// +listType=map
// +listMapKey=name
TargetReplicatedJobStatuses []TargetReplicatedJobStartup `json:"targetReplicatedJobStatuses,omitempty"`
}

type TargetReplicatedJobStartup struct {
// Name of ReplicatedJob to apply startup policy
Name string `json:"name"`

// The status you want the ReplicatedJob to be
// +kubebuilder:validation:Enum=Ready;Succeeded
Status Status `json:"status"`

// Number of Statuses is how many ReplicatedJob statuses to consider "started"
// Empty will mean all status must match the replicas.
NumberOfStatuses int32 `json:"numberOfStatuses,omitempty"`
}

func init() {
SchemeBuilder.Register(&JobSet{}, &JobSetList{})
}
10 changes: 10 additions & 0 deletions api/jobset/v1alpha2/jobset_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ func (js *JobSet) ValidateCreate() (admission.Warnings, error) {
allErrs = append(allErrs, fmt.Errorf("invalid replicatedJob name '%s' does not appear in .spec.ReplicatedJobs", rjobName))
}
}
if js.Spec.StartupPolicy != nil {
for _, rJobName := range js.Spec.StartupPolicy.TargetReplicatedJobStatuses {
if !util.Contains(validReplicatedJobs, rJobName.Name) {
allErrs = append(allErrs, fmt.Errorf("invalid replicatedJob name '%s' does not appear in .specReplicatedJobs", rJobName.Name))
}
}
if len(js.Spec.StartupPolicy.TargetReplicatedJobStatuses) > len(validReplicatedJobs) {
allErrs = append(allErrs, fmt.Errorf("The length of TargetReplicatedJobStatuses '%d' should not exceed length of valid replicated jobs '%d'", len(js.Spec.StartupPolicy.TargetReplicatedJobStatuses), len(validReplicatedJobs)))
}
}
return nil, errors.Join(allErrs...)
}

Expand Down
65 changes: 65 additions & 0 deletions api/jobset/v1alpha2/jobset_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,71 @@ func TestValidateCreate(t *testing.T) {
fmt.Errorf("must be no more than 253 characters"),
),
},
{
name: "StartupPolicy Replicated Job does not match any",
js: &JobSet{
Spec: JobSetSpec{
SuccessPolicy: &SuccessPolicy{},
ReplicatedJobs: []ReplicatedJob{
{
Name: "test-jobset-replicated-job-0",
Replicas: 1,
Template: batchv1.JobTemplateSpec{
Spec: batchv1.JobSpec{},
},
},
{
Name: "test-jobset-replicated-job-1",
Replicas: 1,
Template: batchv1.JobTemplateSpec{
Spec: batchv1.JobSpec{},
},
},
},
StartupPolicy: &StartupPolicy{
TargetReplicatedJobStatuses: []TargetReplicatedJobStartup{{
Name: "no-exist",
Status: Succeeded,
}},
},
},
},
want: errors.Join(
fmt.Errorf("invalid replicatedJob name 'no-exist' does not appear in .specReplicatedJobs"),
),
},
{
name: "TargetReplicatedJobStatuses should not be greater length than ReplicatedJobs",
js: &JobSet{
Spec: JobSetSpec{
SuccessPolicy: &SuccessPolicy{},
ReplicatedJobs: []ReplicatedJob{
{
Name: "test-jobset-replicated-job-0",
Replicas: 1,
Template: batchv1.JobTemplateSpec{
Spec: batchv1.JobSpec{},
},
},
},
StartupPolicy: &StartupPolicy{
TargetReplicatedJobStatuses: []TargetReplicatedJobStartup{
{
Name: "test-jobset-replicated-job-0",
Status: Succeeded,
},
{
Name: "test-jobset-replicated-job-0",
Status: Succeeded,
},
},
},
},
},
want: errors.Join(
fmt.Errorf("The length of TargetReplicatedJobStatuses '2' should not exceed length of valid replicated jobs '1'"),
),
},
}

for _, tc := range testCases {
Expand Down
109 changes: 98 additions & 11 deletions api/jobset/v1alpha2/openapi_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions api/jobset/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions client-go/applyconfiguration/jobset/v1alpha2/jobsetspec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 234a87b

Please sign in to comment.