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 2024/10/19 10:12:48 UTC

(camel-k) branch main updated: feat(trait): deprecate openapi trait

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


The following commit(s) were added to refs/heads/main by this push:
     new 699810e2b feat(trait): deprecate openapi trait
699810e2b is described below

commit 699810e2bdf3a0cfa7930c4dc6702e54eeb6b8e2
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Tue Oct 15 22:28:25 2024 +0200

    feat(trait): deprecate openapi trait
    
    In favour of contract first openapi Camel feature
    
    Closes #5729
---
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc  |  3 ++
 docs/modules/traits/pages/openapi.adoc             |  4 +++
 .../files/openapi => misc/files}/petstore-api.yaml |  0
 .../files/openapi => misc/files}/petstore.yaml     |  4 +++
 e2e/common/{traits => misc}/openapi_test.go        | 35 ++++++++++++++--------
 e2e/support/test_support.go                        | 20 -------------
 pkg/apis/camel/v1/trait/openapi.go                 |  4 +++
 pkg/apis/camel/v1/trait/service_binding.go         |  2 +-
 pkg/trait/openapi.go                               | 17 +++++++----
 pkg/trait/openapi_test.go                          |  6 +++-
 pkg/util/source/inspector.go                       |  7 +++++
 pkg/util/source/inspector_java_source_test.go      | 19 ++++++++++++
 pkg/util/source/inspector_xml.go                   |  5 ++++
 pkg/util/source/inspector_xml_test.go              | 23 ++++++++++++++
 pkg/util/source/inspector_yaml.go                  | 23 ++++++++++++++
 pkg/util/source/inspector_yaml_test.go             | 28 +++++++++++++++++
 16 files changed, 160 insertions(+), 40 deletions(-)

diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index cae7017d4..c778d4ff4 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -8047,6 +8047,9 @@ Deprecated: no longer available since version 2.5.
 
 The OpenAPI DSL trait is internally used to allow creating integrations from a OpenAPI specs.
 
+WARNING: The Openapi trait is **deprecated** and will removed in future release versions:
+use Camel REST contract first instead, https://camel.apache.org/manual/rest-dsl-openapi.html
+
 
 [cols="2,2a",options="header"]
 |===
diff --git a/docs/modules/traits/pages/openapi.adoc b/docs/modules/traits/pages/openapi.adoc
index 28f985dd6..f4276164e 100755
--- a/docs/modules/traits/pages/openapi.adoc
+++ b/docs/modules/traits/pages/openapi.adoc
@@ -1,10 +1,14 @@
 = Openapi Trait
 
 // Start of autogenerated code - DO NOT EDIT! (badges)
+image:https://img.shields.io/badge/2.5.0-white?label=Deprecated&labelColor=C40C0C&color=gray[Deprecated Badge]
 // End of autogenerated code - DO NOT EDIT! (badges)
 // Start of autogenerated code - DO NOT EDIT! (description)
 The OpenAPI DSL trait is internally used to allow creating integrations from a OpenAPI specs.
 
+WARNING: The Openapi trait is **deprecated** and will removed in future release versions:
+use Camel REST contract first instead, https://camel.apache.org/manual/rest-dsl-openapi.html
+
 
 This trait is available in the following profiles: **Kubernetes, Knative, OpenShift**.
 
diff --git a/e2e/common/traits/files/openapi/petstore-api.yaml b/e2e/common/misc/files/petstore-api.yaml
similarity index 100%
rename from e2e/common/traits/files/openapi/petstore-api.yaml
rename to e2e/common/misc/files/petstore-api.yaml
diff --git a/e2e/common/traits/files/openapi/petstore.yaml b/e2e/common/misc/files/petstore.yaml
similarity index 95%
rename from e2e/common/traits/files/openapi/petstore.yaml
rename to e2e/common/misc/files/petstore.yaml
index 72087814f..ca4e483e3 100644
--- a/e2e/common/traits/files/openapi/petstore.yaml
+++ b/e2e/common/misc/files/petstore.yaml
@@ -17,6 +17,10 @@
 # limitations under the License.
 # ---------------------------------------------------------------------------
 
