This is an automated email from the ASF dual-hosted git repository. cdeppisch pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit ffa53139cd78270b2f3b3bd1e850f49099b73266 Author: Christoph Deppisch <cdeppi...@redhat.com> AuthorDate: Thu Jun 1 15:08:13 2023 +0200 fix(#592): Introduce build order strategy - Run builds on same operator namespace with user defined strategy - Default strategy is "sequential" running only one single build at a time - Also support "fifo" strategy where builds are run/queued based on their creation timestamp. This strategy allows parallel builds as long as individual build dependency lists are not colliding - Users may adjust/overwrite the build order strategy via install command option, in the (local) integration platform settings or via the builder trait option - Max number of running builds limitation is not affected by the build order strategy (ensure to always obey the limitation) --- config/crd/bases/camel.apache.org_builds.yaml | 12 ++ .../bases/camel.apache.org_integrationkits.yaml | 4 + .../camel.apache.org_integrationplatforms.yaml | 20 +++ .../crd/bases/camel.apache.org_integrations.yaml | 4 + .../bases/camel.apache.org_kameletbindings.yaml | 4 + config/crd/bases/camel.apache.org_pipes.yaml | 4 + docs/modules/ROOT/pages/architecture/cr/build.adoc | 9 ++ .../ROOT/pages/installation/advanced/advanced.adoc | 1 + docs/modules/ROOT/partials/apis/camel-k-crds.adoc | 24 +++ docs/modules/traits/pages/builder.adoc | 4 + e2e/builder/build_test.go | 77 ++++++++- e2e/common/traits/builder_test.go | 35 ++++- e2e/commonwithcustominstall/local_platform_test.go | 1 + helm/camel-k/crds/crd-build.yaml | 12 ++ helm/camel-k/crds/crd-integration-kit.yaml | 4 + helm/camel-k/crds/crd-integration-platform.yaml | 20 +++ helm/camel-k/crds/crd-integration.yaml | 4 + helm/camel-k/crds/crd-kamelet-binding.yaml | 4 + helm/camel-k/crds/crd-pipe.yaml | 4 + pkg/apis/camel/v1/build_types_support.go | 25 +++ pkg/apis/camel/v1/common_types.go | 18 +++ pkg/apis/camel/v1/common_types_support.go | 1 + pkg/apis/camel/v1/trait/builder.go | 2 + .../camel/v1/buildconfiguration.go | 23 ++- pkg/cmd/install.go | 22 +++ pkg/cmd/install_test.go | 7 + pkg/controller/build/build_controller.go | 3 +- pkg/controller/build/build_monitor.go | 43 ++--- pkg/controller/build/build_monitor_test.go | 173 ++++++++++++++++++++- pkg/controller/integrationkit/build.go | 13 +- pkg/platform/defaults.go | 9 ++ pkg/platform/defaults_test.go | 37 ++++- pkg/resources/resources.go | 28 ++-- pkg/trait/builder.go | 43 ++++- resources/traits.yaml | 4 + 35 files changed, 634 insertions(+), 64 deletions(-) diff --git a/config/crd/bases/camel.apache.org_builds.yaml b/config/crd/bases/camel.apache.org_builds.yaml index 9e525152b..44ee86332 100644 --- a/config/crd/bases/camel.apache.org_builds.yaml +++ b/config/crd/bases/camel.apache.org_builds.yaml @@ -97,6 +97,12 @@ spec: description: The namespace where to run the builder Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy @@ -206,6 +212,12 @@ spec: Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy diff --git a/config/crd/bases/camel.apache.org_integrationkits.yaml b/config/crd/bases/camel.apache.org_integrationkits.yaml index 8ff5668a5..39fccd088 100644 --- a/config/crd/bases/camel.apache.org_integrationkits.yaml +++ b/config/crd/bases/camel.apache.org_integrationkits.yaml @@ -211,6 +211,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/config/crd/bases/camel.apache.org_integrationplatforms.yaml b/config/crd/bases/camel.apache.org_integrationplatforms.yaml index 080b76618..1d716f3e6 100644 --- a/config/crd/bases/camel.apache.org_integrationplatforms.yaml +++ b/config/crd/bases/camel.apache.org_integrationplatforms.yaml @@ -116,6 +116,12 @@ spec: description: The namespace where to run the builder Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy @@ -462,6 +468,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task @@ -1753,6 +1763,12 @@ spec: description: The namespace where to run the builder Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy @@ -2147,6 +2163,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/config/crd/bases/camel.apache.org_integrations.yaml b/config/crd/bases/camel.apache.org_integrations.yaml index 0912bebc7..6106dc086 100644 --- a/config/crd/bases/camel.apache.org_integrations.yaml +++ b/config/crd/bases/camel.apache.org_integrations.yaml @@ -6194,6 +6194,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/config/crd/bases/camel.apache.org_kameletbindings.yaml b/config/crd/bases/camel.apache.org_kameletbindings.yaml index 93b4eba21..2ffcbaff3 100644 --- a/config/crd/bases/camel.apache.org_kameletbindings.yaml +++ b/config/crd/bases/camel.apache.org_kameletbindings.yaml @@ -6469,6 +6469,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/config/crd/bases/camel.apache.org_pipes.yaml b/config/crd/bases/camel.apache.org_pipes.yaml index 6b166be6b..4da7c6ade 100644 --- a/config/crd/bases/camel.apache.org_pipes.yaml +++ b/config/crd/bases/camel.apache.org_pipes.yaml @@ -6466,6 +6466,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/docs/modules/ROOT/pages/architecture/cr/build.adoc b/docs/modules/ROOT/pages/architecture/cr/build.adoc index 306fb22bf..f331906f1 100644 --- a/docs/modules/ROOT/pages/architecture/cr/build.adoc +++ b/docs/modules/ROOT/pages/architecture/cr/build.adoc @@ -36,6 +36,15 @@ At the moment the available strategies are: - buildStrategy: pod (each build is run in a separate pod, the operator monitors the pod state) - buildStrategy: routine (each build is run as a go routine inside the operator pod) +[[build-order-strategy]] +== Build order strategy + +You can choose from different build order strategies. The strategy defines in which order queued builds are run. +At the moment the available strategies are: + +- buildOrderStrategy: sequential (runs builds strictly sequential so that only one single build per operator namespace is running at a time.) +- buildOrderStrategy: fifo (performs the builds with first in first out strategy based on the creation timestamp. The strategy allows builds to run in parallel to each other but oldest builds will be run first.) + [[build-queue]] == Build queues diff --git a/docs/modules/ROOT/pages/installation/advanced/advanced.adoc b/docs/modules/ROOT/pages/installation/advanced/advanced.adoc index c34e804d6..595f9ccef 100644 --- a/docs/modules/ROOT/pages/installation/advanced/advanced.adoc +++ b/docs/modules/ROOT/pages/installation/advanced/advanced.adoc @@ -26,6 +26,7 @@ We have several configuration used to influence the building of an integration: --build-publish-strategy string Set the build publish strategy --build-publish-strategy-option stringArray Add a build publish strategy option, as <name=value> --build-strategy string Set the build strategy +--build-order-strategy string Set the build order strategy --build-timeout string Set how long the build process can last ``` A very important set of configuration you can provide is related to Maven: diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index 169451c07..aa0730185 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -533,6 +533,13 @@ The namespace where to run the builder Pod (must be the same of the operator in the strategy to adopt +|`orderStrategy` + +*xref:#_camel_apache_org_v1_BuildOrderStrategy[BuildOrderStrategy]* +| + + +the build order strategy to adopt + |`requestCPU` + string | @@ -564,6 +571,16 @@ The maximum amount of memory required. Only used for `pod` strategy |=== +[#_camel_apache_org_v1_BuildOrderStrategy] +=== BuildOrderStrategy(`string` alias) + +*Appears on:* + +* <<#_camel_apache_org_v1_BuildConfiguration, BuildConfiguration>> + +BuildOrderStrategy specifies how builds are reconciled and queued. + + [#_camel_apache_org_v1_BuildPhase] === BuildPhase(`string` alias) @@ -5390,6 +5407,13 @@ string The strategy to use, either `pod` or `routine` (default routine) +|`orderStrategy` + +string +| + + +The build order strategy to use, either `fifo` or `sequential` (default sequential) + |`requestCPU` + string | diff --git a/docs/modules/traits/pages/builder.adoc b/docs/modules/traits/pages/builder.adoc index 3ae0a7f40..298d7afba 100755 --- a/docs/modules/traits/pages/builder.adoc +++ b/docs/modules/traits/pages/builder.adoc @@ -40,6 +40,10 @@ The following configuration options are available: | string | The strategy to use, either `pod` or `routine` (default routine) +| builder.order-strategy +| string +| The build order strategy to use, either `fifo` or `sequential` (default sequential) + | builder.request-cpu | string | When using `pod` strategy, the minimum amount of CPU required by the pod builder. diff --git a/e2e/builder/build_test.go b/e2e/builder/build_test.go index ae4835f13..ccb266706 100644 --- a/e2e/builder/build_test.go +++ b/e2e/builder/build_test.go @@ -45,8 +45,9 @@ func TestKitMaxBuildLimit(t *testing.T) { createOperator(ns, "8m0s", "--global", "--force") pl := Platform(ns)() - // set maximum number of running builds + // set maximum number of running builds and order strategy pl.Spec.Build.MaxRunningBuilds = 2 + pl.Spec.Build.BuildConfiguration.OrderStrategy = v1.BuildOrderStrategySequential if err := TestClient().Update(TestContext, pl); err != nil { t.Error(err) t.FailNow() @@ -139,6 +140,80 @@ func TestKitMaxBuildLimit(t *testing.T) { }) } +func TestKitMaxBuildLimitFIFOStrategy(t *testing.T) { + WithNewTestNamespace(t, func(ns string) { + createOperator(ns, "8m0s", "--global", "--force") + + pl := Platform(ns)() + // set maximum number of running builds and order strategy + pl.Spec.Build.MaxRunningBuilds = 2 + pl.Spec.Build.BuildConfiguration.OrderStrategy = v1.BuildOrderStrategyFIFO + if err := TestClient().Update(TestContext, pl); err != nil { + t.Error(err) + t.FailNow() + } + + buildA := "integration-a" + buildB := "integration-b" + buildC := "integration-c" + + doKitBuildInNamespace(buildA, ns, TestTimeoutShort, kitOptions{ + operatorID: fmt.Sprintf("camel-k-%s", ns), + dependencies: []string{ + "camel:timer", "camel:log", + }, + traits: []string{ + "builder.properties=build-property=A", + }, + }, v1.BuildPhaseRunning, v1.IntegrationKitPhaseBuildRunning) + + doKitBuildInNamespace(buildB, ns, TestTimeoutShort, kitOptions{ + operatorID: fmt.Sprintf("camel-k-%s", ns), + dependencies: []string{ + "camel:timer", "camel:log", + }, + traits: []string{ + "builder.properties=build-property=B", + }, + }, v1.BuildPhaseRunning, v1.IntegrationKitPhaseBuildRunning) + + doKitBuildInNamespace(buildC, ns, TestTimeoutShort, kitOptions{ + operatorID: fmt.Sprintf("camel-k-%s", ns), + dependencies: []string{ + "camel:timer", "camel:log", + }, + traits: []string{ + "builder.properties=build-property=C", + }, + }, v1.BuildPhaseScheduling, v1.IntegrationKitPhaseNone) + + var notExceedsMaxBuildLimit = func(runningBuilds int) bool { + return runningBuilds <= 2 + } + + limit := 0 + for limit < 5 && BuildPhase(ns, buildA)() == v1.BuildPhaseRunning { + // verify that number of running builds does not exceed max build limit + Consistently(BuildsRunning(BuildPhase(ns, buildA), BuildPhase(ns, buildB), BuildPhase(ns, buildC)), TestTimeoutShort, 10*time.Second).Should(Satisfy(notExceedsMaxBuildLimit)) + limit++ + } + + // make sure we have verified max build limit at least once + if limit == 0 { + t.Error(errors.New(fmt.Sprintf("Unexpected build phase '%s' for %s - not able to verify max builds limit", BuildPhase(ns, buildA)(), buildA))) + t.FailNow() + } + + // verify that all builds are successful + Eventually(BuildPhase(ns, buildA), TestTimeoutLong).Should(Equal(v1.BuildPhaseSucceeded)) + Eventually(KitPhase(ns, buildA), TestTimeoutLong).Should(Equal(v1.IntegrationKitPhaseReady)) + Eventually(BuildPhase(ns, buildB), TestTimeoutLong).Should(Equal(v1.BuildPhaseSucceeded)) + Eventually(KitPhase(ns, buildB), TestTimeoutLong).Should(Equal(v1.IntegrationKitPhaseReady)) + Eventually(BuildPhase(ns, buildC), TestTimeoutLong).Should(Equal(v1.BuildPhaseSucceeded)) + Eventually(KitPhase(ns, buildC), TestTimeoutLong).Should(Equal(v1.IntegrationKitPhaseReady)) + }) +} + func TestKitTimerToLogFullBuild(t *testing.T) { doKitFullBuild(t, "timer-to-log", "8m0s", TestTimeoutLong, kitOptions{ dependencies: []string{ diff --git a/e2e/common/traits/builder_test.go b/e2e/common/traits/builder_test.go index f876a2445..d940aad83 100644 --- a/e2e/common/traits/builder_test.go +++ b/e2e/common/traits/builder_test.go @@ -37,9 +37,8 @@ import ( func TestBuilderTrait(t *testing.T) { RegisterTestingT(t) - name := "java" - t.Run("Run build strategy routine", func(t *testing.T) { + name := "java" Expect(KamelRunWithID(operatorID, ns, "files/Java.java", "--name", name, "-t", "builder.strategy=routine").Execute()).To(Succeed()) @@ -51,6 +50,33 @@ func TestBuilderTrait(t *testing.T) { integrationKitName := IntegrationKit(ns, name)() builderKitName := fmt.Sprintf("camel-k-%s-builder", integrationKitName) Eventually(BuildConfig(ns, integrationKitName)().Strategy, TestTimeoutShort).Should(Equal(v1.BuildStrategyRoutine)) + Eventually(BuildConfig(ns, integrationKitName)().OrderStrategy, TestTimeoutShort).Should(Equal(v1.BuildOrderStrategySequential)) + // Default resource CPU Check + Eventually(BuildConfig(ns, integrationKitName)().RequestCPU, TestTimeoutShort).Should(Equal("")) + Eventually(BuildConfig(ns, integrationKitName)().LimitCPU, TestTimeoutShort).Should(Equal("")) + Eventually(BuildConfig(ns, integrationKitName)().RequestMemory, TestTimeoutShort).Should(Equal("")) + Eventually(BuildConfig(ns, integrationKitName)().LimitMemory, TestTimeoutShort).Should(Equal("")) + + Eventually(BuilderPod(ns, builderKitName), TestTimeoutShort).Should(BeNil()) + + // We need to remove the kit as well + Expect(Kamel("reset", "-n", ns).Execute()).To(Succeed()) + }) + + t.Run("Run build order strategy fifo", func(t *testing.T) { + name := "java-fifo-strategy" + Expect(KamelRunWithID(operatorID, ns, "files/Java.java", + "--name", name, + "-t", "builder.order-strategy=fifo").Execute()).To(Succeed()) + + Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning)) + Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Magicstring!")) + + integrationKitName := IntegrationKit(ns, name)() + builderKitName := fmt.Sprintf("camel-k-%s-builder", integrationKitName) + Eventually(BuildConfig(ns, integrationKitName)().Strategy, TestTimeoutShort).Should(Equal(v1.BuildStrategyRoutine)) + Eventually(BuildConfig(ns, integrationKitName)().OrderStrategy, TestTimeoutShort).Should(Equal(v1.BuildOrderStrategyFIFO)) // Default resource CPU Check Eventually(BuildConfig(ns, integrationKitName)().RequestCPU, TestTimeoutShort).Should(Equal("")) Eventually(BuildConfig(ns, integrationKitName)().LimitCPU, TestTimeoutShort).Should(Equal("")) @@ -64,6 +90,7 @@ func TestBuilderTrait(t *testing.T) { }) t.Run("Run build resources configuration", func(t *testing.T) { + name := "java-resource-config" Expect(KamelRunWithID(operatorID, ns, "files/Java.java", "--name", name, "-t", "builder.request-cpu=500m", @@ -81,6 +108,7 @@ func TestBuilderTrait(t *testing.T) { builderKitName := fmt.Sprintf("camel-k-%s-builder", integrationKitName) Eventually(BuildConfig(ns, integrationKitName)().Strategy, TestTimeoutShort).Should(Equal(v1.BuildStrategyPod)) + Eventually(BuildConfig(ns, integrationKitName)().OrderStrategy, TestTimeoutShort).Should(Equal(v1.BuildOrderStrategySequential)) Eventually(BuildConfig(ns, integrationKitName)().RequestCPU, TestTimeoutShort).Should(Equal("500m")) Eventually(BuildConfig(ns, integrationKitName)().LimitCPU, TestTimeoutShort).Should(Equal("1000m")) Eventually(BuildConfig(ns, integrationKitName)().RequestMemory, TestTimeoutShort).Should(Equal("2Gi")) @@ -98,6 +126,7 @@ func TestBuilderTrait(t *testing.T) { }) t.Run("Run custom pipeline task", func(t *testing.T) { + name := "java-pipeline" Expect(KamelRunWithID(operatorID, ns, "files/Java.java", "--name", name, "-t", "builder.tasks=custom1;alpine;tree", @@ -141,8 +170,8 @@ func TestBuilderTrait(t *testing.T) { Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed()) }) - name = "java-error" t.Run("Run custom pipeline task error", func(t *testing.T) { + name := "java-error" Expect(KamelRunWithID(operatorID, ns, "files/Java.java", "--name", name, "-t", "builder.tasks=custom1;alpine;cat missingfile.txt", diff --git a/e2e/commonwithcustominstall/local_platform_test.go b/e2e/commonwithcustominstall/local_platform_test.go index 05ce8c3b7..2f924ac20 100644 --- a/e2e/commonwithcustominstall/local_platform_test.go +++ b/e2e/commonwithcustominstall/local_platform_test.go @@ -82,6 +82,7 @@ func TestLocalPlatform(t *testing.T) { local := Platform(ns1)() Expect(local.Status.Build.PublishStrategy).To(Equal(pl.Status.Build.PublishStrategy)) Expect(local.Status.Build.BuildConfiguration.Strategy).To(Equal(pl.Status.Build.BuildConfiguration.Strategy)) + Expect(local.Status.Build.BuildConfiguration.OrderStrategy).To(Equal(pl.Status.Build.BuildConfiguration.OrderStrategy)) Expect(local.Status.Build.Maven.LocalRepository).To(Equal(pl.Status.Build.Maven.LocalRepository)) Expect(local.Status.Build.Maven.CLIOptions).To(ContainElements(pl.Status.Build.Maven.CLIOptions)) Expect(local.Status.Build.Maven.Extension).To(BeEmpty()) diff --git a/helm/camel-k/crds/crd-build.yaml b/helm/camel-k/crds/crd-build.yaml index 9e525152b..44ee86332 100644 --- a/helm/camel-k/crds/crd-build.yaml +++ b/helm/camel-k/crds/crd-build.yaml @@ -97,6 +97,12 @@ spec: description: The namespace where to run the builder Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy @@ -206,6 +212,12 @@ spec: Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy diff --git a/helm/camel-k/crds/crd-integration-kit.yaml b/helm/camel-k/crds/crd-integration-kit.yaml index 8ff5668a5..39fccd088 100644 --- a/helm/camel-k/crds/crd-integration-kit.yaml +++ b/helm/camel-k/crds/crd-integration-kit.yaml @@ -211,6 +211,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/helm/camel-k/crds/crd-integration-platform.yaml b/helm/camel-k/crds/crd-integration-platform.yaml index 080b76618..1d716f3e6 100644 --- a/helm/camel-k/crds/crd-integration-platform.yaml +++ b/helm/camel-k/crds/crd-integration-platform.yaml @@ -116,6 +116,12 @@ spec: description: The namespace where to run the builder Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy @@ -462,6 +468,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task @@ -1753,6 +1763,12 @@ spec: description: The namespace where to run the builder Pod (must be the same of the operator in charge of this Build reconciliation). type: string + orderStrategy: + description: the build order strategy to adopt + enum: + - fifo + - sequential + type: string requestCPU: description: The minimum amount of CPU required. Only used for `pod` strategy @@ -2147,6 +2163,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/helm/camel-k/crds/crd-integration.yaml b/helm/camel-k/crds/crd-integration.yaml index 0912bebc7..6106dc086 100644 --- a/helm/camel-k/crds/crd-integration.yaml +++ b/helm/camel-k/crds/crd-integration.yaml @@ -6194,6 +6194,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml b/helm/camel-k/crds/crd-kamelet-binding.yaml index 93b4eba21..2ffcbaff3 100644 --- a/helm/camel-k/crds/crd-kamelet-binding.yaml +++ b/helm/camel-k/crds/crd-kamelet-binding.yaml @@ -6469,6 +6469,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/helm/camel-k/crds/crd-pipe.yaml b/helm/camel-k/crds/crd-pipe.yaml index 6b166be6b..4da7c6ade 100644 --- a/helm/camel-k/crds/crd-pipe.yaml +++ b/helm/camel-k/crds/crd-pipe.yaml @@ -6466,6 +6466,10 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + orderStrategy: + description: The build order strategy to use, either `fifo` + or `sequential` (default sequential) + type: string properties: description: A list of properties to be provided to the build task diff --git a/pkg/apis/camel/v1/build_types_support.go b/pkg/apis/camel/v1/build_types_support.go index 6131f909b..8c05f66e7 100644 --- a/pkg/apis/camel/v1/build_types_support.go +++ b/pkg/apis/camel/v1/build_types_support.go @@ -201,3 +201,28 @@ func (c BuildCondition) GetReason() string { func (c BuildCondition) GetMessage() string { return c.Message } + +func (bl BuildList) HasRunningBuilds() bool { + for _, b := range bl.Items { + if b.Status.Phase == BuildPhasePending || b.Status.Phase == BuildPhaseRunning { + return true + } + } + + return false +} + +func (bl BuildList) HasScheduledBuildsBefore(build *Build) bool { + for _, b := range bl.Items { + if b.Name == build.Name { + continue + } + + if (b.Status.Phase == BuildPhaseInitialization || b.Status.Phase == BuildPhaseScheduling) && + b.CreationTimestamp.Before(&build.CreationTimestamp) { + return true + } + } + + return false +} diff --git a/pkg/apis/camel/v1/common_types.go b/pkg/apis/camel/v1/common_types.go index 4a4aaa2cf..979cd2a87 100644 --- a/pkg/apis/camel/v1/common_types.go +++ b/pkg/apis/camel/v1/common_types.go @@ -43,6 +43,8 @@ type BuildConfiguration struct { BuilderPodNamespace string `json:"operatorNamespace,omitempty"` // the strategy to adopt Strategy BuildStrategy `property:"strategy" json:"strategy,omitempty"` + // the build order strategy to adopt + OrderStrategy BuildOrderStrategy `property:"order-strategy" json:"orderStrategy,omitempty"` // The minimum amount of CPU required. Only used for `pod` strategy RequestCPU string `property:"request-cpu" json:"requestCPU,omitempty"` // The minimum amount of memory required. Only used for `pod` strategy @@ -70,6 +72,12 @@ const ( // mitigated by the presence of a Maven proxy. // Available for both Quarkus JVM and Native mode. BuildStrategyPod BuildStrategy = "pod" + + // BuildOrderStrategyFIFO performs the builds with first in first out strategy based on the creation timestamp. + // The strategy allows builds to run in parallel to each other but oldest builds will be run first. + BuildOrderStrategyFIFO BuildOrderStrategy = "fifo" + // BuildOrderStrategySequential runs builds strictly sequential so that only one single build per operator namespace is running at a time. + BuildOrderStrategySequential BuildOrderStrategy = "sequential" ) // BuildStrategies is a list of strategies allowed for the build @@ -78,6 +86,16 @@ var BuildStrategies = []BuildStrategy{ BuildStrategyPod, } +// BuildOrderStrategy specifies how builds are reconciled and queued. +// +kubebuilder:validation:Enum=fifo;sequential +type BuildOrderStrategy string + +// BuildOrderStrategies is a list of order strategies allowed for the build +var BuildOrderStrategies = []BuildOrderStrategy{ + BuildOrderStrategyFIFO, + BuildOrderStrategySequential, +} + // ConfigurationSpec represents a generic configuration specification type ConfigurationSpec struct { // represents the type of configuration, ie: property, configmap, secret, ... diff --git a/pkg/apis/camel/v1/common_types_support.go b/pkg/apis/camel/v1/common_types_support.go index b66dca9a8..6b48170d3 100644 --- a/pkg/apis/camel/v1/common_types_support.go +++ b/pkg/apis/camel/v1/common_types_support.go @@ -159,6 +159,7 @@ var _ json.Unmarshaler = (*RawMessage)(nil) // IsEmpty -- . func (bc *BuildConfiguration) IsEmpty() bool { return bc.Strategy == "" && + bc.OrderStrategy == "" && bc.RequestCPU == "" && bc.RequestMemory == "" && bc.LimitCPU == "" && diff --git a/pkg/apis/camel/v1/trait/builder.go b/pkg/apis/camel/v1/trait/builder.go index 6bfe96546..86e682ab3 100644 --- a/pkg/apis/camel/v1/trait/builder.go +++ b/pkg/apis/camel/v1/trait/builder.go @@ -29,6 +29,8 @@ type BuilderTrait struct { Properties []string `property:"properties" json:"properties,omitempty"` // The strategy to use, either `pod` or `routine` (default routine) Strategy string `property:"strategy" json:"strategy,omitempty"` + // The build order strategy to use, either `fifo` or `sequential` (default sequential) + OrderStrategy string `property:"order-strategy" json:"orderStrategy,omitempty"` // When using `pod` strategy, the minimum amount of CPU required by the pod builder. RequestCPU string `property:"request-cpu" json:"requestCPU,omitempty"` // When using `pod` strategy, the minimum amount of memory required by the pod builder. diff --git a/pkg/client/camel/applyconfiguration/camel/v1/buildconfiguration.go b/pkg/client/camel/applyconfiguration/camel/v1/buildconfiguration.go index 581db6aa5..7aa865add 100644 --- a/pkg/client/camel/applyconfiguration/camel/v1/buildconfiguration.go +++ b/pkg/client/camel/applyconfiguration/camel/v1/buildconfiguration.go @@ -26,13 +26,14 @@ import ( // BuildConfigurationApplyConfiguration represents an declarative configuration of the BuildConfiguration type for use // with apply. type BuildConfigurationApplyConfiguration struct { - ToolImage *string `json:"toolImage,omitempty"` - BuilderPodNamespace *string `json:"operatorNamespace,omitempty"` - Strategy *v1.BuildStrategy `json:"strategy,omitempty"` - RequestCPU *string `json:"requestCPU,omitempty"` - RequestMemory *string `json:"requestMemory,omitempty"` - LimitCPU *string `json:"limitCPU,omitempty"` - LimitMemory *string `json:"limitMemory,omitempty"` + ToolImage *string `json:"toolImage,omitempty"` + BuilderPodNamespace *string `json:"operatorNamespace,omitempty"` + Strategy *v1.BuildStrategy `json:"strategy,omitempty"` + OrderStrategy *v1.BuildOrderStrategy `json:"orderStrategy,omitempty"` + RequestCPU *string `json:"requestCPU,omitempty"` + RequestMemory *string `json:"requestMemory,omitempty"` + LimitCPU *string `json:"limitCPU,omitempty"` + LimitMemory *string `json:"limitMemory,omitempty"` } // BuildConfigurationApplyConfiguration constructs an declarative configuration of the BuildConfiguration type for use with @@ -65,6 +66,14 @@ func (b *BuildConfigurationApplyConfiguration) WithStrategy(value v1.BuildStrate return b } +// WithOrderStrategy sets the OrderStrategy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the OrderStrategy field is set to the value of the last call. +func (b *BuildConfigurationApplyConfiguration) WithOrderStrategy(value v1.BuildOrderStrategy) *BuildConfigurationApplyConfiguration { + b.OrderStrategy = &value + return b +} + // WithRequestCPU sets the RequestCPU field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the RequestCPU field is set to the value of the last call. diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index cf68324c8..6a4f3bd08 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -107,6 +107,7 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO cmd.Flags().String("operator-image", "", "Set the operator Image used for the operator deployment") cmd.Flags().String("operator-image-pull-policy", "", "Set the operator ImagePullPolicy used for the operator deployment") cmd.Flags().String("build-strategy", "", "Set the build strategy") + cmd.Flags().String("build-order-strategy", "", "Set the build order strategy") cmd.Flags().String("build-publish-strategy", "", "Set the build publish strategy") cmd.Flags().StringArray("build-publish-strategy-option", nil, "Add a build publish strategy option, as <name=value>") cmd.Flags().String("build-timeout", "", "Set how long the build process can last") @@ -181,6 +182,7 @@ type installCmdOptions struct { OperatorImage string `mapstructure:"operator-image"` OperatorImagePullPolicy string `mapstructure:"operator-image-pull-policy"` BuildStrategy string `mapstructure:"build-strategy"` + BuildOrderStrategy string `mapstructure:"build-order-strategy"` BuildPublishStrategy string `mapstructure:"build-publish-strategy"` BuildPublishStrategyOptions []string `mapstructure:"build-publish-strategy-options"` BuildTimeout string `mapstructure:"build-timeout"` @@ -524,6 +526,9 @@ func (o *installCmdOptions) setupIntegrationPlatform(c client.Client, namespace if o.BuildStrategy != "" { platform.Spec.Build.BuildConfiguration.Strategy = v1.BuildStrategy(o.BuildStrategy) } + if o.BuildOrderStrategy != "" { + platform.Spec.Build.BuildConfiguration.OrderStrategy = v1.BuildOrderStrategy(o.BuildOrderStrategy) + } if o.BuildPublishStrategy != "" { platform.Spec.Build.PublishStrategy = v1.IntegrationPlatformBuildPublishStrategy(o.BuildPublishStrategy) } @@ -749,6 +754,23 @@ func (o *installCmdOptions) validate(_ *cobra.Command, _ []string) error { } } + if o.BuildOrderStrategy != "" { + found := false + for _, s := range v1.BuildOrderStrategies { + if string(s) == o.BuildOrderStrategy { + found = true + break + } + } + if !found { + var strategies []string + for _, s := range v1.BuildOrderStrategies { + strategies = append(strategies, string(s)) + } + return fmt.Errorf("unknown build order strategy: %s. One of [%s] is expected", o.BuildOrderStrategy, strings.Join(strategies, ", ")) + } + } + if o.BuildPublishStrategy != "" { found := false for _, s := range v1.IntegrationPlatformBuildPublishStrategies { diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go index fcfdb8ecd..aacc8824b 100644 --- a/pkg/cmd/install_test.go +++ b/pkg/cmd/install_test.go @@ -107,6 +107,13 @@ func TestInstallBuildStrategyFlag(t *testing.T) { assert.Equal(t, "someString", installCmdOptions.BuildStrategy) } +func TestInstallBuildOrderStrategyFlag(t *testing.T) { + installCmdOptions, rootCmd, _ := initializeInstallCmdOptions(t) + _, err := test.ExecuteCommand(rootCmd, cmdInstall, "--build-order-strategy", "someString") + assert.Nil(t, err) + assert.Equal(t, "someString", installCmdOptions.BuildOrderStrategy) +} + func TestInstallBuildTimeoutFlag(t *testing.T) { installCmdOptions, rootCmd, _ := initializeInstallCmdOptions(t) _, err := test.ExecuteCommand(rootCmd, cmdInstall, "--build-timeout", "10") diff --git a/pkg/controller/build/build_controller.go b/pkg/controller/build/build_controller.go index 33fe525d8..75439a3d2 100644 --- a/pkg/controller/build/build_controller.go +++ b/pkg/controller/build/build_controller.go @@ -147,7 +147,8 @@ func (r *reconcileBuild) Reconcile(ctx context.Context, request reconcile.Reques return reconcile.Result{}, err } buildMonitor := Monitor{ - maxRunningBuilds: ip.Status.Build.MaxRunningBuilds, + maxRunningBuilds: ip.Status.Build.MaxRunningBuilds, + buildOrderStrategy: ip.Status.Build.BuildConfiguration.OrderStrategy, } switch instance.BuilderConfiguration().Strategy { diff --git a/pkg/controller/build/build_monitor.go b/pkg/controller/build/build_monitor.go index 521dd6b86..a60ce1b3a 100644 --- a/pkg/controller/build/build_monitor.go +++ b/pkg/controller/build/build_monitor.go @@ -33,7 +33,8 @@ import ( var runningBuilds sync.Map type Monitor struct { - maxRunningBuilds int32 + maxRunningBuilds int32 + buildOrderStrategy v1.BuildOrderStrategy } func (bm *Monitor) canSchedule(ctx context.Context, c ctrl.Reader, build *v1.Build) (bool, error) { @@ -43,15 +44,15 @@ func (bm *Monitor) canSchedule(ctx context.Context, c ctrl.Reader, build *v1.Bui return true }) - if runningBuildsTotal >= bm.maxRunningBuilds { - requestName := build.Name - requestNamespace := build.Namespace - buildCreator := kubernetes.GetCamelCreator(build) - if buildCreator != nil { - requestName = buildCreator.Name - requestNamespace = buildCreator.Namespace - } + requestName := build.Name + requestNamespace := build.Namespace + buildCreator := kubernetes.GetCamelCreator(build) + if buildCreator != nil { + requestName = buildCreator.Name + requestNamespace = buildCreator.Namespace + } + if runningBuildsTotal >= bm.maxRunningBuilds { Log.WithValues("request-namespace", requestNamespace, "request-name", requestName, "max-running-builds-limit", runningBuildsTotal). ForBuild(build).Infof("Maximum number of running builds (%d) exceeded - the build gets enqueued", runningBuildsTotal) @@ -84,18 +85,22 @@ func (bm *Monitor) canSchedule(ctx context.Context, c ctrl.Reader, build *v1.Bui return false, err } - // Emulate a serialized working queue to only allow one build to run at a given time. - // This is currently necessary for the incremental build to work as expected. - // We may want to explicitly manage build priority as opposed to relying on - // the reconciliation loop to handle the queuing. - for _, b := range builds.Items { - if b.Status.Phase == v1.BuildPhasePending || b.Status.Phase == v1.BuildPhaseRunning { - // Let's requeue the build in case one is already running - return false, nil - } + var allowed bool + switch bm.buildOrderStrategy { + case v1.BuildOrderStrategyFIFO: + // Check on builds that have been created before the current build and grant precedence if any. + allowed = !builds.HasScheduledBuildsBefore(build) + case v1.BuildOrderStrategySequential: + // Emulate a serialized working queue to only allow one build to run at a given time. + // Let's requeue the build in case one is already running + allowed = !builds.HasRunningBuilds() + default: + Log.WithValues("request-namespace", requestNamespace, "request-name", requestName, "order-strategy", bm.buildOrderStrategy). + ForBuild(build).Infof("Unsupported build order strategy (%s) - the build gets enqueued", bm.buildOrderStrategy) + allowed = false } - return true, nil + return allowed, nil } func monitorRunningBuild(build *v1.Build) { diff --git a/pkg/controller/build/build_monitor_test.go b/pkg/controller/build/build_monitor_test.go index 0dd4ee2d3..b44cd0533 100644 --- a/pkg/controller/build/build_monitor_test.go +++ b/pkg/controller/build/build_monitor_test.go @@ -30,7 +30,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -func TestMonitorBuilds(t *testing.T) { +func TestMonitorSequentialBuilds(t *testing.T) { testcases := []struct { name string running []*v1.Build @@ -49,7 +49,7 @@ func TestMonitorBuilds(t *testing.T) { name: "allowNewNativeBuild", running: []*v1.Build{}, finished: []*v1.Build{}, - build: newNativeBuild("ns", "my-build"), + build: newNativeBuild("ns", "my-native-build"), allowed: true, }, { @@ -69,7 +69,7 @@ func TestMonitorBuilds(t *testing.T) { newNativeBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), newNativeBuildInPhase("ns", "my-build-failed", v1.BuildPhaseFailed), }, - build: newNativeBuild("ns", "my-build"), + build: newNativeBuild("ns", "my-native-build"), allowed: true, }, { @@ -144,7 +144,8 @@ func TestMonitorBuilds(t *testing.T) { assert.Nil(t, err) bm := Monitor{ - maxRunningBuilds: 3, + maxRunningBuilds: 3, + buildOrderStrategy: v1.BuildOrderStrategySequential, } // reset running builds in memory cache @@ -167,7 +168,8 @@ func TestAllowBuildRequeue(t *testing.T) { assert.Nil(t, err) bm := Monitor{ - maxRunningBuilds: 3, + maxRunningBuilds: 3, + buildOrderStrategy: v1.BuildOrderStrategySequential, } runningBuild := newBuild("some-ns", "my-build-1") @@ -191,6 +193,165 @@ func TestAllowBuildRequeue(t *testing.T) { assert.True(t, allowed) } +func TestMonitorFIFOBuilds(t *testing.T) { + testcases := []struct { + name string + running []*v1.Build + builds []*v1.Build + build *v1.Build + allowed bool + }{ + { + name: "allowNewBuild", + running: []*v1.Build{}, + builds: []*v1.Build{}, + build: newBuild("ns", "my-build"), + allowed: true, + }, + { + name: "allowNewNativeBuild", + running: []*v1.Build{}, + builds: []*v1.Build{}, + build: newNativeBuild("ns1", "my-build"), + allowed: true, + }, + { + name: "allowNewBuildWhenOthersFinished", + running: []*v1.Build{}, + builds: []*v1.Build{ + newBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + newBuildInPhase("ns", "my-build-failed", v1.BuildPhaseFailed), + }, + build: newBuild("ns", "my-build"), + allowed: true, + }, + { + name: "allowNewNativeBuildWhenOthersFinished", + running: []*v1.Build{}, + builds: []*v1.Build{ + newNativeBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + newNativeBuildInPhase("ns", "my-build-failed", v1.BuildPhaseFailed), + }, + build: newNativeBuild("ns", "my-build"), + allowed: true, + }, + { + name: "limitMaxRunningBuilds", + running: []*v1.Build{ + newBuild("some-ns", "my-build-1"), + newBuild("other-ns", "my-build-2"), + newBuild("another-ns", "my-build-3"), + }, + builds: []*v1.Build{ + newBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + }, + build: newBuild("ns", "my-build"), + allowed: false, + }, + { + name: "limitMaxRunningNativeBuilds", + running: []*v1.Build{ + newBuildInPhase("some-ns", "my-build-1", v1.BuildPhaseRunning), + newNativeBuildInPhase("other-ns", "my-build-2", v1.BuildPhaseRunning), + newNativeBuildInPhase("another-ns", "my-build-3", v1.BuildPhaseRunning), + }, + builds: []*v1.Build{ + newNativeBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + }, + build: newNativeBuildInPhase("ns", "my-build", v1.BuildPhaseInitialization), + allowed: false, + }, + { + name: "allowParallelBuildsWithDifferentLayout", + running: []*v1.Build{ + newNativeBuildInPhase("ns", "my-build-1", v1.BuildPhaseRunning), + }, + build: newBuild("ns", "my-build"), + allowed: true, + }, + { + name: "allowParallelBuildsInSameNamespace", + running: []*v1.Build{ + newBuild("ns", "my-build-1"), + newBuild("other-ns", "my-build-2"), + }, + builds: []*v1.Build{ + newBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + newBuildInPhase("other-ns", "my-build-new", v1.BuildPhaseScheduling), + }, + build: newBuild("ns", "my-build"), + allowed: true, + }, + { + name: "queueBuildWhenOlderBuildIsAlreadyInitialized", + running: []*v1.Build{ + newBuild("ns", "my-build-1"), + newBuild("other-ns", "my-build-2"), + }, + builds: []*v1.Build{ + newBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + newBuildInPhase("ns", "my-build-new", v1.BuildPhaseInitialization), + }, + build: newBuild("ns", "my-build"), + allowed: false, + }, + { + name: "queueBuildWhenOlderBuildIsAlreadyScheduled", + running: []*v1.Build{ + newBuild("ns", "my-build-1"), + newBuild("other-ns", "my-build-2"), + }, + builds: []*v1.Build{ + newBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + newBuildInPhase("ns", "my-build-new", v1.BuildPhaseScheduling), + }, + build: newBuild("ns", "my-build"), + allowed: false, + }, + { + name: "allowBuildsInNewNamespace", + running: []*v1.Build{ + newBuild("some-ns", "my-build-1"), + newBuild("other-ns", "my-build-2"), + }, + builds: []*v1.Build{ + newBuildInPhase("ns", "my-build-x", v1.BuildPhaseSucceeded), + }, + build: newBuild("ns", "my-build"), + allowed: true, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + var initObjs []runtime.Object + for _, build := range append(tc.running, tc.builds...) { + initObjs = append(initObjs, build) + } + + c, err := test.NewFakeClient(initObjs...) + + assert.Nil(t, err) + + bm := Monitor{ + maxRunningBuilds: 3, + buildOrderStrategy: v1.BuildOrderStrategyFIFO, + } + + // reset running builds in memory cache + cleanRunningBuildsMonitor() + for _, build := range tc.running { + monitorRunningBuild(build) + } + + allowed, err := bm.canSchedule(context.TODO(), c, tc.build) + + assert.Nil(t, err) + assert.Equal(t, tc.allowed, allowed) + }) + } +} + func cleanRunningBuildsMonitor() { runningBuilds.Range(func(key interface{}, v interface{}) bool { runningBuilds.Delete(key) @@ -226,6 +387,7 @@ func newBuildWithLayoutInPhase(namespace string, name string, layout string, pha Labels: map[string]string{ v1.IntegrationKitLayoutLabel: layout, }, + CreationTimestamp: metav1.NewTime(time.Now()), }, Spec: v1.BuildSpec{ Tasks: []v1.Task{ @@ -233,6 +395,7 @@ func newBuildWithLayoutInPhase(namespace string, name string, layout string, pha Builder: &v1.BuilderTask{ Configuration: v1.BuildConfiguration{ Strategy: v1.BuildStrategyRoutine, + OrderStrategy: v1.BuildOrderStrategySequential, ToolImage: "camel:latest", BuilderPodNamespace: "ns", }, diff --git a/pkg/controller/integrationkit/build.go b/pkg/controller/integrationkit/build.go index 75228c041..d4b49fa97 100644 --- a/pkg/controller/integrationkit/build.go +++ b/pkg/controller/integrationkit/build.go @@ -113,9 +113,16 @@ func (action *buildAction) handleBuildSubmitted(ctx context.Context, kit *v1.Int if buildConfig.IsEmpty() { // default to IntegrationPlatform configuration buildConfig = &env.Platform.Status.Build.BuildConfiguration - } else if buildConfig.Strategy == "" { - // we always need to define a strategy, so we default to platform if none - buildConfig.Strategy = env.Platform.Status.Build.BuildConfiguration.Strategy + } else { + if buildConfig.Strategy == "" { + // we always need to define a strategy, so we default to platform if none + buildConfig.Strategy = env.Platform.Status.Build.BuildConfiguration.Strategy + } + + if buildConfig.OrderStrategy == "" { + // we always need to define an order strategy, so we default to platform if none + buildConfig.OrderStrategy = env.Platform.Status.Build.BuildConfiguration.OrderStrategy + } } // nolint: contextcheck diff --git a/pkg/platform/defaults.go b/pkg/platform/defaults.go index 7504c195b..a7711e4cc 100644 --- a/pkg/platform/defaults.go +++ b/pkg/platform/defaults.go @@ -97,6 +97,11 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *v1.IntegrationPl log.Debugf("Integration Platform %s [%s]: setting build strategy %s", p.Name, p.Namespace, p.Status.Build.BuildConfiguration.Strategy) } + if p.Status.Build.BuildConfiguration.OrderStrategy == "" { + p.Status.Build.BuildConfiguration.OrderStrategy = v1.BuildOrderStrategySequential + log.Debugf("Integration Platform %s [%s]: setting build order strategy %s", p.Name, p.Namespace, p.Status.Build.BuildConfiguration.OrderStrategy) + } + err := setPlatformDefaults(p, verbose) if err != nil { return err @@ -237,6 +242,10 @@ func applyPlatformSpec(source *v1.IntegrationPlatform, target *v1.IntegrationPla target.Status.Build.BuildConfiguration.Strategy = source.Status.Build.BuildConfiguration.Strategy } + if target.Status.Build.BuildConfiguration.OrderStrategy == "" { + target.Status.Build.BuildConfiguration.OrderStrategy = source.Status.Build.BuildConfiguration.OrderStrategy + } + if target.Status.Build.RuntimeVersion == "" { log.Debugf("Integration Platform %s [%s]: setting runtime version", target.Name, target.Namespace) target.Status.Build.RuntimeVersion = source.Status.Build.RuntimeVersion diff --git a/pkg/platform/defaults_test.go b/pkg/platform/defaults_test.go index b2a51fb22..d73b99af2 100644 --- a/pkg/platform/defaults_test.go +++ b/pkg/platform/defaults_test.go @@ -28,9 +28,35 @@ import ( v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/builder" + "github.com/apache/camel-k/v2/pkg/util/defaults" "github.com/apache/camel-k/v2/pkg/util/test" ) +func TestIntegrationPlatformDefaults(t *testing.T) { + ip := v1.IntegrationPlatform{ + ObjectMeta: metav1.ObjectMeta{ + Name: DefaultPlatformName, + Namespace: "ns", + }, + } + + c, err := test.NewFakeClient(&ip) + assert.Nil(t, err) + + err = ConfigureDefaults(context.TODO(), c, &ip, false) + assert.Nil(t, err) + + assert.Equal(t, v1.IntegrationPlatformClusterKubernetes, ip.Status.Cluster) + assert.Equal(t, v1.TraitProfile(""), ip.Status.Profile) + assert.Equal(t, v1.BuildStrategyRoutine, ip.Status.Build.BuildConfiguration.Strategy) + assert.Equal(t, v1.BuildOrderStrategySequential, ip.Status.Build.BuildConfiguration.OrderStrategy) + assert.Equal(t, defaults.BaseImage(), ip.Status.Build.BaseImage) + assert.Equal(t, defaults.LocalRepository, ip.Status.Build.Maven.LocalRepository) + assert.True(t, ip.Status.Build.MaxRunningBuilds == 3) // default for build strategy routine + assert.Equal(t, 3, len(ip.Status.Build.Maven.CLIOptions)) + assert.NotNil(t, ip.Status.Traits) +} + func TestApplyGlobalPlatformSpec(t *testing.T) { global := v1.IntegrationPlatform{ ObjectMeta: metav1.ObjectMeta{ @@ -40,7 +66,8 @@ func TestApplyGlobalPlatformSpec(t *testing.T) { Spec: v1.IntegrationPlatformSpec{ Build: v1.IntegrationPlatformBuildSpec{ BuildConfiguration: v1.BuildConfiguration{ - Strategy: v1.BuildStrategyRoutine, + Strategy: v1.BuildStrategyRoutine, + OrderStrategy: v1.BuildOrderStrategyFIFO, }, Maven: v1.MavenSpec{ Properties: map[string]string{ @@ -83,6 +110,7 @@ func TestApplyGlobalPlatformSpec(t *testing.T) { assert.Equal(t, v1.IntegrationPlatformClusterOpenShift, ip.Status.Cluster) assert.Equal(t, v1.TraitProfileOpenShift, ip.Status.Profile) assert.Equal(t, v1.BuildStrategyRoutine, ip.Status.Build.BuildConfiguration.Strategy) + assert.Equal(t, v1.BuildOrderStrategyFIFO, ip.Status.Build.BuildConfiguration.OrderStrategy) assert.True(t, ip.Status.Build.MaxRunningBuilds == 3) // default for build strategy routine assert.Equal(t, len(global.Status.Build.Maven.CLIOptions), len(ip.Status.Build.Maven.CLIOptions)) assert.Equal(t, global.Status.Build.Maven.CLIOptions, ip.Status.Build.Maven.CLIOptions) @@ -187,7 +215,8 @@ func TestRetainLocalPlatformSpec(t *testing.T) { Spec: v1.IntegrationPlatformSpec{ Build: v1.IntegrationPlatformBuildSpec{ BuildConfiguration: v1.BuildConfiguration{ - Strategy: v1.BuildStrategyRoutine, + Strategy: v1.BuildStrategyRoutine, + OrderStrategy: v1.BuildOrderStrategySequential, }, Maven: v1.MavenSpec{ Properties: map[string]string{ @@ -224,7 +253,8 @@ func TestRetainLocalPlatformSpec(t *testing.T) { Spec: v1.IntegrationPlatformSpec{ Build: v1.IntegrationPlatformBuildSpec{ BuildConfiguration: v1.BuildConfiguration{ - Strategy: v1.BuildStrategyPod, + Strategy: v1.BuildStrategyPod, + OrderStrategy: v1.BuildOrderStrategyFIFO, }, MaxRunningBuilds: 1, Maven: v1.MavenSpec{ @@ -251,6 +281,7 @@ func TestRetainLocalPlatformSpec(t *testing.T) { assert.Equal(t, v1.IntegrationPlatformClusterKubernetes, ip.Status.Cluster) assert.Equal(t, v1.TraitProfileKnative, ip.Status.Profile) assert.Equal(t, v1.BuildStrategyPod, ip.Status.Build.BuildConfiguration.Strategy) + assert.Equal(t, v1.BuildOrderStrategyFIFO, ip.Status.Build.BuildConfiguration.OrderStrategy) assert.True(t, ip.Status.Build.MaxRunningBuilds == 1) assert.Equal(t, len(global.Status.Build.Maven.CLIOptions), len(ip.Status.Build.Maven.CLIOptions)) assert.Equal(t, global.Status.Build.Maven.CLIOptions, ip.Status.Build.Maven.CLIOptions) diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go index 8911750c1..582168091 100644 --- a/pkg/resources/resources.go +++ b/pkg/resources/resources.go @@ -117,9 +117,9 @@ var assets = func() http.FileSystem { "/crd/bases/camel.apache.org_builds.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_builds.yaml", modTime: time.Time{}, - uncompressedSize: 44155, + uncompressedSize: 44653, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x3d\x5d\x73\x1b\x39\x72\xef\xfa\x15\x5d\xab\x07\xcb\x55\x22\xb9\xeb\xbd\xbb\x6c\x94\x4a\xa5\x74\xf2\x7a\x4f\xf1\x87\x14\x53\xf6\xdd\xbd\x09\x9c\x69\x92\x38\xce\x00\x13\x00\x23\x9a\x97\xca\x7f\x4f\xa1\x01\x0c\x87\xe4\x7c\x60\x64\x69\xbd\xb9\x23\x5e\x6c\x0d\xf1\xd1\xdd\xe8\x2f\x34\x1a\xc0\x29\x8c\x9e\xae\x9c\x9c\xc2\x3b\x9e\xa0\xd0\x98\x82\x91\x60\x96\x08\x97\x05\x4b\x96\x08\x53\x39\x37\x6b\xa6\x10\xde\xc8\x52\xa4\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x3d\x5d\x73\x1b\x39\x72\xef\xfa\x15\x5d\xab\x07\xcb\x55\x22\xb5\xeb\xbd\xbb\x6c\x94\x4a\xa5\x74\xf2\x7a\x4f\xf1\x87\x14\x53\xf6\xdd\xbd\x09\x9c\x69\x92\x38\xce\x00\x13\x00\x23\x9a\x97\xca\x7f\x4f\xa1\x01\x0c\x87\xe4\x7c\x60\x64\x6a\xbd\xb9\x23\x5e\x6c\x71\xf0\xd1\xdd\x68\xf4\x17\x1a\xc0\x29\x8c\x0e\x57\x4e\x4e\xe1\x1d\x4f\x50\x68\x4c\xc1\x48\x30\x0b\x84\xab\x82\x25\x0b\x84\x89\x9c\x99\x15\x53\x08\x6f\x64\x29\x52\x [...] }, "/crd/bases/camel.apache.org_camelcatalogs.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_camelcatalogs.yaml", @@ -131,30 +131,30 @@ var assets = func() http.FileSystem { "/crd/bases/camel.apache.org_integrationkits.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_integrationkits.yaml", modTime: time.Time{}, - uncompressedSize: 20532, + uncompressedSize: 20753, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x3c\x5d\x73\xdb\x38\x92\xef\xfa\x15\x5d\xf1\x43\xec\x2a\x49\xde\xb9\x9b\x9a\xba\xf2\xee\x6d\x95\xd7\x49\x66\x5d\x71\x12\x5f\xe4\xcc\xdc\x54\xcd\x83\x5b\x64\x4b\xc2\x88\x04\xb8\x00\x28\x59\x77\x75\xff\xfd\x0a\x0d\x80\xa2\x24\x92\x62\xe4\xf8\x6e\x1f\xc2\x97\x44\x24\xd0\xe8\xef\x0f\xa0\xe1\x33\x18\x7d\xbb\x67\x70\x06\x77\x22\x21\x69\x28\x05\xab\xc0\x2e\x08\xae\x0b\x4c\x16\x04\x13\x35\xb3\x6b\xd4\x04\xef\x54\x29\x53\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7c\x5f\x6f\xdb\xb8\x96\xf8\xbb\x3f\xc5\x41\xf3\xd0\x04\xb0\x9d\x3b\xbf\xdf\x60\xb0\xc8\xbd\x7b\x81\xdc\xb4\x9d\x1b\x34\x6d\xb3\x75\x3a\xb3\x03\xcc\x43\x8e\xa5\x63\x9b\x63\x89\xd4\x90\x94\x1d\xef\x62\xbf\xfb\x82\x87\xa4\x2c\xdb\x92\xac\x3a\xcd\xee\x3e\x54\x2f\xad\x25\xf2\xf0\xfc\xff\x43\x1e\xe6\x0c\x46\xdf\xee\x19\x9c\xc1\x9d\x48\x48\x1a\x4a\xc1\x2a\xb0\x0b\x82\xeb\x02\x93\x05\xc1\x44\xcd\xec\x1a\x35\xc1\x3b\x55\x [...] }, "/crd/bases/camel.apache.org_integrationplatforms.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_integrationplatforms.yaml", modTime: time.Time{}, - uncompressedSize: 182031, + uncompressedSize: 182959, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x7b\x73\xe3\x36\x96\x30\x0e\xff\x9f\x4f\x81\x72\x6a\xab\xdd\x5d\x96\xd4\x99\xd9\xcc\x64\xbd\x9b\x7d\x1e\xc7\xdd\x49\x9c\xbe\xd8\x8f\xed\xee\xd9\xa9\x24\x15\x41\xe4\x91\x84\x18\x02\xb8\x00\x28\x5b\x79\xe7\xfd\xee\xbf\xc2\x01\x40\x52\x12\x09\x52\x92\x2f\x9d\x44\x4c\xd5\x4c\xdb\x26\xc0\x73\x80\x83\x73\xc3\xb9\x7c\x4e\x7a\xf7\xf7\x7c\xf6\x39\x79\xcb\x12\x10\x1a\x52\x62\x24\x31\x53\x20\x27\x19\x4d\xa6\x40\xae\xe4\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x7b\x73\xe3\x36\x96\x30\x0e\xff\x9f\x4f\x81\x72\x6a\xab\xdd\x5d\x96\xd4\x99\xd9\xcc\x64\xbd\x9b\x7d\x1e\xc7\xdd\x49\x9c\xbe\xd8\x8f\xed\xee\xd9\xa9\x24\x15\x41\xe4\x91\x84\x18\x02\xb8\x00\x28\x5b\x79\xe7\xfd\xee\xbf\xc2\x01\x40\x52\x12\x09\x52\x92\x2f\x9d\x44\x4c\xd5\x4c\xdb\x26\xc0\x73\x80\x83\x73\xc3\xb9\x7c\x4e\x7a\xf7\xf7\x7c\xf6\x39\x79\xcb\x12\x10\x1a\x52\x62\x24\x31\x53\x20\x27\x19\x4d\xa6\x40\xae\xe4\x [...] }, "/crd/bases/camel.apache.org_integrations.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_integrations.yaml", modTime: time.Time{}, - uncompressedSize: 495936, + uncompressedSize: 496157, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x7b\x73\x1b\x37\xb6\x28\x8a\xff\x9f\x4f\x81\x72\x52\x47\xd2\x8e\x48\xd9\x99\xd9\xa9\x19\xff\xa6\x4e\x4a\x5b\x92\x13\xfd\x62\xcb\x2c\x4b\x49\x4e\xca\xc9\x4e\xc0\x6e\x90\xc4\x51\x13\xe8\x01\xd0\x94\x38\xd7\xf7\xbb\xdf\xc2\x02\xd0\x0f\xbe\x7a\xa1\x45\x3a\xce\x9e\xc6\x54\x65\x4c\x91\xbd\x1a\x8f\x85\xf5\x7e\x7c\x4e\x06\xfb\x1b\x9f\x7d\x4e\x5e\xf3\x84\x09\xcd\x52\x62\x24\x31\x33\x46\xce\x73\x9a\xcc\x18\xb9\x95\x13\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x7b\x73\x1b\x37\xb6\x28\x8a\xff\x9f\x4f\x81\x72\x52\x47\xd2\x8e\x48\xd9\x99\xd9\xa9\x19\xff\xa6\x4e\x4a\x5b\x92\x13\xfd\x62\xcb\x2c\x4b\x49\x4e\xca\xc9\x4e\xc0\x6e\x90\xc4\x51\x13\xe8\x01\xd0\x94\x38\xd7\xf7\xbb\xdf\xc2\x02\xd0\x0f\xbe\x7a\xa1\x45\x3a\xce\x9e\xc6\x54\x65\x4c\x91\xbd\x1a\x8f\x85\xf5\x7e\x7c\x4e\x06\xfb\x1b\x9f\x7d\x4e\x5e\xf3\x84\x09\xcd\x52\x62\x24\x31\x33\x46\xce\x73\x9a\xcc\x18\xb9\x95\x13\x [...] }, "/crd/bases/camel.apache.org_kameletbindings.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_kameletbindings.yaml", modTime: time.Time{}, - uncompressedSize: 575715, + uncompressedSize: 575952, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x6b\x73\x1b\x37\xb6\x30\x0a\x7f\xf7\xaf\x40\xc9\xa9\x47\xd2\x8e\x48\xd9\x99\x99\xd4\x8c\xdf\xa9\x9d\xd2\xc8\x72\xa2\x37\xb6\xcc\xb2\x94\xe4\x49\x39\xd9\x09\xd8\x0d\x92\xd8\xea\x06\x7a\x00\x34\x25\xe6\xf8\xfc\xf7\x53\x58\x00\xfa\xc2\x9b\xb0\x9a\x92\x46\x9e\x69\x4c\x55\xc6\xa4\xd8\xab\x71\x5b\xf7\xdb\x73\x32\xb8\xbf\xf1\xec\x39\x79\xcb\x13\x26\x34\x4b\x89\x91\xc4\xcc\x18\x39\x29\x68\x32\x63\xe4\x52\x4e\xcc\x0d\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x6b\x73\x1b\x37\xb6\x30\x0a\x7f\xf7\xaf\x40\xc9\xa9\x47\xd2\x8e\x48\xd9\x99\x99\xd4\x8c\xdf\xa9\x9d\xd2\xc8\x72\xa2\x37\xb6\xcc\xb2\x94\xe4\x49\x39\xd9\x09\xd8\x0d\x92\xd8\xea\x06\x7a\x00\x34\x25\xe6\xf8\xfc\xf7\x53\x58\x00\xfa\xc2\x9b\xb0\x9a\x92\x46\x9e\x69\x4c\x55\xc6\xa4\xd8\xab\x71\x5b\xf7\xdb\x73\x32\xb8\xbf\xf1\xec\x39\x79\xcb\x13\x26\x34\x4b\x89\x91\xc4\xcc\x18\x39\x29\x68\x32\x63\xe4\x52\x4e\xcc\x0d\x [...] }, "/crd/bases/camel.apache.org_kamelets.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_kamelets.yaml", @@ -166,9 +166,9 @@ var assets = func() http.FileSystem { "/crd/bases/camel.apache.org_pipes.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_pipes.yaml", modTime: time.Time{}, - uncompressedSize: 542983, + uncompressedSize: 543220, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x79\x73\x1b\x37\xb6\x38\x0c\xff\xef\x4f\x81\x92\x53\x3f\x49\x37\x22\x65\x67\x96\x9a\xf1\x3b\x75\x53\xba\xb2\xec\xe8\x8d\x2d\xb3\x2c\x25\xf9\xa5\x9c\xdc\x04\xec\x06\x49\x5c\x75\x03\x7d\x01\x34\x25\xe6\xf1\xf3\xdd\x9f\xc2\x01\xd0\x0b\x37\xe1\x34\x25\x8d\x3c\xd3\x98\xaa\x8c\x49\xb1\x4f\x63\x3b\xfb\xf6\x9c\x0c\xee\x6f\x3c\x7b\x4e\xde\xf1\x84\x09\xcd\x52\x62\x24\x31\x33\x46\x4e\x0a\x9a\xcc\x18\xb9\x94\x13\x73\x43\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xfd\x79\x73\x1b\x37\xb6\x38\x0c\xff\xef\x4f\x81\x92\x53\x3f\x49\x37\x22\x65\x67\x96\x9a\xf1\x3b\x75\x53\xba\xb2\xec\xe8\x8d\x2d\xb3\x2c\x25\xf9\xa5\x9c\xdc\x04\xec\x06\x49\x5c\x75\x03\x7d\x01\x34\x25\xe6\xf1\xf3\xdd\x9f\xc2\x01\xd0\x0b\x37\xe1\x34\x25\x8d\x3c\xd3\x98\xaa\x8c\x49\xb1\x4f\x63\x3b\xfb\xf6\x9c\x0c\xee\x6f\x3c\x7b\x4e\xde\xf1\x84\x09\xcd\x52\x62\x24\x31\x33\x46\x4e\x0a\x9a\xcc\x18\xb9\x94\x13\x73\x43\x [...] }, "/manager": &vfsgen۰DirInfo{ name: "manager", @@ -625,9 +625,9 @@ var assets = func() http.FileSystem { "/traits.yaml": &vfsgen۰CompressedFileInfo{ name: "traits.yaml", modTime: time.Time{}, - uncompressedSize: 66742, + uncompressedSize: 66891, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x6b\x73\x1c\xb9\x91\x28\xfa\x5d\xbf\x02\xc1\xbd\x1b\x24\x75\xfb\x41\x8d\xd7\xde\x59\xee\xca\xbe\x1c\x8d\xc6\xa6\xf5\xe2\x15\x39\xe3\x75\xe8\x28\xdc\xe8\x2a\x74\x37\xd4\xd5\x40\x19\x40\x91\xea\x39\x7b\xfe\xfb\x09\x64\x26\x1e\x55\x5d\xcd\x6e\x4a\xe4\xac\xb9\xf6\x6e\x84\x47\x24\x0b\x89\x44\x22\x91\x48\xe4\xd3\x19\x2e\x9d\x3d\x7d\x32\x64\x8a\xaf\xc4\x29\xfb\x95\x2d\x78\x25\x9e\x30\x56\x57\xdc\xcd\xb4\x59\x9d\xb2\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x6b\x73\x1c\xb9\x91\x28\xfa\x5d\xbf\x02\xc1\xbd\x1b\x24\x75\xfb\x41\x8d\xd7\xde\x59\xee\xca\xbe\x1c\x8d\xc6\xa6\xf5\xe2\x15\x39\xe3\x75\xe8\x28\xdc\xe8\x2a\x74\x37\xd4\xd5\x40\x19\x40\x91\xea\x39\x7b\xfe\xfb\x09\x64\x26\x1e\x55\x5d\xcd\x6e\x4a\xe4\xac\xb9\xf6\x6e\x84\x47\x24\x0b\x89\x44\x22\x91\x48\xe4\xd3\x19\x2e\x9d\x3d\x7d\x32\x64\x8a\xaf\xc4\x29\xfb\x95\x2d\x78\x25\x9e\x30\x56\x57\xdc\xcd\xb4\x59\x9d\xb2\x [...] }, } fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{ diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go index e8b72419f..2d997210e 100644 --- a/pkg/trait/builder.go +++ b/pkg/trait/builder.go @@ -181,9 +181,10 @@ func (t *builderTrait) builderTask(e *Environment) (*v1.BuilderTask, error) { } // The builder trait must define certain resources requirements when we have a native build if ok && pointer.BoolDeref(quarkus.Enabled, true) && (isNativeIntegration || isNativeKit) { - // Force the build to run in a separate Pod + // Force the build to run in a separate Pod and strictly sequential t.L.Info("This is a Quarkus native build: setting build configuration with build Pod strategy, 1 CPU core and 4 GiB memory. Make sure your cluster can handle it.") t.Strategy = string(v1.BuildStrategyPod) + t.OrderStrategy = string(v1.BuildOrderStrategySequential) t.RequestCPU = "1000m" t.RequestMemory = "4Gi" } @@ -198,13 +199,39 @@ func (t *builderTrait) builderTask(e *Environment) (*v1.BuilderTask, error) { if t.Strategy != "" { t.L.Infof("User defined build strategy %s", t.Strategy) - switch t.Strategy { - case string(v1.BuildStrategyPod): - buildConfig.Strategy = v1.BuildStrategyPod - case string(v1.BuildStrategyRoutine): - buildConfig.Strategy = v1.BuildStrategyRoutine - default: - return nil, fmt.Errorf("must specify either pod or routine build strategy, unknown %s", t.Strategy) + found := false + for _, s := range v1.BuildStrategies { + if string(s) == t.Strategy { + found = true + buildConfig.Strategy = s + break + } + } + if !found { + var strategies []string + for _, s := range v1.BuildStrategies { + strategies = append(strategies, string(s)) + } + return nil, fmt.Errorf("unknown build strategy: %s. One of [%s] is expected", t.Strategy, strings.Join(strategies, ", ")) + } + } + + if t.OrderStrategy != "" { + t.L.Infof("User defined build order strategy %s", t.OrderStrategy) + found := false + for _, s := range v1.BuildOrderStrategies { + if string(s) == t.OrderStrategy { + found = true + buildConfig.OrderStrategy = s + break + } + } + if !found { + var strategies []string + for _, s := range v1.BuildOrderStrategies { + strategies = append(strategies, string(s)) + } + return nil, fmt.Errorf("unknown build order strategy: %s. One of [%s] is expected", t.OrderStrategy, strings.Join(strategies, ", ")) } } diff --git a/resources/traits.yaml b/resources/traits.yaml index 9a8f278c9..af06f964c 100755 --- a/resources/traits.yaml +++ b/resources/traits.yaml @@ -212,6 +212,10 @@ traits: - name: strategy type: string description: The strategy to use, either `pod` or `routine` (default routine) + - name: order-strategy + type: string + description: The build order strategy to use, either `fifo` or `sequential` (default + sequential) - name: request-cpu type: string description: When using `pod` strategy, the minimum amount of CPU required by