From 00729c9594e45704f68a6326ff0eb252942ec2df Mon Sep 17 00:00:00 2001 From: rxinui Date: Mon, 21 Apr 2025 16:50:57 +0200 Subject: [PATCH 1/3] new: add --scheduler-name to build and buildrun - test: add go test and bats tests - ref: harmonise tab/spaces in bats tests Signed-off-by: rxinui --- docs/shp_build_create.md | 1 + docs/shp_build_run.md | 1 + docs/shp_build_upload.md | 1 + docs/shp_buildrun_create.md | 1 + pkg/shp/flags/build.go | 4 +- pkg/shp/flags/build_test.go | 10 ++- pkg/shp/flags/buildrun.go | 4 +- pkg/shp/flags/buildrun_test.go | 10 ++- pkg/shp/flags/flags.go | 12 +++ test/e2e/node-selector.bats | 135 ++++++++++++++++++++++++--------- 10 files changed, 138 insertions(+), 41 deletions(-) diff --git a/docs/shp_build_create.md b/docs/shp_build_create.md index d77966c84..784536608 100644 --- a/docs/shp_build_create.md +++ b/docs/shp_build_create.md @@ -30,6 +30,7 @@ shp build create [flags] --retention-succeeded-limit uint number of succeeded BuildRuns to be kept (default 65535) --retention-ttl-after-failed duration duration to delete a failed BuildRun after completion --retention-ttl-after-succeeded duration duration to delete a succeeded BuildRun after completion + --scheduler-name string specify the scheduler to be used to dispatch the Pod --source-context-dir string use a inner directory as context directory --source-git-clone-secret string name of the secret with credentials to access the git source, e.g. git credentials --source-git-revision string git repository source revision diff --git a/docs/shp_build_run.md b/docs/shp_build_run.md index bcec5fa72..7c5d51dfc 100644 --- a/docs/shp_build_run.md +++ b/docs/shp_build_run.md @@ -32,6 +32,7 @@ shp build run [flags] --retention-ttl-after-failed duration duration to delete the BuildRun after it failed --retention-ttl-after-succeeded duration duration to delete the BuildRun after it succeeded --sa-name string Kubernetes service-account name + --scheduler-name string specify the scheduler to be used to dispatch the Pod --timeout duration build process timeout ``` diff --git a/docs/shp_build_upload.md b/docs/shp_build_upload.md index befdcfe25..ae8967cbf 100644 --- a/docs/shp_build_upload.md +++ b/docs/shp_build_upload.md @@ -42,6 +42,7 @@ shp build upload [path/to/source|.] [flags] --retention-ttl-after-failed duration duration to delete the BuildRun after it failed --retention-ttl-after-succeeded duration duration to delete the BuildRun after it succeeded --sa-name string Kubernetes service-account name + --scheduler-name string specify the scheduler to be used to dispatch the Pod --timeout duration build process timeout ``` diff --git a/docs/shp_buildrun_create.md b/docs/shp_buildrun_create.md index 0cdcc6ded..550b57f88 100644 --- a/docs/shp_buildrun_create.md +++ b/docs/shp_buildrun_create.md @@ -31,6 +31,7 @@ shp buildrun create [flags] --retention-ttl-after-failed duration duration to delete the BuildRun after it failed --retention-ttl-after-succeeded duration duration to delete the BuildRun after it succeeded --sa-name string Kubernetes service-account name + --scheduler-name string specify the scheduler to be used to dispatch the Pod --timeout duration build process timeout ``` diff --git a/pkg/shp/flags/build.go b/pkg/shp/flags/build.go index 4b6b2cb67..80246d6b4 100644 --- a/pkg/shp/flags/build.go +++ b/pkg/shp/flags/build.go @@ -44,7 +44,8 @@ func BuildSpecFromFlags(flags *pflag.FlagSet) (*buildv1beta1.BuildSpec, *string, TTLAfterFailed: &metav1.Duration{}, TTLAfterSucceeded: &metav1.Duration{}, }, - NodeSelector: map[string]string{}, + NodeSelector: map[string]string{}, + SchedulerName: ptr.To(""), } sourceFlags(flags, spec.Source) @@ -57,6 +58,7 @@ func BuildSpecFromFlags(flags *pflag.FlagSet) (*buildv1beta1.BuildSpec, *string, imageAnnotationsFlags(flags, spec.Output.Annotations) buildRetentionFlags(flags, spec.Retention) buildNodeSelectorFlags(flags, spec.NodeSelector) + buildSchedulerNameFlag(flags, spec.SchedulerName) var dockerfile, builderImage string dockerfileFlags(flags, &dockerfile) builderImageFlag(flags, &builderImage) diff --git a/pkg/shp/flags/build_test.go b/pkg/shp/flags/build_test.go index 1c351b529..1ed34f90a 100644 --- a/pkg/shp/flags/build_test.go +++ b/pkg/shp/flags/build_test.go @@ -55,7 +55,8 @@ func TestBuildSpecFromFlags(t *testing.T) { Duration: 30 * time.Minute, }, }, - NodeSelector: map[string]string{"kubernetes.io/hostname": "worker-1"}, + NodeSelector: map[string]string{"kubernetes.io/hostname": "worker-1"}, + SchedulerName: ptr.To("dolphinscheduler"), } cmd := &cobra.Command{} @@ -123,6 +124,13 @@ func TestBuildSpecFromFlags(t *testing.T) { g.Expect(expected.NodeSelector).To(o.Equal(spec.NodeSelector), ".spec.nodeSelector") }) + t.Run(".spec.schedulerName", func(_ *testing.T) { + err := flags.Set(SchedulerNameFlag, *expected.SchedulerName) + g.Expect(err).To(o.BeNil()) + + g.Expect(expected.SchedulerName).To(o.Equal(spec.SchedulerName), "spec.schedulerName") + }) + t.Run(".spec.timeout", func(_ *testing.T) { err := flags.Set(TimeoutFlag, expected.Timeout.Duration.String()) g.Expect(err).To(o.BeNil()) diff --git a/pkg/shp/flags/buildrun.go b/pkg/shp/flags/buildrun.go index 30459a8a5..7109c140e 100644 --- a/pkg/shp/flags/buildrun.go +++ b/pkg/shp/flags/buildrun.go @@ -28,7 +28,8 @@ func BuildRunSpecFromFlags(flags *pflag.FlagSet) *buildv1beta1.BuildRunSpec { TTLAfterFailed: &metav1.Duration{}, TTLAfterSucceeded: &metav1.Duration{}, }, - NodeSelector: map[string]string{}, + NodeSelector: map[string]string{}, + SchedulerName: ptr.To(""), } buildRefFlags(flags, &spec.Build) @@ -41,6 +42,7 @@ func BuildRunSpecFromFlags(flags *pflag.FlagSet) *buildv1beta1.BuildRunSpec { imageAnnotationsFlags(flags, spec.Output.Annotations) buildRunRetentionFlags(flags, spec.Retention) buildNodeSelectorFlags(flags, spec.NodeSelector) + buildSchedulerNameFlag(flags, spec.SchedulerName) return spec } diff --git a/pkg/shp/flags/buildrun_test.go b/pkg/shp/flags/buildrun_test.go index 073a91f1d..494be4bbc 100644 --- a/pkg/shp/flags/buildrun_test.go +++ b/pkg/shp/flags/buildrun_test.go @@ -38,7 +38,8 @@ func TestBuildRunSpecFromFlags(t *testing.T) { Duration: 30 * time.Minute, }, }, - NodeSelector: map[string]string{"kubernetes.io/hostname": "worker-1"}, + NodeSelector: map[string]string{"kubernetes.io/hostname": "worker-1"}, + SchedulerName: ptr.To("dolphinscheduler"), } cmd := &cobra.Command{} @@ -83,6 +84,13 @@ func TestBuildRunSpecFromFlags(t *testing.T) { g.Expect(expected.NodeSelector).To(o.Equal(spec.NodeSelector), ".spec.nodeSelector") }) + t.Run(".spec.schedulerName", func(_ *testing.T) { + err := flags.Set(SchedulerNameFlag, *expected.SchedulerName) + g.Expect(err).To(o.BeNil()) + + g.Expect(expected.SchedulerName).To(o.Equal(spec.SchedulerName), "spec.schedulerName") + }) + t.Run(".spec.retention.ttlAfterFailed", func(_ *testing.T) { err := flags.Set(RetentionTTLAfterFailedFlag, expected.Retention.TTLAfterFailed.Duration.String()) g.Expect(err).To(o.BeNil()) diff --git a/pkg/shp/flags/flags.go b/pkg/shp/flags/flags.go index 35249073c..90dd7e2c0 100644 --- a/pkg/shp/flags/flags.go +++ b/pkg/shp/flags/flags.go @@ -66,6 +66,8 @@ const ( RetentionTTLAfterSucceededFlag = "retention-ttl-after-succeeded" // NodeSelectorFlag command-line flag. NodeSelectorFlag = "node-selector" + // SchedulerNameFlag command-line flag. + SchedulerNameFlag = "scheduler-name" ) // sourceFlags flags for ".spec.source" @@ -266,6 +268,16 @@ func buildNodeSelectorFlags(flags *pflag.FlagSet, nodeSelectorLabels map[string] flags.Var(NewMapValue(nodeSelectorLabels), NodeSelectorFlag, "set of key-value pairs that correspond to labels of a node to match") } +// buildSchedulerNameFlag registers flags for adding BuildSpec.SchedulerName +func buildSchedulerNameFlag(flags *pflag.FlagSet, schedulerName *string) { + flags.StringVar( + schedulerName, + SchedulerNameFlag, + "", + "specify the scheduler to be used to dispatch the Pod", + ) +} + // envFlags registers flags for adding corev1.EnvVars. func envFlags(flags *pflag.FlagSet, envs *[]corev1.EnvVar) { flags.VarP( diff --git a/test/e2e/node-selector.bats b/test/e2e/node-selector.bats index cfcf868d8..5896814ef 100644 --- a/test/e2e/node-selector.bats +++ b/test/e2e/node-selector.bats @@ -3,112 +3,173 @@ source test/e2e/helpers.sh setup() { - load 'bats/support/load' - load 'bats/assert/load' - load 'bats/file/load' + load 'bats/support/load' + load 'bats/assert/load' + load 'bats/file/load' } teardown() { - run kubectl delete builds.shipwright.io --all - run kubectl delete buildruns.shipwright.io --all + run kubectl delete builds.shipwright.io --all + run kubectl delete buildruns.shipwright.io --all } +scheduler_name="dolphinscheduler" + @test "shp build create --node-selector single label" { # generate random names for our build - build_name=$(random_name) + build_name=$(random_name) - # create a Build with node selector + # create a Build with node selector run shp build create ${build_name} --source-git-url=https://github.com/shipwright-io/sample-go --output-image=my-fake-image --node-selector="kubernetes.io/hostname=node-1" assert_success # ensure that the build was successfully created - assert_output --partial "Created build \"${build_name}\"" + assert_output --partial "Created build \"${build_name}\"" # get the jsonpath of Build object .spec.nodeSelector - run kubectl get builds.shipwright.io/${build_name} -ojsonpath="{.spec.nodeSelector}" - assert_success + run kubectl get builds.shipwright.io/${build_name} -ojsonpath="{.spec.nodeSelector}" + assert_success assert_output '{"kubernetes.io/hostname":"node-1"}' } @test "shp build create --node-selector multiple labels" { # generate random names for our build - build_name=$(random_name) + build_name=$(random_name) - # create a Build with node selector - run shp build create ${build_name} --source-git-url=https://github.com/shipwright-io/sample-go --output-image=my-fake-image --node-selector="kubernetes.io/hostname=node-1" --node-selector="kubernetes.io/os=linux" + # create a Build with node selector + run shp build create ${build_name} --source-git-url=https://github.com/shipwright-io/sample-go --output-image=my-fake-image --node-selector="kubernetes.io/hostname=node-1" --node-selector="kubernetes.io/os=linux" assert_success # ensure that the build was successfully created - assert_output --partial "Created build \"${build_name}\"" + assert_output --partial "Created build \"${build_name}\"" # get the jsonpath of Build object .spec.nodeSelector - run kubectl get builds.shipwright.io/${build_name} -ojsonpath="{.spec.nodeSelector}" - assert_success + run kubectl get builds.shipwright.io/${build_name} -ojsonpath="{.spec.nodeSelector}" + assert_success assert_output --partial '"kubernetes.io/hostname":"node-1"' assert_output --partial '"kubernetes.io/os":"linux"' } +@test "shp build create --scheduler-name" { + # generate random names for our build + build_name=$(random_name) + + # create a Build with node selector + run shp build create ${build_name} --source-git-url=https://github.com/shipwright-io/sample-go --output-image=my-fake-image --scheduler-name=${scheduler_name} + assert_success + + # ensure that the build was successfully created + assert_output --partial "Created build \"${build_name}\"" + + # get the jsonpath of Build object .spec.nodeSelector + run kubectl get builds.shipwright.io/${build_name} -ojsonpath="{.spec.schedulerName}" + assert_success + + assert_output "${scheduler_name}" +} + @test "shp buildrun create --node-selector single label" { # generate random names for our buildrun - buildrun_name=$(random_name) - build_name=$(random_name) + buildrun_name=$(random_name) + build_name=$(random_name) - # create a Build with node selector + # create a Build with node selector run shp buildrun create ${buildrun_name} --buildref-name=${build_name} --node-selector="kubernetes.io/hostname=node-1" assert_success # ensure that the build was successfully created - assert_output --partial "BuildRun created \"${buildrun_name}\" for Build \"${build_name}\"" + assert_output --partial "BuildRun created \"${buildrun_name}\" for Build \"${build_name}\"" # get the jsonpath of Build object .spec.nodeSelector - run kubectl get buildruns.shipwright.io/${buildrun_name} -ojsonpath="{.spec.nodeSelector}" - assert_success + run kubectl get buildruns.shipwright.io/${buildrun_name} -ojsonpath="{.spec.nodeSelector}" + assert_success assert_output '{"kubernetes.io/hostname":"node-1"}' } @test "shp buildrun create --node-selector multiple labels" { # generate random names for our buildrun - buildrun_name=$(random_name) - build_name=$(random_name) + buildrun_name=$(random_name) + build_name=$(random_name) - # create a Build with node selector - run shp buildrun create ${buildrun_name} --buildref-name=${build_name} --node-selector="kubernetes.io/hostname=node-1" --node-selector="kubernetes.io/os=linux" + # create a Build with node selector + run shp buildrun create ${buildrun_name} --buildref-name=${build_name} --node-selector="kubernetes.io/hostname=node-1" --node-selector="kubernetes.io/os=linux" assert_success # ensure that the build was successfully created - assert_output --partial "BuildRun created \"${buildrun_name}\" for Build \"${build_name}\"" + assert_output --partial "BuildRun created \"${buildrun_name}\" for Build \"${build_name}\"" # get the jsonpath of Build object .spec.nodeSelector - run kubectl get buildruns.shipwright.io/${buildrun_name} -ojsonpath="{.spec.nodeSelector}" - assert_success + run kubectl get buildruns.shipwright.io/${buildrun_name} -ojsonpath="{.spec.nodeSelector}" + assert_success assert_output --partial '"kubernetes.io/hostname":"node-1"' assert_output --partial '"kubernetes.io/os":"linux"' } +@test "shp buildrun create --scheduler-name" { + # generate random names for our buildrun + buildrun_name=$(random_name) + build_name=$(random_name) + + # create a Build with node selector + run shp buildrun create ${buildrun_name} --buildref-name=${build_name} --scheduler-name=${scheduler_name} + assert_success + + # ensure that the build was successfully created + assert_output --partial "BuildRun created \"${buildrun_name}\" for Build \"${build_name}\"" + + # get the jsonpath of Build object .spec.nodeSelector + run kubectl get buildruns.shipwright.io/${buildrun_name} -ojsonpath="{.spec.schedulerName}" + assert_success + + assert_output "${scheduler_name}" +} @test "shp build run --node-selector set" { # generate random names for our build - build_name=$(random_name) + build_name=$(random_name) - # create a Build with node selector + # create a Build with node selector run shp build create ${build_name} --source-git-url=https://github.com/shipwright-io/sample-go --output-image=my-fake-image assert_success # ensure that the build was successfully created - assert_output --partial "Created build \"${build_name}\"" + assert_output --partial "Created build \"${build_name}\"" # get the build object - run kubectl get builds.shipwright.io/${build_name} - assert_success + run kubectl get builds.shipwright.io/${build_name} + assert_success run shp build run ${build_name} --node-selector="kubernetes.io/hostname=node-1" # get the jsonpath of Build object .spec.nodeSelector - run kubectl get buildruns.shipwright.io -ojsonpath='{.items[*].spec.nodeSelector}' - assert_success + run kubectl get buildruns.shipwright.io -ojsonpath='{.items[*].spec.nodeSelector}' + assert_success assert_output --partial '"kubernetes.io/hostname":"node-1"' -} \ No newline at end of file +} + +@test "shp build run --scheduler-name" { + # generate random names for our build + build_name=$(random_name) + + # create a Build with node selector + run shp build create ${build_name} --source-git-url=https://github.com/shipwright-io/sample-go --output-image=my-fake-image + assert_success + + # ensure that the build was successfully created + assert_output --partial "Created build \"${build_name}\"" + + # get the build object + run kubectl get builds.shipwright.io/${build_name} + assert_success + + run shp build run ${build_name} --scheduler-name=${scheduler_name} + + # get the jsonpath of BuildRun object .spec.schedulerName + run kubectl get buildruns.shipwright.io -l build.shipwright.io/name=${build_name} -ojsonpath='{.spec.schedulerName}' + assert_success + assert_output --partial "${scheduler_name}" +} From a4e6cf03282d2e0499e3002eeebabfd570a0973b Mon Sep 17 00:00:00 2001 From: rxinui Date: Thu, 8 May 2025 23:18:40 +0200 Subject: [PATCH 2/3] fix: sanitize schedulerName flag for build buildrun Signed-off-by: rxinui --- pkg/shp/flags/build.go | 3 +++ pkg/shp/flags/buildrun.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/pkg/shp/flags/build.go b/pkg/shp/flags/build.go index 80246d6b4..b1b7ff47d 100644 --- a/pkg/shp/flags/build.go +++ b/pkg/shp/flags/build.go @@ -136,4 +136,7 @@ func SanitizeBuildSpec(b *buildv1beta1.BuildSpec) { b.Retention = nil } } + if b.SchedulerName != nil && *b.SchedulerName == "" { + b.SchedulerName = nil + } } diff --git a/pkg/shp/flags/buildrun.go b/pkg/shp/flags/buildrun.go index 7109c140e..2ce262ab0 100644 --- a/pkg/shp/flags/buildrun.go +++ b/pkg/shp/flags/buildrun.go @@ -86,4 +86,7 @@ func SanitizeBuildRunSpec(br *buildv1beta1.BuildRunSpec) { br.Retention = nil } } + if br.SchedulerName != nil && *br.SchedulerName == "" { + br.SchedulerName = nil + } } From 5ea8ae179043b4be2f9c6c8455e94d11e9b490f4 Mon Sep 17 00:00:00 2001 From: rxinui Date: Fri, 9 May 2025 15:24:32 +0200 Subject: [PATCH 3/3] fix: bats test jsonpath Signed-off-by: rxinui --- test/e2e/node-selector.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/node-selector.bats b/test/e2e/node-selector.bats index 5896814ef..ea567d7f0 100644 --- a/test/e2e/node-selector.bats +++ b/test/e2e/node-selector.bats @@ -169,7 +169,7 @@ scheduler_name="dolphinscheduler" run shp build run ${build_name} --scheduler-name=${scheduler_name} # get the jsonpath of BuildRun object .spec.schedulerName - run kubectl get buildruns.shipwright.io -l build.shipwright.io/name=${build_name} -ojsonpath='{.spec.schedulerName}' + run kubectl get buildruns.shipwright.io -l build.shipwright.io/name=${build_name} -ojsonpath='{.items[*].spec.schedulerName}' assert_success assert_output --partial "${scheduler_name}" }