You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2019/07/24 09:13:49 UTC

[camel-k] 01/02: Fix #856: lookup destination in multiple places and add e2e tests

This is an automated email from the ASF dual-hosted git repository.

nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit d0366d8436c45b23661e71e79ba491c4d6001e35
Author: nferraro <ni...@gmail.com>
AuthorDate: Tue Jul 23 23:21:44 2019 +0200

    Fix #856: lookup destination in multiple places and add e2e tests
---
 e2e/files/knative1.groovy                        | 20 +++++++
 e2e/files/knative2.groovy                        | 19 +++++++
 e2e/files/knativech1.groovy                      | 20 +++++++
 e2e/files/knativech2.groovy                      | 19 +++++++
 e2e/knative_test.go                              | 57 +++++++++++++++++++
 e2e/test_support.go                              | 31 +++++++++-
 pkg/apis/camel/v1alpha1/knative/types_support.go | 10 +---
 pkg/cmd/install.go                               | 13 +++++
 pkg/trait/knative.go                             | 72 +++++++++++++++---------
 script/Makefile                                  |  5 +-
 10 files changed, 230 insertions(+), 36 deletions(-)

diff --git a/e2e/files/knative1.groovy b/e2e/files/knative1.groovy
new file mode 100644
index 0000000..b69fc82
--- /dev/null
+++ b/e2e/files/knative1.groovy
@@ -0,0 +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.
+ */
+
+from('timer:tick')
+  .to('knative:endpoint/knative2')
+  .log('Received: ${body}')
diff --git a/e2e/files/knative2.groovy b/e2e/files/knative2.groovy
new file mode 100644
index 0000000..cb1c6fb
--- /dev/null
+++ b/e2e/files/knative2.groovy
@@ -0,0 +1,19 @@
+/*
+ * 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('knative:endpoint/knative2')
+  .setBody().constant("Hello from knative2")
diff --git a/e2e/files/knativech1.groovy b/e2e/files/knativech1.groovy
new file mode 100644
index 0000000..1a32a64
--- /dev/null
+++ b/e2e/files/knativech1.groovy
@@ -0,0 +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.
+ */
+
+from('timer:tick')
+  .setBody().constant("Hello from knativech1")
+  .to('knative:channel/messages')
diff --git a/e2e/files/knativech2.groovy b/e2e/files/knativech2.groovy
new file mode 100644
index 0000000..65eeb2e
--- /dev/null
+++ b/e2e/files/knativech2.groovy
@@ -0,0 +1,19 @@
+/*
+ * 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('knative:channel/messages')
+  .log('Received: ${body}')
diff --git a/e2e/knative_test.go b/e2e/knative_test.go
new file mode 100644
index 0000000..371add2
--- /dev/null
+++ b/e2e/knative_test.go
@@ -0,0 +1,57 @@
+// +build knative
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "knative"
+
+/*
+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 e2e
+
+import (
+	"testing"
+	"time"
+
+	. "github.com/onsi/gomega"
+	v1 "k8s.io/api/core/v1"
+)
+
+func TestRunServiceCombo(t *testing.T) {
+	withNewTestNamespace(func(ns string) {
+		RegisterTestingT(t)
+		Expect(kamel("install", "-n", ns, "--trait-profile", "knative").Execute()).Should(BeNil())
+		Expect(kamel("run", "-n", ns, "files/knative2.groovy").Execute()).Should(BeNil())
+		Expect(kamel("run", "-n", ns, "files/knative1.groovy").Execute()).Should(BeNil())
+		Eventually(integrationPodPhase(ns, "knative2"), 10*time.Minute).Should(Equal(v1.PodRunning))
+		Eventually(integrationPodPhase(ns, "knative1"), 10*time.Minute).Should(Equal(v1.PodRunning))
+		Eventually(integrationLogs(ns, "knative1"), 5*time.Minute).Should(ContainSubstring("Received: Hello from knative2"))
+		Expect(kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
+	})
+}
+
+func TestRunChannelCombo(t *testing.T) {
+	withNewTestNamespace(func(ns string) {
+		RegisterTestingT(t)
+		Expect(createKnativeChannel(ns, "messages")()).Should(BeNil())
+		Expect(kamel("install", "-n", ns, "--trait-profile", "knative").Execute()).Should(BeNil())
+		Expect(kamel("run", "-n", ns, "files/knativech2.groovy").Execute()).Should(BeNil())
+		Expect(kamel("run", "-n", ns, "files/knativech1.groovy").Execute()).Should(BeNil())
+		Eventually(integrationPodPhase(ns, "knativech2"), 10*time.Minute).Should(Equal(v1.PodRunning))
+		Eventually(integrationPodPhase(ns, "knativech1"), 10*time.Minute).Should(Equal(v1.PodRunning))
+		Eventually(integrationLogs(ns, "knativech2"), 5*time.Minute).Should(ContainSubstring("Received: Hello from knativech1"))
+		Expect(kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
+	})
+}
diff --git a/e2e/test_support.go b/e2e/test_support.go
index 134c825..5a0ca40 100644
--- a/e2e/test_support.go
+++ b/e2e/test_support.go
@@ -1,4 +1,4 @@
-// +build integration
+// +build integration knative
 
 // To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration"
 
@@ -35,6 +35,7 @@ import (
 	"github.com/apache/camel-k/pkg/util/log"
 	"github.com/apache/camel-k/pkg/util/openshift"
 	"github.com/google/uuid"
+	eventing "github.com/knative/eventing/pkg/apis/eventing/v1alpha1"
 	"github.com/onsi/gomega"
 	projectv1 "github.com/openshift/api/project/v1"
 	"github.com/spf13/cobra"
@@ -409,6 +410,34 @@ func scaleOperator(ns string, replicas int32) func() error {
 }
 
 /*
+	Knative
+ */
+
+func createKnativeChannel(ns string, name string) func() error {
+	return func() error {
+		channel := eventing.Channel{
+			TypeMeta: metav1.TypeMeta{
+				Kind: "Channel",
+				APIVersion: eventing.SchemeGroupVersion.String(),
+			},
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: ns,
+				Name: name,
+			},
+			Spec: eventing.ChannelSpec{
+				Provisioner: &v1.ObjectReference{
+					APIVersion: "eventing.knative.dev/v1alpha1",
+					Kind: "ClusterChannelProvisioner",
+					Name: "in-memory",
+				},
+			},
+		}
+		return testClient.Create(testContext, &channel)
+	}
+}
+
+
+/*
 	Namespace testing functions
 */
 
