Skip to content

Commit

Permalink
Add Custom Scheduler Name to Build and BuildRun objects
Browse files Browse the repository at this point in the history
Signed-off-by: Dylan Orzel <dorzel@redhat.com>
  • Loading branch information
dorzel committed Feb 4, 2025
1 parent cd2da9f commit f1375b6
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 38 deletions.
12 changes: 12 additions & 0 deletions deploy/crds/shipwright.io_buildruns.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7439,6 +7439,10 @@ spec:
format: duration
type: string
type: object
schedulerName:
description: SchedulerName specifies the scheduler to be used
to dispatch the Pod
type: string
source:
description: |-
Source refers to the location where the source code is,
Expand Down Expand Up @@ -9753,6 +9757,10 @@ spec:
format: duration
type: string
type: object
schedulerName:
description: SchedulerName specifies the scheduler to be used to dispatch
the Pod
type: string
serviceAccount:
description: |-
ServiceAccount refers to the kubernetes serviceaccount
Expand Down Expand Up @@ -11941,6 +11949,10 @@ spec:
format: duration
type: string
type: object
schedulerName:
description: SchedulerName specifies the scheduler to be used
to dispatch the Pod
type: string
source:
description: |-
Source refers to the location where the source code is,
Expand Down
4 changes: 4 additions & 0 deletions deploy/crds/shipwright.io_builds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2818,6 +2818,10 @@ spec:
format: duration
type: string
type: object
schedulerName:
description: SchedulerName specifies the scheduler to be used to dispatch
the Pod
type: string
source:
description: |-
Source refers to the location where the source code is,
Expand Down
7 changes: 6 additions & 1 deletion pkg/apis/build/v1beta1/build_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ const (
NodeSelectorNotValid BuildReason = "NodeSelectorNotValid"
// TolerationNotValid indicates that the Toleration value is not valid
TolerationNotValid BuildReason = "TolerationNotValid"

// SchedulerNameNotValid indicates that the Scheduler name is not valid
SchedulerNameNotValid BuildReason = "SchedulerNameNotValid"
// AllValidationsSucceeded indicates a Build was successfully validated
AllValidationsSucceeded = "all validations succeeded"
)
Expand Down Expand Up @@ -191,6 +192,10 @@ type BuildSpec struct {
// +patchMergeKey=Key
// +patchStrategy=merge
Tolerations []corev1.Toleration `json:"tolerations,omitempty" patchStrategy:"merge" patchMergeKey:"Key"`

// SchedulerName specifies the scheduler to be used to dispatch the Pod
// +optional
SchedulerName string `json:"schedulerName,omitempty"`
}

// BuildVolume is a volume that will be mounted in build pod during build step
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/build/v1beta1/buildrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ type BuildRunSpec struct {
// +patchMergeKey=Key
// +patchStrategy=merge
Tolerations []corev1.Toleration `json:"tolerations,omitempty" patchStrategy:"merge" patchMergeKey:"Key"`

// SchedulerName specifies the scheduler to be used to dispatch the Pod
// +optional
SchedulerName string `json:"schedulerName,omitempty"`
}

// BuildRunRequestedState defines the buildrun state the user can provide to override whatever is the current state.
Expand Down
1 change: 1 addition & 0 deletions pkg/reconciler/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var validationTypes = [...]string{
validate.Triggers,
validate.NodeSelector,
validate.Tolerations,
validate.SchedulerName,
}

// ReconcileBuild reconciles a Build object
Expand Down
10 changes: 10 additions & 0 deletions pkg/reconciler/buildrun/buildrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ func (r *ReconcileBuildRun) Reconcile(ctx context.Context, request reconcile.Req
validate.NewEnv(build),
validate.NewNodeSelector(build),
validate.NewTolerations(build),
validate.NewSchedulerName(build),
)

// an internal/technical error during validation happened
Expand Down Expand Up @@ -310,6 +311,15 @@ func (r *ReconcileBuildRun) Reconcile(ctx context.Context, request reconcile.Req
return reconcile.Result{}, nil
}

// Validate the schedulerName
valid, reason, message = validate.BuildRunSchedulerName(buildRun.Spec.SchedulerName)
if !valid {
if err := resources.UpdateConditionWithFalseStatus(ctx, r.client, buildRun, message, reason); err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{}, nil
}

// Create the TaskRun, this needs to be the last step in this block to be idempotent
generatedTaskRun, err := r.createTaskRun(ctx, svcAccount, strategy, build, buildRun)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions pkg/reconciler/buildrun/resources/taskrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,15 @@ func GenerateTaskRun(
taskRunPodTemplate.Tolerations = taskRunTolerations
}

// Set custom scheduler name if specified, giving preference to BuildRun values
if buildRun.Spec.SchedulerName != "" {
taskRunPodTemplate.SchedulerName = buildRun.Spec.SchedulerName
} else {
if build.Spec.SchedulerName != "" {
taskRunPodTemplate.SchedulerName = build.Spec.SchedulerName
}
}

