Skip to content

Commit

Permalink
feat: support kamelet version in Pipe
Browse files Browse the repository at this point in the history
  • Loading branch information
squakez committed Sep 3, 2024
1 parent 8b0981d commit 90739db
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 28 deletions.
4 changes: 3 additions & 1 deletion docs/modules/ROOT/pages/kamelets/kamelets-dev.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,9 @@ 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.

The `.spec.versions` field may not be necessarily supported by the core as it's meant to provide a way to handle versioning on the cluster only. The runtime must be provided with a materialized Kamelet file with the chosen spec (the operator is in charge of that).

== Kamelet data types

Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/kamelets/kamelets-user.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
----
Expand Down
4 changes: 3 additions & 1 deletion docs/modules/ROOT/partials/apis/camel-k-crds.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4141,7 +4141,9 @@ KameletSpec specifies the configuration required to execute a Kamelet.
|
the optional versions available for this Kamelet.
the optional versions available for this Kamelet. This field may not be taken in account by Camel core and is meant to support
any user defined versioning model on cluster only. If the user wants to use any given version, she must materialize a file with the given version spec
as the `main` Kamelet spec on the runtime.
|===
Expand Down
25 changes: 25 additions & 0 deletions e2e/common/traits/files/.camel-jbang/camel-jbang-run.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
loggingLevel=info
loggingColor=true
loggingJson=false
camel.jbang.localKameletDir=file\:.
camel.main.modeline=true
camel.jbang.compileWorkDir=.camel-jbang/compile
camel.jbang.health=false
camel.jbang.metrics=false
camel.jbang.console=false
camel.jbang.verbose=false
camel.jbang.camel-version=4.7.0
camel.jbang.springBootVersion=3.3.1
camel.jbang.quarkusVersion=3.12.0
camel.jbang.kameletsVersion=4.7.0
camel.main.name=kamelet-it-v1
camel.main.routesIncludePattern=file\:kamelet-it-v1.yaml
dependency=mvn\:org.apache.camel\:camel-kamelet\:4.7.0
dependency=mvn\:org.apache.camel\:camel-yaml-dsl\:4.7.0
dependency=mvn\:org.apache.camel\:camel-core-languages\:4.7.0
dependency=mvn\:org.apache.camel\:camel-rest\:4.7.0
dependency=mvn\:org.apache.camel\:camel-rest-openapi\:4.7.0
dependency=mvn\:org.apache.camel\:camel-platform-http\:4.7.0
camel.jbang.platform-http.port=8080
kamelet=my-timer-source
dependency=mvn\:org.apache.camel\:camel-timer\:4.7.0
19 changes: 19 additions & 0 deletions e2e/common/traits/files/kamelet-it-main.yaml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
21 changes: 20 additions & 1 deletion e2e/common/traits/files/kamelet-it-v1.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
# 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"
uri: "kamelet:my-timer-source?kameletVersion=v1"
steps:
- log: "${body}"
17 changes: 17 additions & 0 deletions e2e/common/traits/files/my-timer-source.kamelet.yaml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
5 changes: 4 additions & 1 deletion helm/camel-k/crds/camel-k-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29845,7 +29845,10 @@ spec:
Deprecated: In favor of using DataTypes
type: object
type: object
description: the optional versions available for this Kamelet.
description: |-
the optional versions available for this Kamelet. This field may not be taken in account by Camel core and is meant to support
any user defined versioning model on cluster only. If the user wants to use any given version, she must materialize a file with the given version spec
as the `main` Kamelet spec on the runtime.
type: object
type: object
status:
Expand Down
6 changes: 5 additions & 1 deletion pkg/apis/camel/v1/kamelet_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -77,7 +79,9 @@ type Kamelet struct {
// KameletSpec specifies the configuration required to execute a Kamelet.
type KameletSpec struct {
KameletSpecBase `json:",inline"`
// the optional versions available for this Kamelet.
// the optional versions available for this Kamelet. This field may not be taken in account by Camel core and is meant to support
// any user defined versioning model on cluster only. If the user wants to use any given version, she must materialize a file with the given version spec
// as the `main` Kamelet spec on the runtime.
Versions map[string]KameletSpecBase `json:"versions,omitempty"`
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,10 @@ spec:
Deprecated: In favor of using DataTypes
type: object
type: object
description: the optional versions available for this Kamelet.
description: |-
the optional versions available for this Kamelet. This field may not be taken in account by Camel core and is meant to support
any user defined versioning model on cluster only. If the user wants to use any given version, she must materialize a file with the given version spec
as the `main` Kamelet spec on the runtime.
type: object
type: object
status:
Expand Down
16 changes: 9 additions & 7 deletions pkg/trait/kamelets.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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 ""
Expand Down
6 changes: 3 additions & 3 deletions pkg/trait/kamelets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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))

Expand Down
18 changes: 18 additions & 0 deletions pkg/util/bindings/bindings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
26 changes: 18 additions & 8 deletions pkg/util/bindings/kamelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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,
},
})

Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion pkg/util/source/kamelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions pkg/util/source/kamelet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
}

0 comments on commit 90739db

Please sign in to comment.