+- rest:
+    openApi:
+      specification: petstore-api.yaml
+
 - from:
     uri: "direct:listPets"
     steps:
diff --git a/e2e/common/traits/openapi_test.go b/e2e/common/misc/openapi_test.go
similarity index 56%
rename from e2e/common/traits/openapi_test.go
rename to e2e/common/misc/openapi_test.go
index 217738d60..e98dd7596 100644
--- a/e2e/common/traits/openapi_test.go
+++ b/e2e/common/misc/openapi_test.go
@@ -24,38 +24,47 @@ package common
 
 import (
 	"context"
+	"fmt"
 	"os"
 	"testing"
+	"time"
 
 	. "github.com/onsi/gomega"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
 	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 TestOpenAPI(t *testing.T) {
 	t.Parallel()
 	WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
-		openapiContent, err := os.ReadFile("./files/openapi/petstore-api.yaml")
+		name := RandomizedSuffixName("petstore")
+		openapiContent, err := os.ReadFile("./files/petstore-api.yaml")
 		require.NoError(t, err)
 		var cmDataProps = make(map[string]string)
 		cmDataProps["petstore-api.yaml"] = string(openapiContent)
 		CreatePlainTextConfigmap(t, ctx, ns, "my-openapi", cmDataProps)
 
-		g.Expect(KamelRun(t, ctx, ns, "--name", "petstore", "--open-api", "configmap:my-openapi", "files/openapi/petstore.yaml").Execute()).To(Succeed())
+		g.Expect(KamelRun(t, ctx, ns,
+			"--name", name, "--resource", "configmap:my-openapi", "files/petstore.yaml").
+			Execute()).To(Succeed())
 
-		g.Eventually(IntegrationPodPhase(t, ctx, ns, "petstore"), TestTimeoutLong).
-			Should(Equal(corev1.PodRunning))
-		g.Eventually(DeploymentWithIntegrationLabel(t, ctx, ns, "petstore"), TestTimeoutLong).
-			Should(Not(BeNil()))
-
-		g.Eventually(IntegrationLogs(t, ctx, ns, "petstore"), TestTimeoutMedium).
-			Should(ContainSubstring("Started listPets (rest://get:/v1:/pets)"))
-		g.Eventually(IntegrationLogs(t, ctx, ns, "petstore"), TestTimeoutMedium).
-			Should(ContainSubstring("Started createPets (rest://post:/v1:/pets)"))
-		g.Eventually(IntegrationLogs(t, ctx, ns, "petstore"), TestTimeoutMedium).
-			Should(ContainSubstring("Started showPetById (rest://get:/v1:/pets/%7BpetId%7D)"))
+		g.Eventually(IntegrationConditionStatus(t, ctx, ns, name, v1.IntegrationConditionReady), TestTimeoutMedium).
+			Should(Equal(corev1.ConditionTrue))
+		g.Eventually(IntegrationPodPhase(t, ctx, ns, name)).Should(Equal(corev1.PodRunning))
+		// Let's make sure the Integration is ready to receive traffic
+		g.Eventually(IntegrationLogs(t, ctx, ns, name)).Should(ContainSubstring("Listening on: http://0.0.0.0:8080"))
+		pod := IntegrationPod(t, ctx, ns, name)()
+		g.Expect(pod).NotTo(BeNil())
+		response, err := TestClient(t).CoreV1().RESTClient().Get().
+			Timeout(30 * time.Second).
+			AbsPath(fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/proxy/v1/pets", pod.Namespace, pod.Name)).
+			DoRaw(ctx)
+		require.NoError(t, err)
+		assert.Equal(t, "listPets", string(response))
 	})
 }
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index 54d58fc63..7b055195a 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -1774,26 +1774,6 @@ func KnativeService(t *testing.T, ctx context.Context, ns string, name string) f
 		return &answer
 	}
 }
