You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pc...@apache.org on 2023/05/24 13:50:24 UTC
[camel-k] 03/09: feat(trait): enable custom tasks via builder
This is an automated email from the ASF dual-hosted git repository.
pcongiusti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit c864d653d569354704780d027e9a442af341cfea
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Thu May 18 17:05:21 2023 +0200
feat(trait): enable custom tasks via builder
---
.../bases/camel.apache.org_integrationkits.yaml | 6 +++
.../camel.apache.org_integrationplatforms.yaml | 12 ++++++
.../crd/bases/camel.apache.org_integrations.yaml | 6 +++
.../bases/camel.apache.org_kameletbindings.yaml | 6 +++
config/crd/bases/camel.apache.org_pipes.yaml | 6 +++
config/rbac/operator-role.yaml | 1 +
docs/modules/ROOT/partials/apis/camel-k-crds.adoc | 41 ++++++++++++++++++
e2e/common/traits/builder_test.go | 24 +++++++++++
helm/camel-k/crds/crd-integration-kit.yaml | 6 +++
helm/camel-k/crds/crd-integration-platform.yaml | 12 ++++++
helm/camel-k/crds/crd-integration.yaml | 6 +++
helm/camel-k/crds/crd-kamelet-binding.yaml | 6 +++
helm/camel-k/crds/crd-pipe.yaml | 6 +++
pkg/apis/camel/v1/trait/builder.go | 12 ++++++
pkg/apis/camel/v1/trait/zz_generated.deepcopy.go | 20 +++++++++
pkg/controller/build/build_pod.go | 15 +++++++
pkg/controller/build/monitor_pod.go | 49 +++++++++++-----------
pkg/trait/builder.go | 27 +++++++++++-
pkg/trait/builder_test.go | 29 +++++++++++++
pkg/util/kubernetes/log/util.go | 21 ++++++++++
20 files changed, 285 insertions(+), 26 deletions(-)
diff --git a/config/crd/bases/camel.apache.org_integrationkits.yaml b/config/crd/bases/camel.apache.org_integrationkits.yaml
index 530927802..8ff5668a5 100644
--- a/config/crd/bases/camel.apache.org_integrationkits.yaml
+++ b/config/crd/bases/camel.apache.org_integrationkits.yaml
@@ -229,6 +229,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
diff --git a/config/crd/bases/camel.apache.org_integrationplatforms.yaml b/config/crd/bases/camel.apache.org_integrationplatforms.yaml
index 45fbbb428..94b37247d 100644
--- a/config/crd/bases/camel.apache.org_integrationplatforms.yaml
+++ b/config/crd/bases/camel.apache.org_integrationplatforms.yaml
@@ -727,6 +727,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
@@ -2653,6 +2659,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
diff --git a/config/crd/bases/camel.apache.org_integrations.yaml b/config/crd/bases/camel.apache.org_integrations.yaml
index b29aac0b2..0912bebc7 100644
--- a/config/crd/bases/camel.apache.org_integrations.yaml
+++ b/config/crd/bases/camel.apache.org_integrations.yaml
@@ -6212,6 +6212,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
diff --git a/config/crd/bases/camel.apache.org_kameletbindings.yaml b/config/crd/bases/camel.apache.org_kameletbindings.yaml
index 5707985ca..93b4eba21 100644
--- a/config/crd/bases/camel.apache.org_kameletbindings.yaml
+++ b/config/crd/bases/camel.apache.org_kameletbindings.yaml
@@ -6487,6 +6487,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available
+ only when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components
that support it (e.g. Kaniko build pod).
diff --git a/config/crd/bases/camel.apache.org_pipes.yaml b/config/crd/bases/camel.apache.org_pipes.yaml
index c1f04c4e2..6b166be6b 100644
--- a/config/crd/bases/camel.apache.org_pipes.yaml
+++ b/config/crd/bases/camel.apache.org_pipes.yaml
@@ -6484,6 +6484,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available
+ only when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components
that support it (e.g. Kaniko build pod).
diff --git a/config/rbac/operator-role.yaml b/config/rbac/operator-role.yaml
index 47ac7d44b..975028317 100644
--- a/config/rbac/operator-role.yaml
+++ b/config/rbac/operator-role.yaml
@@ -95,6 +95,7 @@ rules:
- ""
resources:
- pods/proxy
+ - pods/log
verbs:
- get
- apiGroups:
diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index 59e476879..6967c654f 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -5495,6 +5495,13 @@ string
When using `pod` strategy, the maximum amount of memory required by the pod builder.
+|`tasks` +
+[]string
+|
+
+
+A list of tasks to be executed (available only when using `pod` strategy) with format <name>;<container-image>;<container-command>
+
|===
@@ -7504,6 +7511,40 @@ The type of service to be used, either 'ClusterIP', 'NodePort' or 'LoadBalancer'
+[#_camel_apache_org_v1_trait_Task]
+=== Task
+
+A Task is a generic operation run on the project
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`name` +
+string
+|
+
+
+The name of the task to execute
+
+|`image` +
+string
+|
+
+
+The container image to use
+
+|`command` +
+string
+|
+
+
+The command to execute
+
+
+|===
+
[#_camel_apache_org_v1_trait_TolerationTrait]
=== TolerationTrait
diff --git a/e2e/common/traits/builder_test.go b/e2e/common/traits/builder_test.go
index 8eeb0c834..9b47e48ff 100644
--- a/e2e/common/traits/builder_test.go
+++ b/e2e/common/traits/builder_test.go
@@ -95,4 +95,28 @@ func TestBuilderTrait(t *testing.T) {
Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
})
+
+ t.Run("Run custom pipeline task", func(t *testing.T) {
+ Expect(KamelRunWithID(operatorID, ns, "files/Java.java",
+ "--name", name,
+ "-t", "builder.tasks=custom1;alpine;tree",
+ "-t", "builder.tasks=custom2;alpine;cat maven/pom.xml",
+ ).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(BuilderPod(ns, builderKitName), TestTimeoutShort).ShouldNot(BeNil())
+ Eventually(len(BuilderPod(ns, builderKitName)().Spec.InitContainers), TestTimeoutShort).Should(Equal(3))
+ Eventually(BuilderPod(ns, builderKitName)().Spec.InitContainers[0].Name, TestTimeoutShort).Should(Equal("builder"))
+ Eventually(BuilderPod(ns, builderKitName)().Spec.InitContainers[1].Name, TestTimeoutShort).Should(Equal("custom1"))
+ Eventually(BuilderPod(ns, builderKitName)().Spec.InitContainers[2].Name, TestTimeoutShort).Should(Equal("custom2"))
+ Eventually(Logs(ns, builderKitName, corev1.PodLogOptions{Container: "custom1"})).Should(ContainSubstring(`generated-bytecode.jar`))
+ Eventually(Logs(ns, builderKitName, corev1.PodLogOptions{Container: "custom2"})).Should(ContainSubstring(`<artifactId>camel-k-runtime-bom</artifactId>`))
+
+ Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+ })
}
diff --git a/helm/camel-k/crds/crd-integration-kit.yaml b/helm/camel-k/crds/crd-integration-kit.yaml
index 530927802..8ff5668a5 100644
--- a/helm/camel-k/crds/crd-integration-kit.yaml
+++ b/helm/camel-k/crds/crd-integration-kit.yaml
@@ -229,6 +229,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
diff --git a/helm/camel-k/crds/crd-integration-platform.yaml b/helm/camel-k/crds/crd-integration-platform.yaml
index 45fbbb428..94b37247d 100644
--- a/helm/camel-k/crds/crd-integration-platform.yaml
+++ b/helm/camel-k/crds/crd-integration-platform.yaml
@@ -727,6 +727,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
@@ -2653,6 +2659,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
diff --git a/helm/camel-k/crds/crd-integration.yaml b/helm/camel-k/crds/crd-integration.yaml
index b29aac0b2..0912bebc7 100644
--- a/helm/camel-k/crds/crd-integration.yaml
+++ b/helm/camel-k/crds/crd-integration.yaml
@@ -6212,6 +6212,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available only
+ when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components that
support it (e.g. Kaniko build pod).
diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml b/helm/camel-k/crds/crd-kamelet-binding.yaml
index 5707985ca..93b4eba21 100644
--- a/helm/camel-k/crds/crd-kamelet-binding.yaml
+++ b/helm/camel-k/crds/crd-kamelet-binding.yaml
@@ -6487,6 +6487,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available
+ only when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components
that support it (e.g. Kaniko build pod).
diff --git a/helm/camel-k/crds/crd-pipe.yaml b/helm/camel-k/crds/crd-pipe.yaml
index c1f04c4e2..6b166be6b 100644
--- a/helm/camel-k/crds/crd-pipe.yaml
+++ b/helm/camel-k/crds/crd-pipe.yaml
@@ -6484,6 +6484,12 @@ spec:
description: The strategy to use, either `pod` or `routine`
(default routine)
type: string
+ tasks:
+ description: A list of tasks to be executed (available
+ only when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ items:
+ type: string
+ type: array
verbose:
description: Enable verbose logging on build components
that support it (e.g. Kaniko build pod).
diff --git a/pkg/apis/camel/v1/trait/builder.go b/pkg/apis/camel/v1/trait/builder.go
index 4f62bc0b9..282065eec 100644
--- a/pkg/apis/camel/v1/trait/builder.go
+++ b/pkg/apis/camel/v1/trait/builder.go
@@ -37,4 +37,16 @@ type BuilderTrait struct {
LimitCPU string `property:"limit-cpu" json:"limitCPU,omitempty"`
// When using `pod` strategy, the maximum amount of memory required by the pod builder.
LimitMemory string `property:"limit-memory" json:"limitMemory,omitempty"`
+ // A list of tasks to be executed (available only when using `pod` strategy) with format <name>;<container-image>;<container-command>
+ Tasks []string `property:"tasks" json:"tasks,omitempty"`
+}
+
+// A Task is a generic operation run on the project
+type Task struct {
+ // The name of the task to execute
+ Name string `property:"name" json:"name,omitempty"`
+ // The container image to use
+ Image string `property:"image" json:"image,omitempty"`
+ // The command to execute
+ Command string `property:"command" json:"command,omitempty"`
}
diff --git a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
index 6643fcbd7..67f7eb349 100644
--- a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
@@ -64,6 +64,11 @@ func (in *BuilderTrait) DeepCopyInto(out *BuilderTrait) {
*out = make([]string, len(*in))
copy(*out, *in)
}
+ if in.Tasks != nil {
+ in, out := &in.Tasks, &out.Tasks
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuilderTrait.
@@ -978,6 +983,21 @@ func (in *ServiceTrait) DeepCopy() *ServiceTrait {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Task) DeepCopyInto(out *Task) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Task.
+func (in *Task) DeepCopy() *Task {
+ if in == nil {
+ return nil
+ }
+ out := new(Task)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TolerationTrait) DeepCopyInto(out *TolerationTrait) {
*out = *in
diff --git a/pkg/controller/build/build_pod.go b/pkg/controller/build/build_pod.go
index cb738edb4..5f6ab09d5 100644
--- a/pkg/controller/build/build_pod.go
+++ b/pkg/controller/build/build_pod.go
@@ -160,6 +160,8 @@ func newBuildPod(ctx context.Context, c ctrl.Reader, build *v1.Build) (*corev1.P
addBuildTaskToPod(build, task.S2i.Name, pod)
case task.Spectrum != nil:
addBuildTaskToPod(build, task.Spectrum.Name, pod)
+ case task.Custom != nil:
+ addCustomTaskToPod(build, task.Custom, pod)
}
}
@@ -530,6 +532,19 @@ func addKanikoTaskToPod(ctx context.Context, c ctrl.Reader, build *v1.Build, tas
return nil
}
+func addCustomTaskToPod(build *v1.Build, task *v1.UserTask, pod *corev1.Pod) {
+ container := corev1.Container{
+ Name: task.Name,
+ Image: task.ContainerImage,
+ ImagePullPolicy: corev1.PullIfNotPresent,
+ Command: strings.Split(task.ContainerCommand, " "),
+ WorkingDir: filepath.Join(builderDir, build.Name),
+ Env: proxyFromEnvironment(),
+ }
+
+ addContainerToPod(build, container, pod)
+}
+
func addContainerToPod(build *v1.Build, container corev1.Container, pod *corev1.Pod) {
if hasVolume(pod, builderVolume) {
container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
diff --git a/pkg/controller/build/monitor_pod.go b/pkg/controller/build/monitor_pod.go
index 687bfb3ca..2e64e667d 100644
--- a/pkg/controller/build/monitor_pod.go
+++ b/pkg/controller/build/monitor_pod.go
@@ -19,7 +19,6 @@ package build
import (
"context"
- "encoding/json"
"fmt"
"os"
"time"
@@ -36,6 +35,7 @@ import (
v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
"github.com/apache/camel-k/v2/pkg/platform"
"github.com/apache/camel-k/v2/pkg/util/kubernetes"
+ "github.com/apache/camel-k/v2/pkg/util/kubernetes/log"
)
const timeoutAnnotation = "camel.apache.org/timeout"
@@ -169,7 +169,7 @@ func (action *monitorPodAction) Handle(ctx context.Context, build *v1.Build) (*v
case corev1.PodFailed:
phase := v1.BuildPhaseFailed
message := "Pod failed"
- if terminationMessage := action.getTerminationMessage(pod); terminationMessage != "" {
+ if terminationMessage := action.getTerminationMessage(ctx, pod); terminationMessage != "" {
message = terminationMessage
}
if pod.DeletionTimestamp != nil {
@@ -304,37 +304,36 @@ func (action *monitorPodAction) getTerminatedTime(pod *corev1.Pod) metav1.Time {
return finishedAt
}
-func (action *monitorPodAction) getTerminationMessage(pod *corev1.Pod) string {
- var terminationMessages []terminationMessage
-
+func (action *monitorPodAction) getTerminationMessage(ctx context.Context, pod *corev1.Pod) string {
var containers []corev1.ContainerStatus
containers = append(containers, pod.Status.InitContainerStatuses...)
containers = append(containers, pod.Status.ContainerStatuses...)
for _, container := range containers {
- if t := container.State.Terminated; t != nil && t.ExitCode != 0 && t.Message != "" {
- terminationMessages = append(terminationMessages, terminationMessage{
+ if t := container.State.Terminated; t != nil && t.ExitCode != 0 {
+ if t.Message != "" {
+ return fmt.Sprintf("Container %s failed with: %s", container.Name, t.Message)
+ }
+
+ var maxLines int64
+ maxLines = 20
+ logOptions := corev1.PodLogOptions{
Container: container.Name,
- Message: t.Message,
- })
- }
- }
+ TailLines: &maxLines,
+ }
+ message, err := log.DumpLog(ctx, action.client, pod, logOptions)
+ if err != nil {
+ action.L.Errorf(err, "Dumping log for %s Pod failed", pod.Name)
+ return fmt.Sprintf(
+ "Container %s failed. Operator was not able to retrieve the error message, please, check the container log from %s Pod",
+ container.Name,
+ pod.Name,
+ )
+ }
- switch len(terminationMessages) {
- case 0:
- return ""
- case 1:
- return terminationMessages[0].Message
- default:
- message, err := json.Marshal(terminationMessages)
- if err != nil {
- return ""
+ return fmt.Sprintf("Container %s failed with: %s", container.Name, message)
}
- return string(message)
}
-}
-type terminationMessage struct {
- Container string `json:"container,omitempty"`
- Message string `json:"message,omitempty"`
+ return ""
}
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index ea583746b..bd20b38f1 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -20,6 +20,7 @@ package trait
import (
"fmt"
"sort"
+ "strings"
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/pointer"
@@ -61,6 +62,7 @@ func (t *builderTrait) Configure(e *Environment) (bool, error) {
}
func (t *builderTrait) Apply(e *Environment) error {
+ // Building task
builderTask, err := t.builderTask(e)
if err != nil {
e.IntegrationKit.Status.Phase = v1.IntegrationKitPhaseError
@@ -71,9 +73,14 @@ func (t *builderTrait) Apply(e *Environment) error {
}
return nil
}
-
e.Pipeline = append(e.Pipeline, v1.Task{Builder: builderTask})
+ // Custom tasks
+ if t.Tasks != nil {
+ e.Pipeline = append(e.Pipeline, t.customTasks()...)
+ }
+
+ // Publishing task
switch e.Platform.Status.Pipeline.PublishStrategy {
case v1.IntegrationPlatformBuildPublishStrategySpectrum:
e.Pipeline = append(e.Pipeline, v1.Task{Spectrum: &v1.SpectrumTask{
@@ -236,3 +243,21 @@ func getImageName(e *Environment) string {
}
return e.Platform.Status.Pipeline.Registry.Address + "/" + organization + "/camel-k-" + e.IntegrationKit.Name + ":" + e.IntegrationKit.ResourceVersion
}
+
+func (t *builderTrait) customTasks() []v1.Task {
+ var customTasks []v1.Task
+ for _, t := range t.Tasks {
+ // TODO, better strategy than a simple split!
+ splitted := strings.Split(t, ";")
+ customTasks = append(customTasks, v1.Task{
+ Custom: &v1.UserTask{
+ BaseTask: v1.BaseTask{
+ Name: splitted[0],
+ },
+ ContainerImage: splitted[1],
+ ContainerCommand: splitted[2],
+ },
+ })
+ }
+ return customTasks
+}
diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go
index caad574aa..7bd87d41d 100644
--- a/pkg/trait/builder_test.go
+++ b/pkg/trait/builder_test.go
@@ -173,3 +173,32 @@ func createNominalBuilderTraitTest() *builderTrait {
return builderTrait
}
+
+func TestCustomTaskBuilderTrait(t *testing.T) {
+ env := createBuilderTestEnv(v1.IntegrationPlatformClusterKubernetes, v1.IntegrationPlatformBuildPublishStrategySpectrum)
+ builderTrait := createNominalBuilderTraitTest()
+ builderTrait.Tasks = append(builderTrait.Tasks, "test;alpine;ls")
+
+ err := builderTrait.Apply(env)
+
+ assert.Nil(t, err)
+ builderTask := findCustomTaskByName(env.Pipeline, "builder")
+ publisherTask := findCustomTaskByName(env.Pipeline, "spectrum")
+ customTask := findCustomTaskByName(env.Pipeline, "test")
+ assert.NotNil(t, customTask)
+ assert.NotNil(t, builderTask)
+ assert.NotNil(t, publisherTask)
+ assert.Equal(t, 3, len(env.Pipeline))
+ assert.Equal(t, "test", customTask.Custom.Name)
+ assert.Equal(t, "alpine", customTask.Custom.ContainerImage)
+ assert.Equal(t, "ls", customTask.Custom.ContainerCommand)
+}
+
+func findCustomTaskByName(tasks []v1.Task, name string) v1.Task {
+ for _, t := range tasks {
+ if t.Custom != nil && t.Custom.Name == name {
+ return t
+ }
+ }
+ return v1.Task{}
+}
diff --git a/pkg/util/kubernetes/log/util.go b/pkg/util/kubernetes/log/util.go
index 8f9acdb98..f52f58e16 100644
--- a/pkg/util/kubernetes/log/util.go
+++ b/pkg/util/kubernetes/log/util.go
@@ -18,6 +18,7 @@ limitations under the License.
package log
import (
+ "bytes"
"context"
"fmt"
"io"
@@ -25,6 +26,7 @@ import (
v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
"github.com/spf13/cobra"
+ corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
)
@@ -44,3 +46,22 @@ func PrintUsingSelector(ctx context.Context, cmd *cobra.Command, client kubernet
return nil
}
+
+// DumpLog extract the full log from a Pod. Recommended when the quantity of log expected is minimum.
+func DumpLog(ctx context.Context, client kubernetes.Interface, pod *corev1.Pod, podLogOpts corev1.PodLogOptions) (string, error) {
+ req := client.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &podLogOpts)
+ podLogs, err := req.Stream(ctx)
+ if err != nil {
+ return "", err
+ }
+ defer podLogs.Close()
+
+ buf := new(bytes.Buffer)
+ _, err = io.Copy(buf, podLogs)
+ if err != nil {
+ return "", err
+ }
+ str := buf.String()
+
+ return str, nil
+}