diff --git a/pkg/apis/camel/v1alpha1/knative/types_support.go b/pkg/apis/camel/v1alpha1/knative/types_support.go
index 4c9e53e..f18f35b 100644
--- a/pkg/apis/camel/v1alpha1/knative/types_support.go
+++ b/pkg/apis/camel/v1alpha1/knative/types_support.go
@@ -24,11 +24,7 @@ import (
 )
 
 // BuildCamelServiceDefinition creates a CamelServiceDefinition from a given URL
-func BuildCamelServiceDefinition(name string, serviceType CamelServiceType, rawurl string) (*CamelServiceDefinition, error) {
-	serviceURL, err := url.Parse(rawurl)
-	if err != nil {
-		return nil, err
-	}
+func BuildCamelServiceDefinition(name string, serviceType CamelServiceType, serviceURL url.URL) (CamelServiceDefinition, error) {
 	protocol := CamelProtocol(serviceURL.Scheme)
 	definition := CamelServiceDefinition{
 		Name:        name,
@@ -42,7 +38,7 @@ func BuildCamelServiceDefinition(name string, serviceType CamelServiceType, rawu
 	if portStr != "" {
 		port, err := strconv.Atoi(portStr)
 		if err != nil {
-			return nil, err
+			return CamelServiceDefinition{}, err
 		}
 		definition.Port = port
 	}
@@ -52,7 +48,7 @@ func BuildCamelServiceDefinition(name string, serviceType CamelServiceType, rawu
 	} else {
 		definition.Metadata[CamelMetaServicePath] = "/"
 	}
-	return &definition, nil
+	return definition, nil
 }
 
 func defaultCamelProtocolPort(prot CamelProtocol) int {
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 9f13bb6..166b862 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -73,6 +73,7 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	cmd.Flags().StringSliceVar(&impl.kits, "kit", nil, "Add an integration kit to build at startup")
 	cmd.Flags().StringVar(&impl.buildStrategy, "build-strategy", "", "Set the build strategy")
 	cmd.Flags().StringVar(&impl.buildTimeout, "build-timeout", "", "Set how long the build process can last")
+	cmd.Flags().StringVar(&impl.traitProfile, "trait-profile", "", "The profile to use for traits")
 
 	// maven settings
 	cmd.Flags().StringVar(&impl.localRepository, "local-repository", "", "Location of the local maven repository")
@@ -112,6 +113,7 @@ type installCmdOptions struct {
 	properties        []string
 	kits              []string
 	registry          v1alpha1.IntegrationPlatformRegistrySpec
+	traitProfile      string
 }
 
 // nolint: gocyclo
@@ -208,6 +210,9 @@ func (o *installCmdOptions) install(_ *cobra.Command, _ []string) error {
 
 			platform.Spec.Build.Timeout.Duration = d
 		}
+		if o.traitProfile != "" {
+			platform.Spec.Profile = v1alpha1.TraitProfileByName(o.traitProfile)
+		}
 
 		if len(o.mavenRepositories) > 0 {
 			for _, r := range o.mavenRepositories {
@@ -318,6 +323,14 @@ func (o *installCmdOptions) validate(_ *cobra.Command, _ []string) error {
 		result = multierr.Append(result, err)
 	}
 
+	if o.traitProfile != "" {
+		tp := v1alpha1.TraitProfileByName(o.traitProfile)
+		if tp == v1alpha1.TraitProfile("") {
+			err := fmt.Errorf("unknown trait profile %s", o.traitProfile)
+			result = multierr.Append(result, err)
+		}
+	}
+
 	return result
 }
 
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index 698bee5..6f672ff 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -19,18 +19,19 @@ package trait
 
 import (
 	"fmt"
+	"net/url"
 	"strings"
 
-	"github.com/pkg/errors"
-
-	"github.com/scylladb/go-set/strset"
-
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/metadata"
 	"github.com/apache/camel-k/pkg/util/envvar"
+	"github.com/pkg/errors"
+	"github.com/scylladb/go-set/strset"
 
 	knativeapi "github.com/apache/camel-k/pkg/apis/camel/v1alpha1/knative"
 	knativeutil "github.com/apache/camel-k/pkg/util/knative"
+	duck "github.com/knative/pkg/apis/duck/v1alpha1"
+	serving "github.com/knative/serving/pkg/apis/serving/v1alpha1"
 )
 
 type knativeTrait struct {
@@ -210,19 +211,13 @@ func (t *knativeTrait) configureChannels(e *Environment, env *knativeapi.CamelEn
 		if err != nil {
 			return err
 		}
-		if c == nil || c.Status.Address.Hostname == "" {
-			return errors.New("cannot find address of channel " + ch)
+		if c == nil {
+			return errors.Errorf("cannot find channel %s", ch)
 		}
 
-		svc := knativeapi.CamelServiceDefinition{
-			Name:        ch,
-			Host:        c.Status.Address.Hostname,
-			Port:        80,
-			Protocol:    knativeapi.CamelProtocolHTTP,
-			ServiceType: knativeapi.CamelServiceTypeChannel,
-			Metadata: map[string]string{
-				knativeapi.CamelMetaServicePath: "/",
-			},
+		svc, err := buildCamelServiceDefinitionFromAddressable(ch, knativeapi.CamelServiceTypeChannel, c.Status.Address)
+		if err != nil {
+			return errors.Wrapf(err, "cannot determine address of channel %s", ch)
 		}
 		env.Services = append(env.Services, svc)
 	}
@@ -270,19 +265,12 @@ func (t *knativeTrait) configureEndpoints(e *Environment, env *knativeapi.CamelE
 		if err != nil {
 			return err
 		}
-		if s == nil || s.Status.Address == nil || s.Status.Address.Hostname == "" {
-			return errors.New("cannot find address of endpoint " + endpoint)
+		if s == nil {
+			return errors.Errorf("cannot find endpoint %s", endpoint)
 		}
-
-		svc := knativeapi.CamelServiceDefinition{
-			Name:        endpoint,
-			Host:        s.Status.Address.Hostname,
-			Port:        80,
-			Protocol:    knativeapi.CamelProtocolHTTP,
-			ServiceType: knativeapi.CamelServiceTypeEndpoint,
-			Metadata: map[string]string{
-				knativeapi.CamelMetaServicePath: "/",
-			},
+		svc, err := buildCamelServiceDefinitionFromServiceStatus(endpoint, knativeapi.CamelServiceTypeEndpoint, s.Status)
+		if err != nil {
+			return errors.Wrapf(err, "cannot determine address of endpoint %s", endpoint)
 		}
 		env.Services = append(env.Services, svc)
 	}
@@ -301,3 +289,33 @@ func (t *knativeTrait) extractNames(names string) []string {
 
 	return answer
 }
+
+// buildCamelServiceDefinitionFromServiceStatus creates a CamelServiceDefinition from a Knative ServiceStatus
+func buildCamelServiceDefinitionFromServiceStatus(name string, serviceType knativeapi.CamelServiceType, status serving.ServiceStatus) (knativeapi.CamelServiceDefinition, error) {
+	// build it using the Route URL information if available
+	if status.URL != nil && status.URL.Host != "" {
+		return knativeapi.BuildCamelServiceDefinition(name, serviceType, url.URL(*status.URL))
+	}
+	// fallback to using the addressable
+	if status.Address != nil {
+		return buildCamelServiceDefinitionFromAddressable(name, serviceType, *status.Address)
+	}
+	return knativeapi.CamelServiceDefinition{}, errors.New("cannot determine service hostname")
+}
+
+// buildCamelServiceDefinitionFromAddressable creates a CamelServiceDefinition from a Knative Addressable
+func buildCamelServiceDefinitionFromAddressable(name string, serviceType knativeapi.CamelServiceType, addressable duck.Addressable) (knativeapi.CamelServiceDefinition, error) {
+	// build it using the URL information if available
+	if addressable.URL != nil && addressable.URL.Host != "" {
+		return knativeapi.BuildCamelServiceDefinition(name, serviceType, url.URL(*addressable.URL))
+	}
+	// fallback to using hostname
+	if addressable.Hostname == "" {
+		return knativeapi.CamelServiceDefinition{}, errors.New("cannot determine addressable hostname")
+	}
+	serviceURL, err := url.Parse(fmt.Sprintf("http://%s", addressable.Hostname))
+	if err != nil {
+		return knativeapi.CamelServiceDefinition{}, err
+	}
+	return knativeapi.BuildCamelServiceDefinition(name, serviceType, *serviceURL)
+}
diff --git a/script/Makefile b/script/Makefile
index 90e2a15..f13df4c 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -106,6 +106,9 @@ test: build
 test-integration: build
 	go test -timeout 30m -v ./e2e/... -tags=integration
 
+test-knative: build
+	go test -timeout 30m -v ./e2e/... -tags=knative
+
 build-operator:
 	go build $(GOFLAGS) -o camel-k ./cmd/manager/*.go
 
@@ -124,7 +127,7 @@ build-olm:
 	./script/build_olm.sh $(VERSION)
 
 build-compile-integration-tests:
-	go test -c -tags=integration ./e2e/*.go
+	go test -c -tags="integration knative" ./e2e/*.go
 
 clean:
 	# go clean fails if modules support are turned on as it tries to