-func DeploymentWithIntegrationLabel(t *testing.T, ctx context.Context, ns string, label string) func() *appsv1.Deployment {
-	return func() *appsv1.Deployment {
-		lst := appsv1.DeploymentList{
-			TypeMeta: metav1.TypeMeta{
-				Kind:       "Deployment",
-				APIVersion: appsv1.SchemeGroupVersion.String(),
-			},
-		}
-		if err := TestClient(t).List(ctx, &lst, ctrl.InNamespace(ns), ctrl.MatchingLabels{v1.IntegrationLabel: label}); err != nil && k8serrors.IsNotFound(err) {
-			return nil
-		} else if err != nil {
-			log.Errorf(err, "Error while retrieving deployment %s", label)
-			return nil
-		}
-		if len(lst.Items) == 0 {
-			return nil
-		}
-		return &lst.Items[0]
-	}
-}
 
 func Deployment(t *testing.T, ctx context.Context, ns string, name string) func() *appsv1.Deployment {
 	return func() *appsv1.Deployment {
diff --git a/pkg/apis/camel/v1/trait/openapi.go b/pkg/apis/camel/v1/trait/openapi.go
index a8c7f6a41..de0acedb1 100644
--- a/pkg/apis/camel/v1/trait/openapi.go
+++ b/pkg/apis/camel/v1/trait/openapi.go
@@ -19,7 +19,11 @@ package trait
 
 // The OpenAPI DSL trait is internally used to allow creating integrations from a OpenAPI specs.
 //
+// WARNING: The Openapi trait is **deprecated** and will removed in future release versions:
+// use Camel REST contract first instead, https://camel.apache.org/manual/rest-dsl-openapi.html
+//
 // +camel-k:trait=openapi.
+// +camel-k:deprecated=2.5.0.
 type OpenAPITrait struct {
 	PlatformBaseTrait `property:",squash" json:",inline"`
 	// The configmaps holding the spec of the OpenAPI (compatible with > 3.0 spec only).
diff --git a/pkg/apis/camel/v1/trait/service_binding.go b/pkg/apis/camel/v1/trait/service_binding.go
index 82aff8e01..4b5a8bb63 100644
--- a/pkg/apis/camel/v1/trait/service_binding.go
+++ b/pkg/apis/camel/v1/trait/service_binding.go
@@ -17,7 +17,7 @@ limitations under the License.
 
 package trait
 
-// WARNING: The Registry trait is **deprecated** and will removed in future release versions.
+// WARNING: The Service Binding trait is **deprecated** and will removed in future release versions.
 //
 
 // The Service Binding trait allows users to connect to Services in Kubernetes:
diff --git a/pkg/trait/openapi.go b/pkg/trait/openapi.go
index fbc1bf49d..4b1a1100b 100644
--- a/pkg/trait/openapi.go
+++ b/pkg/trait/openapi.go
@@ -62,12 +62,19 @@ func newOpenAPITrait() Trait {
 }
 
 func (t *openAPITrait) Configure(e *Environment) (bool, *TraitCondition, error) {
-	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
-		return false, nil, nil
-	}
-
 	if t.Configmaps != nil {
-		return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil, nil
+		if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
+			condition := NewIntegrationCondition(
+				"OpenApi",
+				v1.IntegrationConditionTraitInfo,
+				corev1.ConditionTrue,
+				traitConfigurationReason,
+				"OpenApi trait is deprecated and may be removed in future version: "+
+					"use Camel REST contract first instead, https://camel.apache.org/manual/rest-dsl-openapi.html",
+			)
+
+			return true, condition, nil
+		}
 	}
 
 	return false, nil, nil
diff --git a/pkg/trait/openapi_test.go b/pkg/trait/openapi_test.go
index 8ef68f2a2..85a55a68c 100644
--- a/pkg/trait/openapi_test.go
+++ b/pkg/trait/openapi_test.go
@@ -73,7 +73,11 @@ func TestRestDslTraitApplicability(t *testing.T) {
 	enabled, condition, err = trait.Configure(e)
 	require.NoError(t, err)
 	assert.True(t, enabled)
-	assert.Nil(t, condition)
+	assert.NotNil(t, condition)
+	assert.Equal(t, "OpenApi trait is deprecated and may be removed in future version: "+
+		"use Camel REST contract first instead, https://camel.apache.org/manual/rest-dsl-openapi.html",
+		condition.message,
+	)
 }
 
 func TestRestDslTraitApplyError(t *testing.T) {
diff --git a/pkg/util/source/inspector.go b/pkg/util/source/inspector.go
index 04c646b95..1c697b9a4 100644
--- a/pkg/util/source/inspector.go
+++ b/pkg/util/source/inspector.go
@@ -54,6 +54,7 @@ var (
 	restConfigurationRegexp = regexp.MustCompile(`.*restConfiguration\(\).*`)
 	restRegexp              = regexp.MustCompile(`.*rest\s*\([^)]*\).*`)
 	restClosureRegexp       = regexp.MustCompile(`.*rest\s*{\s*`)
+	openAPIRegexp           = regexp.MustCompile(`.*\.openApi\s*\([^)]*\).*`)
 	groovyLanguageRegexp    = regexp.MustCompile(`.*\.groovy\s*\(.*\).*`)
 	jsonPathLanguageRegexp  = regexp.MustCompile(`.*\.?(jsonpath|jsonpathWriteAsString)\s*\(.*\).*`)
 	ognlRegexp              = regexp.MustCompile(`.*\.ognl\s*\(.*\).*`)
@@ -110,6 +111,12 @@ var (
 			}
 			return deps
 		},
+		openAPIRegexp: func(catalog *camel.RuntimeCatalog) []string {
+			if dfDep := catalog.GetArtifactByScheme("rest-openapi"); dfDep != nil {
+				return []string{dfDep.GetDependencyID()}
+			}
+			return []string{}
+		},
 		groovyLanguageRegexp: func(catalog *camel.RuntimeCatalog) []string {
 			if dependency, ok := catalog.GetLanguageDependency("groovy"); ok {
 				return []string{dependency}
diff --git a/pkg/util/source/inspector_java_source_test.go b/pkg/util/source/inspector_java_source_test.go
index 71e60e2db..33e4722ba 100644
--- a/pkg/util/source/inspector_java_source_test.go
+++ b/pkg/util/source/inspector_java_source_test.go
@@ -171,3 +171,22 @@ func TestJavaReplaceURI(t *testing.T) {
 	assert.True(t, replaced)
 	assert.Equal(t, "from(\"direct:newURI?hello=world\").to(\"log:info\")", sourceSpec.Content)
 }
+
+func TestJavaRestOpenapiFirst(t *testing.T) {
+	inspector := newTestJavaSourceInspector(t)
+
+	sourceSpec := v1.SourceSpec{
+		DataSpec: v1.DataSpec{
+			Name: "test.java",
+			Content: `
+public void configure() throws Exception {
+    rest().openApi("petstore-v3.json");
+}
+			`,
+		},
+	}
+	meta := NewMetadata()
+	err := inspector.Extract(sourceSpec, &meta)
+	require.NoError(t, err)
+	assert.Contains(t, meta.Dependencies.List(), "camel:rest-openapi")
+}
diff --git a/pkg/util/source/inspector_xml.go b/pkg/util/source/inspector_xml.go
index 1a1954879..2604a5944 100644
--- a/pkg/util/source/inspector_xml.go
+++ b/pkg/util/source/inspector_xml.go
@@ -49,9 +49,14 @@ func (i XMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 
 		if se, ok := t.(xml.StartElement); ok {
 			switch se.Name.Local {
+			//nolint: goconst
 			case "rest", "restConfiguration":
 				meta.ExposesHTTPServices = true
 				meta.RequiredCapabilities.Add(v1.CapabilityRest)
+			case "openApi":
+				if dfDep := i.catalog.GetArtifactByScheme("rest-openapi"); dfDep != nil {
+					meta.AddDependency(dfDep.GetDependencyID())
+				}
 			case "circuitBreaker":
 				meta.RequiredCapabilities.Add(v1.CapabilityCircuitBreaker)
 			case "json":
diff --git a/pkg/util/source/inspector_xml_test.go b/pkg/util/source/inspector_xml_test.go
index 8e68c3bcf..98f326ced 100644
--- a/pkg/util/source/inspector_xml_test.go
+++ b/pkg/util/source/inspector_xml_test.go
@@ -205,3 +205,26 @@ func TestXMLReplaceURI(t *testing.T) {
 	assert.True(t, replaced)
 	assert.Contains(t, sourceSpec.Content, "<from uri=\"direct:newURI?hello=world\"/>")
 }
+
+func TestXMLRestOpenapiFirst(t *testing.T) {
+	inspector := newTestXMLInspector(t)
+
+	sourceSpec := v1.SourceSpec{
+		DataSpec: v1.DataSpec{
+			Name: "test.xml",
+			Content: `
+		  <rest>
+			<openApi specification="petstore-v3.json"/>
+		  </rest>
+		  <route>
+			<from uri="direct:getUserByName"/>
+			// do something here
+		  </route>
+			`,
+		},
+	}
+	meta := NewMetadata()
+	err := inspector.Extract(sourceSpec, &meta)
+	require.NoError(t, err)
+	assert.Contains(t, meta.Dependencies.List(), "camel:rest-openapi")
+}
diff --git a/pkg/util/source/inspector_yaml.go b/pkg/util/source/inspector_yaml.go
index 199007635..dac9165c0 100644
--- a/pkg/util/source/inspector_yaml.go
+++ b/pkg/util/source/inspector_yaml.go
@@ -41,6 +41,9 @@ func (i YAMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 	}
 
 	for _, definition := range definitions {
+		if err := i.parseDefinition(definition, meta); err != nil {
+			return err
+		}
 		for k, v := range definition {
 			if err := i.parseStep(k, v, meta); err != nil {
 				return err
@@ -62,6 +65,26 @@ func (i YAMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 	return nil
 }
 
+//nolint:nestif
+func (i YAMLInspector) parseDefinition(def map[string]interface{}, meta *Metadata) error {
+	for k, v := range def {
+		if k == "rest" {
+			meta.ExposesHTTPServices = true
+			meta.RequiredCapabilities.Add(v1.CapabilityRest)
+			// support contract first openapi
+			if oa, ok := v.(map[interface{}]interface{}); ok {
+				if _, oaOk := oa["openApi"]; oaOk {
+					if dfDep := i.catalog.GetArtifactByScheme("rest-openapi"); dfDep != nil {
+						meta.AddDependency(dfDep.GetDependencyID())
+					}
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
 //nolint:nestif
 func (i YAMLInspector) parseStep(key string, content interface{}, meta *Metadata) error {
 	switch key {
diff --git a/pkg/util/source/inspector_yaml_test.go b/pkg/util/source/inspector_yaml_test.go
index d1eee1462..03cd99178 100644
--- a/pkg/util/source/inspector_yaml_test.go
+++ b/pkg/util/source/inspector_yaml_test.go
@@ -729,3 +729,31 @@ func TestYAMLRouteReplaceURI(t *testing.T) {
 	// Assert changed uri and removed parameters
 	assert.Contains(t, sourceSpec.Content, expectedYamlRouteCronReplacement)
 }
+
+func TestYAMLRESTContractFirst(t *testing.T) {
+	yamlContractFirst := `
+- rest:
+    openApi:
+      specification: petstore-v3.json
+
+- route:
+    id: route1
+    from:
+      uri: "timer:tick"
+      parameters:
+        period: "5000"
+    steps:
+      - setBody:
+          constant: "Hello Yaml !!!"
+      - transform:
+          simple: "${body.toUpperCase()}"
+      - to: "{{url}}"
+`
+
+	inspector := newTestYAMLInspector(t)
+	t.Run("TestYAMLRESTContractFirst", func(t *testing.T) {
+		assertExtractYAML(t, inspector, yamlContractFirst, func(meta *Metadata) {
+			assert.Contains(t, meta.Dependencies.List(), "camel:rest-openapi")
+		})
+	})
+}