if !(taskRunPodTemplate.Equals(&pod.PodTemplate{})) {
expectedTaskRun.Spec.PodTemplate = taskRunPodTemplate
}
Expand Down
14 changes: 4 additions & 10 deletions pkg/validate/nodeselector.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,11 @@ func NewNodeSelector(build *build.Build) *NodeSelectorRef {
// ValidatePath implements BuildPath interface and validates
// that NodeSelector keys/values are valid labels
func (b *NodeSelectorRef) ValidatePath(_ context.Context) error {
for key, value := range b.Build.Spec.NodeSelector {
if errs := validation.IsQualifiedName(key); len(errs) > 0 {
b.Build.Status.Reason = ptr.To(build.NodeSelectorNotValid)
b.Build.Status.Message = ptr.To(fmt.Sprintf("Node selector key not valid: %v", strings.Join(errs, ", ")))
}
if errs := validation.IsValidLabelValue(value); len(errs) > 0 {
b.Build.Status.Reason = ptr.To(build.NodeSelectorNotValid)
b.Build.Status.Message = ptr.To(fmt.Sprintf("Node selector value not valid: %v", strings.Join(errs, ", ")))
}
ok, reason, msg := BuildRunNodeSelector(b.Build.Spec.NodeSelector)
if !ok {
b.Build.Status.Reason = ptr.To(build.BuildReason(reason))
b.Build.Status.Message = ptr.To(msg)
}

return nil
}

Expand Down
47 changes: 47 additions & 0 deletions pkg/validate/scheduler_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package validate

import (
"context"
"fmt"
"strings"

"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/utils/ptr"

build "github.com/shipwright-io/build/pkg/apis/build/v1beta1"
)

// SchedulerNameRef contains all required fields
// to validate a Scheduler name
type SchedulerNameRef struct {
Build *build.Build // build instance for analysis
}

func NewSchedulerName(build *build.Build) *SchedulerNameRef {
return &SchedulerNameRef{build}
}

// ValidatePath implements BuildPath interface and validates
// that SchedulerName values are valid
func (b *SchedulerNameRef) ValidatePath(_ context.Context) error {
ok, reason, msg := BuildRunSchedulerName(b.Build.Spec.SchedulerName)
if !ok {
b.Build.Status.Reason = ptr.To(build.BuildReason(reason))
b.Build.Status.Message = ptr.To(msg)
}
return nil
}

// BuildSchedulerName is used to validate the schedulerName in the BuildRun object
func BuildRunSchedulerName(schedulerName string) (bool, string, string) {
if schedulerName != "" {
if errs := validation.IsQualifiedName(schedulerName); len(errs) > 0 {
return false, string(build.SchedulerNameNotValid), fmt.Sprintf("Scheduler name not valid: %v", strings.Join(errs, ", "))
}
}
return true, "", ""
}
31 changes: 4 additions & 27 deletions pkg/validate/tolerations.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,34 +29,11 @@ func NewTolerations(build *build.Build) *TolerationsRef {
// ValidatePath implements BuildPath interface and validates
// that tolerations key/operator/value are valid
func (b *TolerationsRef) ValidatePath(_ context.Context) error {
for _, toleration := range b.Build.Spec.Tolerations {
// validate Key
if errs := validation.IsQualifiedName(toleration.Key); errs != nil {
b.Build.Status.Reason = ptr.To(build.TolerationNotValid)
b.Build.Status.Message = ptr.To(fmt.Sprintf("Toleration key not valid: %v", strings.Join(errs, ", ")))
}
// validate Operator
if !((toleration.Operator == v1.TolerationOpExists) || (toleration.Operator == v1.TolerationOpEqual)) {
b.Build.Status.Reason = ptr.To(build.TolerationNotValid)
b.Build.Status.Message = ptr.To(fmt.Sprintf("Toleration operator not valid. Must be one of: '%v', '%v'", v1.TolerationOpExists, v1.TolerationOpEqual))
}
// validate Value
if errs := validation.IsValidLabelValue(toleration.Value); errs != nil {
b.Build.Status.Reason = ptr.To(build.TolerationNotValid)
b.Build.Status.Message = ptr.To(fmt.Sprintf("Toleration value not valid: %v", strings.Join(errs, ", ")))
}
// validate Taint Effect, of which only "NoSchedule" is supported
if !((toleration.Effect) == "" || (toleration.Effect == v1.TaintEffectNoSchedule)) {
b.Build.Status.Reason = ptr.To(build.TolerationNotValid)
b.Build.Status.Message = ptr.To(fmt.Sprintf("Only the '%v' toleration effect is supported.", v1.TaintEffectNoSchedule))
}
// validate TolerationSeconds, which should not be specified
if toleration.TolerationSeconds != nil {
b.Build.Status.Reason = ptr.To(build.TolerationNotValid)
b.Build.Status.Message = ptr.To("Specifying TolerationSeconds is not supported.")
}
ok, reason, msg := BuildRunTolerations(b.Build.Spec.Tolerations)
if !ok {
b.Build.Status.Reason = ptr.To(build.BuildReason(reason))
b.Build.Status.Message = ptr.To(msg)
}

return nil
}

Expand Down
9 changes: 9 additions & 0 deletions pkg/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const (
NodeSelector = "nodeselector"
// Tolerations for validating `spec.tolerations` entry
Tolerations = "tolerations"
// SchedulerName for validating `spec.schedulerName` entry
SchedulerName = "schedulername"
)

const (
Expand Down Expand Up @@ -83,6 +85,8 @@ func NewValidation(
return &NodeSelectorRef{Build: build}, nil
case Tolerations:
return &TolerationsRef{Build: build}, nil
case SchedulerName:
return &SchedulerNameRef{Build: build}, nil
default:
return nil, fmt.Errorf("unknown validation type")
}
Expand Down Expand Up @@ -147,6 +151,11 @@ func BuildRunFields(buildRun *build.BuildRun) (string, string) {
return resources.BuildRunBuildFieldOverrideForbidden,
"cannot use 'tolerations' override and 'buildSpec' simultaneously"
}

if len(buildRun.Spec.SchedulerName) > 0 {
return resources.BuildRunBuildFieldOverrideForbidden,
"cannot use 'schedulerName' override and 'buildSpec' simultaneously"
}
}

return "", ""
Expand Down

0 comments on commit f1375b6

Please sign in to comment.