diff --git a/docs/modules/ROOT/pages/kamelets/kamelets-dev.adoc b/docs/modules/ROOT/pages/kamelets/kamelets-dev.adoc index da18d483ff..914816a88f 100644 --- a/docs/modules/ROOT/pages/kamelets/kamelets-dev.adoc +++ b/docs/modules/ROOT/pages/kamelets/kamelets-dev.adoc @@ -373,7 +373,7 @@ spec: NOTE: make sure the overall content fits into 1 MiB, which is the storage limit for a Custom Resource. -This is a way to handle multiple version on Kubernetes and may not be supported out of the box by Camel core. If the Integration will require specifically to use `kamelet:my-timer-source?version=v2`, then, the operator will mount properly the specification on the running application. +This is a way to handle multiple version on Kubernetes and may not be supported out of the box by Camel core. If the Integration will require specifically to use `kamelet:my-timer-source?kameletVersion=v2`, then, the operator will mount properly the specification on the running application. == Kamelet data types diff --git a/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc b/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc index 5c84142192..d39814ced0 100644 --- a/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc +++ b/docs/modules/ROOT/pages/kamelets/kamelets-user.adoc @@ -226,7 +226,7 @@ Kamelets provided in a catalog are generally meant to work with a given runtime .kamlet-namedconfig-route.yaml ---- - from: - uri: "timer:tick?version=v2" + uri: "timer:tick?kameletVersion=v2" steps: - to: "log:info" ---- diff --git a/e2e/common/traits/files/kamelet-it-main.yaml b/e2e/common/traits/files/kamelet-it-main.yaml index cbda8d96c5..6dc2d08f2e 100644 --- a/e2e/common/traits/files/kamelet-it-main.yaml +++ b/e2e/common/traits/files/kamelet-it-main.yaml @@ -1,3 +1,22 @@ +# camel-k: language=yaml + +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + - from: uri: "kamelet:my-timer-source" steps: diff --git a/e2e/common/traits/files/kamelet-it-v1.yaml b/e2e/common/traits/files/kamelet-it-v1.yaml index 8f4a0ab7b3..1daf658909 100644 --- a/e2e/common/traits/files/kamelet-it-v1.yaml +++ b/e2e/common/traits/files/kamelet-it-v1.yaml @@ -1,3 +1,22 @@ +# camel-k: language=yaml + +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + - from: uri: "kamelet:my-timer-source?version=v1" steps: diff --git a/e2e/common/traits/files/my-timer-source.kamelet.yaml b/e2e/common/traits/files/my-timer-source.kamelet.yaml index f291e1a110..c389d36487 100644 --- a/e2e/common/traits/files/my-timer-source.kamelet.yaml +++ b/e2e/common/traits/files/my-timer-source.kamelet.yaml @@ -1,3 +1,20 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + apiVersion: camel.apache.org/v1 kind: Kamelet metadata: diff --git a/pkg/apis/camel/v1/kamelet_types.go b/pkg/apis/camel/v1/kamelet_types.go index 7bc28652a4..5279f93752 100644 --- a/pkg/apis/camel/v1/kamelet_types.go +++ b/pkg/apis/camel/v1/kamelet_types.go @@ -49,6 +49,8 @@ var ( reservedKameletNames = map[string]bool{"source": true, "sink": true} // KameletIDProperty used to identify. KameletIDProperty = "id" + // KameletVersionProperty used to specify the version to use. + KameletVersionProperty = "kameletVersion" ) // +genclient diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go index 01a563034f..8e861c5d33 100644 --- a/pkg/trait/kamelets.go +++ b/pkg/trait/kamelets.go @@ -53,6 +53,8 @@ const ( kameletMountPointAnnotation = "camel.apache.org/kamelet.mount-point" ) +var kameletVersionProperty = fmt.Sprintf("?%s=", v1.KameletVersionProperty) + type kameletsTrait struct { BaseTrait traitv1.KameletsTrait `property:",squash"` @@ -181,8 +183,8 @@ func (t *kameletsTrait) addKamelets(e *Environment) error { return err } kb := newKameletBundle() - for version, kamelet := range kamelets { - if err := t.addKameletAsSource(e, kamelet, version); err != nil { + for _, kamelet := range kamelets { + if err := t.addKameletAsSource(e, kamelet); err != nil { return err } // Adding dependencies from Kamelets @@ -218,7 +220,7 @@ func (t *kameletsTrait) addKamelets(e *Environment) error { // This func will add a Kamelet as a generated Integration source. The source included here is going to be used in order to parse the Kamelet // for any component or capability (ie, rest) which is included in the Kamelet spec itself. However, the generated source is marked as coming `FromKamelet`. // When mounting the sources, these generated sources won't be mounted as sources but as Kamelet instead. -func (t *kameletsTrait) addKameletAsSource(e *Environment, kamelet *v1.Kamelet, version string) error { +func (t *kameletsTrait) addKameletAsSource(e *Environment, kamelet *v1.Kamelet) error { sources := make([]v1.SourceSpec, 0) if kamelet.Spec.Template != nil { @@ -281,8 +283,8 @@ func getKameletKey(item string, withVersion bool) string { if strings.Contains(i, "/") { i = strings.SplitN(i, "/", 2)[0] } - if strings.Contains(i, "?version=") { - versionedKamelet := strings.SplitN(i, "?version=", 2) + if strings.Contains(i, kameletVersionProperty) { + versionedKamelet := strings.SplitN(i, kameletVersionProperty, 2) if withVersion { i = fmt.Sprintf("%s-%s", versionedKamelet[0], versionedKamelet[1]) } else { @@ -293,8 +295,8 @@ func getKameletKey(item string, withVersion bool) string { } func getKameletVersion(item string) string { - if strings.Contains(item, "?version=") { - versionedKamelet := strings.SplitN(item, "?version=", 2) + if strings.Contains(item, fmt.Sprintf("?%s=", v1.KameletVersionProperty)) { + versionedKamelet := strings.SplitN(item, kameletVersionProperty, 2) return versionedKamelet[1] } return "" diff --git a/pkg/trait/kamelets_test.go b/pkg/trait/kamelets_test.go index b8937aa6d5..161ac3714f 100644 --- a/pkg/trait/kamelets_test.go +++ b/pkg/trait/kamelets_test.go @@ -54,7 +54,7 @@ func TestConfigurationWithKamelets(t *testing.T) { uri: kamelet:c1 steps: - to: kamelet:c2 - - to: kamelet:c3?version=v1 + - to: kamelet:c3?kameletVersion=v1 - to: telegram:bots - to: kamelet://c0?prop=x - to: kamelet://complex-.-.-1a?prop=x&prop2 @@ -222,7 +222,7 @@ func TestNonYAMLKameletLookup(t *testing.T) { func TestMultipleKamelets(t *testing.T) { trait, environment := createKameletsTestEnvironment(` - from: - uri: kamelet:timer?version=v1 + uri: kamelet:timer?kameletVersion=v1 steps: - to: kamelet:logger `, &v1.Kamelet{ @@ -310,7 +310,7 @@ func TestMultipleKamelets(t *testing.T) { require.NoError(t, err) assert.True(t, enabled) assert.Nil(t, condition) - assert.Equal(t, "logger,timer?version=v1", trait.List) + assert.Equal(t, "logger,timer?kameletVersion=v1", trait.List) assert.Equal(t, []string{"logger", "timer"}, trait.getKameletKeys(false)) assert.Equal(t, []string{"logger", "timer-v1"}, trait.getKameletKeys(true)) diff --git a/pkg/util/bindings/bindings_test.go b/pkg/util/bindings/bindings_test.go index f1e06b7a04..eeff83b805 100644 --- a/pkg/util/bindings/bindings_test.go +++ b/pkg/util/bindings/bindings_test.go @@ -163,6 +163,24 @@ func TestBindings(t *testing.T) { "camel.kamelet.mykamelet.sink.mymessage": "myval", }, }, + { + endpointType: v1.EndpointTypeSink, + endpoint: v1.Endpoint{ + Ref: &corev1.ObjectReference{ + Kind: "Kamelet", + APIVersion: "camel.apache.org/v1any1", + Name: "mykamelet", + }, + Properties: asEndpointProperties(map[string]string{ + "mymessage": "myval", + "kameletVersion": "v1", + }), + }, + uri: "kamelet:mykamelet/sink?kameletVersion=v1", + props: map[string]string{ + "camel.kamelet.mykamelet.sink.mymessage": "myval", + }, + }, { endpoint: v1.Endpoint{ Ref: &corev1.ObjectReference{ diff --git a/pkg/util/bindings/kamelet.go b/pkg/util/bindings/kamelet.go index 300207bad9..d1001c87ed 100644 --- a/pkg/util/bindings/kamelet.go +++ b/pkg/util/bindings/kamelet.go @@ -41,8 +41,6 @@ func (k BindingConverter) ID() string { } // Translate --. -// -//nolint:dupl func (k BindingConverter) Translate(ctx BindingContext, endpointCtx EndpointContext, e v1.Endpoint) (*Binding, error) { if e.Ref == nil { // works only on refs @@ -71,6 +69,12 @@ func (k BindingConverter) Translate(ctx BindingContext, endpointCtx EndpointCont } else { id = endpointCtx.GenerateID() } + version, versionPresent := props[v1.KameletVersionProperty] + if versionPresent { + delete(props, v1.KameletVersionProperty) + } + + kameletTranslated := getKameletName(kameletName, id, version) binding := Binding{} binding.ApplicationProperties = make(map[string]string) @@ -97,7 +101,7 @@ func (k BindingConverter) Translate(ctx BindingContext, endpointCtx EndpointCont steps = append(steps, map[string]interface{}{ "kamelet": map[string]interface{}{ - "name": fmt.Sprintf("%s/%s", kameletName, url.PathEscape(id)), + "name": kameletTranslated, }, }) @@ -126,7 +130,7 @@ func (k BindingConverter) Translate(ctx BindingContext, endpointCtx EndpointCont } } - binding.URI = fmt.Sprintf("kamelet:%s/%s", kameletName, url.PathEscape(id)) + binding.URI = fmt.Sprintf("kamelet:%s", kameletTranslated) case v1.EndpointTypeSink: if in, applicationProperties := k.DataTypeStep(e, id, v1.TypeSlotIn, dataTypeActionKamelet); in != nil { binding.Step = in @@ -135,14 +139,22 @@ func (k BindingConverter) Translate(ctx BindingContext, endpointCtx EndpointCont } } - binding.URI = fmt.Sprintf("kamelet:%s/%s", kameletName, url.PathEscape(id)) + binding.URI = fmt.Sprintf("kamelet:%s", kameletTranslated) default: - binding.URI = fmt.Sprintf("kamelet:%s/%s", kameletName, url.PathEscape(id)) + binding.URI = fmt.Sprintf("kamelet:%s", kameletTranslated) } return &binding, nil } +func getKameletName(name, id, version string) string { + kamelet := fmt.Sprintf("%s/%s", name, url.PathEscape(id)) + if version != "" { + kamelet = fmt.Sprintf("%s?%s=%s", kamelet, v1.KameletVersionProperty, version) + } + return kamelet +} + // DataTypeStep --. func (k BindingConverter) DataTypeStep(e v1.Endpoint, id string, typeSlot v1.TypeSlot, dataTypeActionKamelet string) (map[string]interface{}, map[string]string) { if e.DataTypes == nil { @@ -193,8 +205,6 @@ func (k V1alpha1BindingConverter) ID() string { // Translate -- . // Deprecated. -// -//nolint:dupl func (k V1alpha1BindingConverter) Translate(ctx V1alpha1BindingContext, endpointCtx V1alpha1EndpointContext, e v1alpha1.Endpoint) (*Binding, error) { if e.Ref == nil { // works only on refs diff --git a/pkg/util/source/kamelet.go b/pkg/util/source/kamelet.go index 50a0729395..d44f542a2c 100644 --- a/pkg/util/source/kamelet.go +++ b/pkg/util/source/kamelet.go @@ -20,10 +20,12 @@ package source import ( "fmt" "regexp" + + v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" ) var kameletNameRegexp = regexp.MustCompile("kamelet:(?://)?([a-z0-9-.]+(/[a-z0-9-.]+)?)(?:$|[^a-z0-9-.].*)") -var kameletVersionRegexp = regexp.MustCompile("version=([a-z0-9-.]+)") +var kameletVersionRegexp = regexp.MustCompile(v1.KameletVersionProperty + "=([a-z0-9-.]+)") func ExtractKamelets(uris []string) []string { var kamelets []string diff --git a/pkg/util/source/kamelet_test.go b/pkg/util/source/kamelet_test.go index ad9beace0a..173183c2d3 100644 --- a/pkg/util/source/kamelet_test.go +++ b/pkg/util/source/kamelet_test.go @@ -29,6 +29,6 @@ func TestExtractKamelets(t *testing.T) { assert.Equal(t, "my-test", ExtractKamelet("kamelet:my-test?")) assert.Equal(t, "my-test", ExtractKamelet("kamelet:my-test?option=1")) assert.Equal(t, "my-test", ExtractKamelet("kamelet:my-test?option=1&opt2=2")) - assert.Equal(t, "my-test?version=v1", ExtractKamelet("kamelet:my-test?option=1&opt2=2&version=v1")) - assert.Equal(t, "my-test?version=v1", ExtractKamelet("kamelet:my-test?version=v1")) + assert.Equal(t, "my-test?kameletVersion=v1", ExtractKamelet("kamelet:my-test?option=1&opt2=2&kameletVersion=v1")) + assert.Equal(t, "my-test?kameletVersion=v1", ExtractKamelet("kamelet:my-test?kameletVersion=v1")) }