From c7852a7d2dd0bb2d24ee9c8eaae1bd41fcf3af90 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Sat, 18 Jan 2025 09:02:40 +0100 Subject: [PATCH] feat(ctrl): leverage core error handler vs trait * Trait was internal and it is removed as no longer needed --- .../ROOT/partials/apis/camel-k-crds.adoc | 2 + e2e/common/traits/error_handler_test.go | 49 -------- pkg/apis/camel/v1/error_handler_types.go | 9 -- .../camel/v1/error_handler_types_support.go | 11 +- .../camel/v1/integration_types_support.go | 2 +- pkg/apis/camel/v1/trait/error_handler.go | 2 + pkg/controller/pipe/error_handler.go | 42 ++++++- pkg/controller/pipe/error_handler_test.go | 24 +--- pkg/controller/pipe/integration.go | 11 ++ pkg/controller/pipe/integration_test.go | 98 ++++++++++++++-- pkg/trait/error_handler.go | 111 ------------------ pkg/trait/error_handler_test.go | 111 ------------------ pkg/trait/kamelets.go | 9 +- pkg/trait/kamelets_test.go | 5 + pkg/trait/trait_register.go | 1 - 15 files changed, 156 insertions(+), 331 deletions(-) delete mode 100644 e2e/common/traits/error_handler_test.go delete mode 100644 pkg/trait/error_handler.go delete mode 100644 pkg/trait/error_handler_test.go diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index fd9a261d07..5731cb6740 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -7030,6 +7030,8 @@ These take precedence over any previously defined environment variables. * <<#_camel_apache_org_v1_Traits, Traits>> +WARNING: This trait is no longer in use. + The error-handler is a platform trait used to inject Error Handler source into the integration runtime. diff --git a/e2e/common/traits/error_handler_test.go b/e2e/common/traits/error_handler_test.go deleted file mode 100644 index d421a99e19..0000000000 --- a/e2e/common/traits/error_handler_test.go +++ /dev/null @@ -1,49 +0,0 @@ -//go:build integration -// +build integration - -// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration" - -/* -Licensed to the Apache Software Foundation (ASF) under one or more -contributor license agreements. See the NOTICE file distributed with -this work for additional information regarding copyright ownership. -The ASF licenses this file to You under the Apache License, Version 2.0 -(the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package common - -import ( - "context" - "testing" - - . "github.com/onsi/gomega" - - corev1 "k8s.io/api/core/v1" - - . "github.com/apache/camel-k/v2/e2e/support" - v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" -) - -func TestErrorHandlerTrait(t *testing.T) { - t.Parallel() - WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) { - t.Run("Run errored integration with error handler", func(t *testing.T) { - name := RandomizedSuffixName("error-handler") - g.Expect(KamelRun(t, ctx, ns, "files/ErroredRoute.java", "--name", name, "-t", "error-handler.enabled=true", "-t", "error-handler.ref=defaultErrorHandler", "-p", "camel.beans.defaultErrorHandler=#class:org.apache.camel.builder.DeadLetterChannelBuilder", "-p", "camel.beans.defaultErrorHandler.deadLetterUri=log:my-special-error-handler-in-place?level=ERROR&showCaughtException=false&showBody=false&showBodyType=false&showExchangePattern=false").Execute()).To(Succeed()) - g.Eventually(IntegrationPodPhase(t, ctx, ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning)) - g.Eventually(IntegrationConditionStatus(t, ctx, ns, name, v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) - g.Eventually(IntegrationLogs(t, ctx, ns, name), TestTimeoutShort).ShouldNot(ContainSubstring("InvalidPayloadException")) - g.Eventually(IntegrationLogs(t, ctx, ns, name), TestTimeoutShort).Should(ContainSubstring("my-special-error-handler-in-place")) - }) - }) -} diff --git a/pkg/apis/camel/v1/error_handler_types.go b/pkg/apis/camel/v1/error_handler_types.go index 49b93d20d6..e272808189 100644 --- a/pkg/apis/camel/v1/error_handler_types.go +++ b/pkg/apis/camel/v1/error_handler_types.go @@ -17,15 +17,6 @@ limitations under the License. package v1 -const ( - // ErrorHandlerRefName the reference name to use when looking for an error handler. - ErrorHandlerRefName = "camel.k.errorHandler.ref" - // ErrorHandlerRefDefaultName the default name of the error handler. - ErrorHandlerRefDefaultName = "defaultErrorHandler" - // ErrorHandlerAppPropertiesPrefix the prefix used for the error handler bean. - ErrorHandlerAppPropertiesPrefix = "camel.beans.defaultErrorHandler" -) - // ErrorHandlerSpec represents an unstructured object for an error handler. type ErrorHandlerSpec struct { RawMessage `json:",inline,omitempty"` diff --git a/pkg/apis/camel/v1/error_handler_types_support.go b/pkg/apis/camel/v1/error_handler_types_support.go index 483c39319d..d12e76d1fd 100644 --- a/pkg/apis/camel/v1/error_handler_types_support.go +++ b/pkg/apis/camel/v1/error_handler_types_support.go @@ -68,10 +68,7 @@ func (e ErrorHandlerNone) Type() ErrorHandlerType { // Configuration --. func (e ErrorHandlerNone) Configuration() (map[string]interface{}, error) { - return map[string]interface{}{ - ErrorHandlerAppPropertiesPrefix: "#class:org.apache.camel.builder.NoErrorHandlerBuilder", - ErrorHandlerRefName: ErrorHandlerRefDefaultName, - }, nil + return map[string]interface{}{}, nil } // ErrorHandlerLog represent a default (log) error handler type. @@ -91,17 +88,12 @@ func (e ErrorHandlerLog) Configuration() (map[string]interface{}, error) { if err != nil { return nil, err } - properties[ErrorHandlerAppPropertiesPrefix] = "#class:org.apache.camel.builder.DefaultErrorHandlerBuilder" - if e.Parameters != nil { var parameters map[string]interface{} err := json.Unmarshal(e.Parameters.RawMessage, ¶meters) if err != nil { return nil, err } - for key, value := range parameters { - properties[ErrorHandlerAppPropertiesPrefix+"."+key] = value - } } return properties, nil @@ -129,7 +121,6 @@ func (e ErrorHandlerSink) Configuration() (map[string]interface{}, error) { if err != nil { return nil, err } - properties[ErrorHandlerAppPropertiesPrefix] = "#class:org.apache.camel.builder.DeadLetterChannelBuilder" return properties, err } diff --git a/pkg/apis/camel/v1/integration_types_support.go b/pkg/apis/camel/v1/integration_types_support.go index c54a4e8867..88c50be276 100644 --- a/pkg/apis/camel/v1/integration_types_support.go +++ b/pkg/apis/camel/v1/integration_types_support.go @@ -502,7 +502,7 @@ func ToYamlDSL(flows []Flow) ([]byte, error) { if err != nil { return nil, err } - jsondata := make([]map[string]interface{}, 0) + var jsondata interface{} d := json.NewDecoder(bytes.NewReader(data)) d.UseNumber() if err := d.Decode(&jsondata); err != nil { diff --git a/pkg/apis/camel/v1/trait/error_handler.go b/pkg/apis/camel/v1/trait/error_handler.go index c84934f646..d52a27ca78 100644 --- a/pkg/apis/camel/v1/trait/error_handler.go +++ b/pkg/apis/camel/v1/trait/error_handler.go @@ -17,6 +17,8 @@ limitations under the License. package trait +// WARNING: This trait is no longer in use. +// // The error-handler is a platform trait used to inject Error Handler source into the integration runtime. // // +camel-k:trait=error-handler. diff --git a/pkg/controller/pipe/error_handler.go b/pkg/controller/pipe/error_handler.go index cdec5aea82..a03ed4f30f 100644 --- a/pkg/controller/pipe/error_handler.go +++ b/pkg/controller/pipe/error_handler.go @@ -26,6 +26,10 @@ import ( "github.com/apache/camel-k/v2/pkg/util/bindings" ) +const defaultCamelErrorHandler = "defaultErrorHandler" + +// maybeErrorHandler will return a Binding mapping a DeadLetterChannel, a Log or a None Error Handler. +// If the bindings has no URI, then, you can assume it's a none Error Handler. func maybeErrorHandler(errHandlConf *v1.ErrorHandlerSpec, bindingContext bindings.BindingContext) (*bindings.Binding, error) { if errHandlConf == nil { return nil, nil @@ -39,7 +43,11 @@ func maybeErrorHandler(errHandlConf *v1.ErrorHandlerSpec, bindingContext binding } // We need to get the translated URI from any referenced resource (ie, kamelets) if errorHandlerSpec.Type() == v1.ErrorHandlerTypeSink { - errorHandlerBinding, err = bindings.Translate(bindingContext, bindings.EndpointContext{Type: v1.EndpointTypeErrorHandler}, *errorHandlerSpec.Endpoint()) + errorHandlerBinding, err = bindings.Translate( + bindingContext, + bindings.EndpointContext{Type: v1.EndpointTypeErrorHandler}, + *errorHandlerSpec.Endpoint(), + ) if err != nil { return nil, fmt.Errorf("could not determine error handler URI: %w", err) } @@ -48,6 +56,9 @@ func maybeErrorHandler(errHandlConf *v1.ErrorHandlerSpec, bindingContext binding errorHandlerBinding = &bindings.Binding{ ApplicationProperties: make(map[string]string), } + if errorHandlerSpec.Type() == v1.ErrorHandlerTypeLog { + errorHandlerBinding.URI = defaultCamelErrorHandler + } } err = setErrorHandlerConfiguration(errorHandlerBinding, errorHandlerSpec) @@ -106,8 +117,31 @@ func setErrorHandlerConfiguration(errorHandlerBinding *bindings.Binding, errorHa for key, value := range properties { errorHandlerBinding.ApplicationProperties[key] = fmt.Sprintf("%v", value) } - if errorHandler.Type() == v1.ErrorHandlerTypeSink && errorHandlerBinding.URI != "" { - errorHandlerBinding.ApplicationProperties[fmt.Sprintf("%s.deadLetterUri", v1.ErrorHandlerAppPropertiesPrefix)] = errorHandlerBinding.URI - } + return nil } + +// translateCamelErrorHandler will translate a binding as an error handler YAML as expected by Camel. +func translateCamelErrorHandler(b *bindings.Binding) map[string]interface{} { + yamlCode := map[string]interface{}{} + switch b.URI { + case "": + yamlCode["errorHandler"] = map[string]interface{}{ + "noErrorHandler": map[string]interface{}{}, + } + case defaultCamelErrorHandler: + yamlCode["errorHandler"] = map[string]interface{}{ + "defaultErrorHandler": map[string]interface{}{ + "logName": "err", + }, + } + default: + yamlCode["errorHandler"] = map[string]interface{}{ + "deadLetterChannel": map[string]interface{}{ + "deadLetterUri": b.URI, + }, + } + } + + return yamlCode +} diff --git a/pkg/controller/pipe/error_handler_test.go b/pkg/controller/pipe/error_handler_test.go index 4cd751f8d2..9ec0f19840 100644 --- a/pkg/controller/pipe/error_handler_test.go +++ b/pkg/controller/pipe/error_handler_test.go @@ -31,10 +31,8 @@ func TestParseErrorHandlerNoneDoesSucceed(t *testing.T) { ) require.NoError(t, err) assert.Equal(t, v1.ErrorHandlerTypeNone, noErrorHandler.Type()) - parameters, err := noErrorHandler.Configuration() + _, err = noErrorHandler.Configuration() require.NoError(t, err) - assert.Equal(t, "#class:org.apache.camel.builder.NoErrorHandlerBuilder", parameters[v1.ErrorHandlerAppPropertiesPrefix]) - assert.Equal(t, v1.ErrorHandlerRefDefaultName, parameters[v1.ErrorHandlerRefName]) } func TestParseErrorHandlerLogDoesSucceed(t *testing.T) { @@ -43,10 +41,8 @@ func TestParseErrorHandlerLogDoesSucceed(t *testing.T) { ) require.NoError(t, err) assert.Equal(t, v1.ErrorHandlerTypeLog, logErrorHandler.Type()) - parameters, err := logErrorHandler.Configuration() + _, err = logErrorHandler.Configuration() require.NoError(t, err) - assert.Equal(t, "#class:org.apache.camel.builder.DefaultErrorHandlerBuilder", parameters[v1.ErrorHandlerAppPropertiesPrefix]) - assert.Equal(t, v1.ErrorHandlerRefDefaultName, parameters[v1.ErrorHandlerRefName]) } func TestParseErrorHandlerLogWithParametersDoesSucceed(t *testing.T) { @@ -55,12 +51,8 @@ func TestParseErrorHandlerLogWithParametersDoesSucceed(t *testing.T) { ) require.NoError(t, err) assert.Equal(t, v1.ErrorHandlerTypeLog, logErrorHandler.Type()) - parameters, err := logErrorHandler.Configuration() + _, err = logErrorHandler.Configuration() require.NoError(t, err) - assert.Equal(t, "#class:org.apache.camel.builder.DefaultErrorHandlerBuilder", parameters[v1.ErrorHandlerAppPropertiesPrefix]) - assert.Equal(t, "value1", parameters["camel.beans.defaultErrorHandler.param1"]) - assert.Equal(t, "value2", parameters["camel.beans.defaultErrorHandler.param2"]) - assert.Equal(t, v1.ErrorHandlerRefDefaultName, parameters[v1.ErrorHandlerRefName]) } func TestParseErrorHandlerSinkDoesSucceed(t *testing.T) { @@ -71,10 +63,8 @@ func TestParseErrorHandlerSinkDoesSucceed(t *testing.T) { assert.NotNil(t, sinkErrorHandler) assert.Equal(t, v1.ErrorHandlerTypeSink, sinkErrorHandler.Type()) assert.Equal(t, "someUri", *sinkErrorHandler.Endpoint().URI) - parameters, err := sinkErrorHandler.Configuration() + _, err = sinkErrorHandler.Configuration() require.NoError(t, err) - assert.Equal(t, "#class:org.apache.camel.builder.DeadLetterChannelBuilder", parameters[v1.ErrorHandlerAppPropertiesPrefix]) - assert.Equal(t, v1.ErrorHandlerRefDefaultName, parameters[v1.ErrorHandlerRefName]) } func TestParseErrorHandlerSinkWithParametersDoesSucceed(t *testing.T) { @@ -93,12 +83,8 @@ func TestParseErrorHandlerSinkWithParametersDoesSucceed(t *testing.T) { assert.NotNil(t, sinkErrorHandler) assert.Equal(t, v1.ErrorHandlerTypeSink, sinkErrorHandler.Type()) assert.Equal(t, "someUri", *sinkErrorHandler.Endpoint().URI) - parameters, err := sinkErrorHandler.Configuration() + _, err = sinkErrorHandler.Configuration() require.NoError(t, err) - assert.Equal(t, "#class:org.apache.camel.builder.DeadLetterChannelBuilder", parameters[v1.ErrorHandlerAppPropertiesPrefix]) - assert.Equal(t, v1.ErrorHandlerRefDefaultName, parameters[v1.ErrorHandlerRefName]) - assert.Equal(t, "value1", parameters["camel.beans.defaultErrorHandler.param1"]) - assert.Equal(t, "value2", parameters["camel.beans.defaultErrorHandler.param2"]) } func TestParseErrorHandlerSinkFail(t *testing.T) { diff --git a/pkg/controller/pipe/integration.go b/pkg/controller/pipe/integration.go index 95d18722ee..d093295c6d 100644 --- a/pkg/controller/pipe/integration.go +++ b/pkg/controller/pipe/integration.go @@ -204,10 +204,21 @@ func CreateIntegrationFor(ctx context.Context, c client.Client, binding *v1.Pipe "from": fromWrapper, }, } + + if errorHandler != nil { + eh := translateCamelErrorHandler(errorHandler) + encodedErrorHandler, err := json.Marshal(eh) + if err != nil { + return nil, err + } + it.Spec.Flows = append(it.Spec.Flows, v1.Flow{RawMessage: encodedErrorHandler}) + } + encodedRoute, err := json.Marshal(flowRoute) if err != nil { return nil, err } + it.Spec.Flows = append(it.Spec.Flows, v1.Flow{RawMessage: encodedRoute}) return &it, nil diff --git a/pkg/controller/pipe/integration_test.go b/pkg/controller/pipe/integration_test.go index d5756003fd..fe7868b225 100644 --- a/pkg/controller/pipe/integration_test.go +++ b/pkg/controller/pipe/integration_test.go @@ -54,6 +54,38 @@ func TestCreateIntegrationForPipe(t *testing.T) { assert.Equal(t, expectedNominalRoute(), string(dsl)) } +func TestCreateIntegrationForPipeWithSinkKameletErrorHandler(t *testing.T) { + client, err := internal.NewFakeClient() + require.NoError(t, err) + + pipe := nominalPipe("my-error-handler-pipe") + pipe.Spec.ErrorHandler = &v1.ErrorHandlerSpec{ + RawMessage: []byte(`{"sink": {"endpoint": {"ref": {"kind": "Kamelet", "apiVersion": "camel.apache.org/v1", "name": "my-err"}}}}`), + } + + it, err := CreateIntegrationFor(context.TODO(), client, &pipe) + require.NoError(t, err) + assert.Equal(t, "my-error-handler-pipe", it.Name) + assert.Equal(t, "default", it.Namespace) + assert.Equal(t, "camel.apache.org/v1", it.OwnerReferences[0].APIVersion) + assert.Equal(t, "Pipe", it.OwnerReferences[0].Kind) + assert.Equal(t, "my-error-handler-pipe", it.OwnerReferences[0].Name) + dsl, err := v1.ToYamlDSL(it.Spec.Flows) + require.NoError(t, err) + assert.Equal(t, + `- errorHandler: + deadLetterChannel: + deadLetterUri: kamelet:my-err/errorHandler +- route: + from: + steps: + - to: kamelet:my-sink/sink + uri: kamelet:my-source/source + id: binding +`, string(dsl), + ) +} + func TestCreateIntegrationForPipeWithSinkErrorHandler(t *testing.T) { client, err := internal.NewFakeClient() require.NoError(t, err) @@ -70,13 +102,20 @@ func TestCreateIntegrationForPipeWithSinkErrorHandler(t *testing.T) { assert.Equal(t, "camel.apache.org/v1", it.OwnerReferences[0].APIVersion) assert.Equal(t, "Pipe", it.OwnerReferences[0].Kind) assert.Equal(t, "my-error-handler-pipe", it.OwnerReferences[0].Name) - assert.Len(t, it.Spec.Configuration, 3) - assert.Equal(t, "#class:org.apache.camel.builder.DeadLetterChannelBuilder", it.Spec.GetConfigurationProperty("camel.beans.defaultErrorHandler")) - assert.Equal(t, "someUri", it.Spec.GetConfigurationProperty("camel.beans.defaultErrorHandler.deadLetterUri")) - assert.Equal(t, "defaultErrorHandler", it.Spec.GetConfigurationProperty(v1.ErrorHandlerRefName)) dsl, err := v1.ToYamlDSL(it.Spec.Flows) require.NoError(t, err) - assert.Equal(t, expectedNominalRoute(), string(dsl)) + assert.Equal(t, + `- errorHandler: + deadLetterChannel: + deadLetterUri: someUri +- route: + from: + steps: + - to: kamelet:my-sink/sink + uri: kamelet:my-source/source + id: binding +`, string(dsl), + ) } func TestCreateIntegrationForPipeWithLogErrorHandler(t *testing.T) { @@ -95,13 +134,52 @@ func TestCreateIntegrationForPipeWithLogErrorHandler(t *testing.T) { assert.Equal(t, "camel.apache.org/v1", it.OwnerReferences[0].APIVersion) assert.Equal(t, "Pipe", it.OwnerReferences[0].Kind) assert.Equal(t, "my-error-handler-pipe", it.OwnerReferences[0].Name) - assert.Len(t, it.Spec.Configuration, 3) - assert.Equal(t, "#class:org.apache.camel.builder.DefaultErrorHandlerBuilder", it.Spec.GetConfigurationProperty("camel.beans.defaultErrorHandler")) - assert.Equal(t, "true", it.Spec.GetConfigurationProperty("camel.beans.defaultErrorHandler.showHeaders")) - assert.Equal(t, "defaultErrorHandler", it.Spec.GetConfigurationProperty(v1.ErrorHandlerRefName)) dsl, err := v1.ToYamlDSL(it.Spec.Flows) require.NoError(t, err) - assert.Equal(t, expectedNominalRoute(), string(dsl)) + assert.Equal(t, + `- errorHandler: + defaultErrorHandler: + logName: err +- route: + from: + steps: + - to: kamelet:my-sink/sink + uri: kamelet:my-source/source + id: binding +`, string(dsl), + ) +} + +func TestCreateIntegrationForPipeWithNoneErrorHandler(t *testing.T) { + client, err := internal.NewFakeClient() + require.NoError(t, err) + + pipe := nominalPipe("my-error-handler-pipe") + pipe.Spec.ErrorHandler = &v1.ErrorHandlerSpec{ + RawMessage: []byte(`{"none": {}}`), + } + + it, err := CreateIntegrationFor(context.TODO(), client, &pipe) + require.NoError(t, err) + assert.Equal(t, "my-error-handler-pipe", it.Name) + assert.Equal(t, "default", it.Namespace) + assert.Equal(t, "camel.apache.org/v1", it.OwnerReferences[0].APIVersion) + assert.Equal(t, "Pipe", it.OwnerReferences[0].Kind) + assert.Equal(t, "my-error-handler-pipe", it.OwnerReferences[0].Name) + dsl, err := v1.ToYamlDSL(it.Spec.Flows) + require.NoError(t, err) + assert.Equal(t, + `- errorHandler: + noErrorHandler: {} +- route: + from: + steps: + - to: kamelet:my-sink/sink + uri: kamelet:my-source/source + id: binding +`, + string(dsl), + ) } func TestCreateIntegrationForPipeDataType(t *testing.T) { diff --git a/pkg/trait/error_handler.go b/pkg/trait/error_handler.go deleted file mode 100644 index 05eabeaa19..0000000000 --- a/pkg/trait/error_handler.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one or more -contributor license agreements. See the NOTICE file distributed with -this work for additional information regarding copyright ownership. -The ASF licenses this file to You under the Apache License, Version 2.0 -(the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package trait - -import ( - "fmt" - "strings" - - "gopkg.in/yaml.v2" - - v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" - "github.com/apache/camel-k/v2/pkg/util" -) - -const ( - errorHandlerTraitID = "error-handler" - errorHandlerTraitOrder = 470 -) - -type errorHandlerTrait struct { - BasePlatformTrait - traitv1.ErrorHandlerTrait `property:",squash"` -} - -func newErrorHandlerTrait() Trait { - return &errorHandlerTrait{ - // NOTE: Must run before dependency trait - BasePlatformTrait: NewBasePlatformTrait(errorHandlerTraitID, errorHandlerTraitOrder), - } -} - -func (t *errorHandlerTrait) Configure(e *Environment) (bool, *TraitCondition, error) { - if e.Integration == nil { - return false, nil, nil - } - if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() { - return false, nil, nil - } - if t.ErrorHandlerRef == "" { - t.ErrorHandlerRef = e.Integration.Spec.GetConfigurationProperty(v1.ErrorHandlerRefName) - } - - return t.ErrorHandlerRef != "", nil, nil -} - -func (t *errorHandlerTrait) Apply(e *Environment) error { - if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) { - // If the user configure directly the URI, we need to auto-discover the underlying component - // and add the related dependency - defaultErrorHandlerURI := e.Integration.Spec.GetConfigurationProperty( - fmt.Sprintf("%s.deadLetterUri", v1.ErrorHandlerAppPropertiesPrefix)) - if defaultErrorHandlerURI != "" && !strings.HasPrefix(defaultErrorHandlerURI, "kamelet:") { - t.addErrorHandlerDependencies(e, defaultErrorHandlerURI) - } - - return t.addGlobalErrorHandlerAsSource(e) - } - return nil -} - -func (t *errorHandlerTrait) addErrorHandlerDependencies(e *Environment, uri string) { - candidateComp, scheme := e.CamelCatalog.DecodeComponent(uri) - if candidateComp != nil { - util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, candidateComp.GetDependencyID()) - if scheme != nil { - for _, dep := range candidateComp.GetProducerDependencyIDs(scheme.ID) { - util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, dep) - } - } - } -} - -func (t *errorHandlerTrait) addGlobalErrorHandlerAsSource(e *Environment) error { - flowErrorHandler := map[string]interface{}{ - "errorHandler": map[string]string{ - "refErrorHandler": t.ErrorHandlerRef, - }, - } - encodedFlowErrorHandler, err := yaml.Marshal([]map[string]interface{}{flowErrorHandler}) - if err != nil { - return err - } - errorHandlerSource := v1.SourceSpec{ - DataSpec: v1.DataSpec{ - Name: "camel-k-embedded-error-handler.yaml", - Content: string(encodedFlowErrorHandler), - }, - Language: v1.LanguageYaml, - Type: v1.SourceTypeErrorHandler, - } - - e.Integration.Status.AddOrReplaceGeneratedSources(errorHandlerSource) - - return nil -} diff --git a/pkg/trait/error_handler_test.go b/pkg/trait/error_handler_test.go deleted file mode 100644 index 4f6ed61687..0000000000 --- a/pkg/trait/error_handler_test.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one or more -contributor license agreements. See the NOTICE file distributed with -this work for additional information regarding copyright ownership. -The ASF licenses this file to You under the Apache License, Version 2.0 -(the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package trait - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - "github.com/apache/camel-k/v2/pkg/util/camel" -) - -func TestErrorHandlerConfigureFromIntegrationProperty(t *testing.T) { - catalog, err := camel.DefaultCatalog() - require.NoError(t, err) - e := &Environment{ - CamelCatalog: catalog, - Catalog: NewEnvironmentTestCatalog(), - Integration: &v1.Integration{}, - } - e.Integration.Spec.AddConfigurationProperty(fmt.Sprintf("%v = %s", v1.ErrorHandlerRefName, "defaultErrorHandler")) - - trait := newErrorHandlerTrait() - enabled, condition, err := trait.Configure(e) - require.NoError(t, err) - assert.False(t, enabled) - assert.Nil(t, condition) - - e.Integration.Status.Phase = v1.IntegrationPhaseNone - enabled, condition, err = trait.Configure(e) - require.NoError(t, err) - assert.False(t, enabled) - assert.Nil(t, condition) - - e.Integration.Status.Phase = v1.IntegrationPhaseInitialization - enabled, condition, err = trait.Configure(e) - require.NoError(t, err) - assert.True(t, enabled) - assert.Nil(t, condition) - -} - -func TestErrorHandlerApplySource(t *testing.T) { - catalog, err := camel.DefaultCatalog() - require.NoError(t, err) - e := &Environment{ - CamelCatalog: catalog, - Catalog: NewEnvironmentTestCatalog(), - Integration: &v1.Integration{}, - } - e.Integration.Spec.AddConfiguration("property", fmt.Sprintf("%v = %s", v1.ErrorHandlerRefName, "defaultErrorHandler")) - e.Integration.Status.Phase = v1.IntegrationPhaseInitialization - - trait := newErrorHandlerTrait() - enabled, condition, err := trait.Configure(e) - require.NoError(t, err) - assert.True(t, enabled) - assert.Nil(t, condition) - - err = trait.Apply(e) - require.NoError(t, err) - assert.Equal(t, `- errorHandler: - refErrorHandler: defaultErrorHandler -`, e.Integration.Status.GeneratedSources[0].Content) -} - -func TestErrorHandlerApplyDependency(t *testing.T) { - c, err := camel.DefaultCatalog() - require.NoError(t, err) - e := &Environment{ - Catalog: NewEnvironmentTestCatalog(), - CamelCatalog: c, - Integration: &v1.Integration{}, - } - e.Integration.Spec.AddConfigurationProperty("camel.beans.defaultErrorHandler = #class:org.apache.camel.builder.DeadLetterChannelBuilder") - e.Integration.Spec.AddConfigurationProperty("camel.beans.defaultErrorHandler.deadLetterUri = log:info") - e.Integration.Spec.AddConfigurationProperty(fmt.Sprintf("%v = %s", v1.ErrorHandlerRefName, "defaultErrorHandler")) - e.Integration.Status.Phase = v1.IntegrationPhaseInitialization - - trait := newErrorHandlerTrait() - enabled, condition, err := trait.Configure(e) - require.NoError(t, err) - assert.True(t, enabled) - assert.Nil(t, condition) - - err = trait.Apply(e) - require.NoError(t, err) - assert.Len(t, e.Integration.Spec.Configuration, 3) - assert.Equal(t, "#class:org.apache.camel.builder.DeadLetterChannelBuilder", e.Integration.Spec.GetConfigurationProperty("camel.beans.defaultErrorHandler")) - assert.Equal(t, "log:info", e.Integration.Spec.GetConfigurationProperty("camel.beans.defaultErrorHandler.deadLetterUri")) - assert.Equal(t, "defaultErrorHandler", e.Integration.Spec.GetConfigurationProperty(v1.ErrorHandlerRefName)) - assert.Equal(t, "camel:log", e.Integration.Status.Dependencies[0]) -} diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go index f587b5109a..bf52ac6198 100644 --- a/pkg/trait/kamelets.go +++ b/pkg/trait/kamelets.go @@ -39,7 +39,6 @@ import ( "github.com/apache/camel-k/v2/pkg/util/camel" "github.com/apache/camel-k/v2/pkg/util/digest" "github.com/apache/camel-k/v2/pkg/util/dsl" - "github.com/apache/camel-k/v2/pkg/util/source" ) const ( @@ -48,6 +47,7 @@ const ( contentKey = "content" KameletLocationProperty = "camel.component.kamelet.location" + KameletErrorHandler = "camel.component.kamelet.no-error-handler" kameletMountPointAnnotation = "camel.apache.org/kamelet.mount-point" ) @@ -83,11 +83,6 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, *TraitCondition, error) if err != nil { return false, nil, err } - // Check if a Kamelet is configured as default error handler URI - defaultErrorHandlerURI := e.Integration.Spec.GetConfigurationProperty(v1.ErrorHandlerAppPropertiesPrefix + ".deadLetterUri") - if defaultErrorHandlerURI != "" && strings.HasPrefix(defaultErrorHandlerURI, "kamelet:") { - kamelets = append(kamelets, source.ExtractKamelet(defaultErrorHandlerURI)) - } if len(kamelets) > 0 { sort.Strings(kamelets) t.List = strings.Join(kamelets, ",") @@ -228,6 +223,8 @@ func (t *kameletsTrait) addKamelets(e *Environment) error { } } e.ApplicationProperties[KameletLocationProperty] += ",classpath:/kamelets" + // required because of https://issues.apache.org/jira/browse/CAMEL-21599 + e.ApplicationProperties[KameletErrorHandler] = "false" // resort dependencies sort.Strings(e.Integration.Status.Dependencies) diff --git a/pkg/trait/kamelets_test.go b/pkg/trait/kamelets_test.go index ef6820f4ea..43275de86b 100644 --- a/pkg/trait/kamelets_test.go +++ b/pkg/trait/kamelets_test.go @@ -747,4 +747,9 @@ func TestKameletAuto(t *testing.T) { assert.Equal(t, traitv1.KameletsTrait{ List: "none,timer", }, trait.KameletsTrait) + assert.Equal(t, + "file:/etc/camel/kamelets/kamelets-bundle-it-001,classpath:/kamelets", + environment.ApplicationProperties[KameletLocationProperty], + ) + assert.Equal(t, "false", environment.ApplicationProperties[KameletErrorHandler]) } diff --git a/pkg/trait/trait_register.go b/pkg/trait/trait_register.go index 6d543a88bd..e214027837 100644 --- a/pkg/trait/trait_register.go +++ b/pkg/trait/trait_register.go @@ -29,7 +29,6 @@ func init() { AddToTraits(newDeployerTrait) AddToTraits(newDeploymentTrait) AddToTraits(newEnvironmentTrait) - AddToTraits(newErrorHandlerTrait) AddToTraits(newGCTrait) AddToTraits(newHealthTrait) AddToTraits(NewInitTrait)