Skip to content

Commit

Permalink
feat(trait): deprecate openapi trait
Browse files Browse the repository at this point in the history
In favour of contract first openapi Camel feature

Closes #5729
  • Loading branch information
squakez committed Oct 19, 2024
1 parent 88abc3c commit 699810e
Show file tree
Hide file tree
Showing 16 changed files with 160 additions and 40 deletions.
3 changes: 3 additions & 0 deletions docs/modules/ROOT/partials/apis/camel-k-crds.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
|===
Expand Down
4 changes: 4 additions & 0 deletions docs/modules/traits/pages/openapi.adoc
Original file line number Diff line number Diff line change
@@ -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**.

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
# limitations under the License.
# ---------------------------------------------------------------------------

- rest:
openApi:
specification: petstore-api.yaml

- from:
uri: "direct:listPets"
steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
})
}
20 changes: 0 additions & 20 deletions e2e/support/test_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/camel/v1/trait/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/camel/v1/trait/service_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
17 changes: 12 additions & 5 deletions pkg/trait/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion pkg/trait/openapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 7 additions & 0 deletions pkg/util/source/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -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*\(.*\).*`)
Expand Down Expand Up @@ -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}
Expand Down
19 changes: 19 additions & 0 deletions pkg/util/source/inspector_java_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
5 changes: 5 additions & 0 deletions pkg/util/source/inspector_xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down
23 changes: 23 additions & 0 deletions pkg/util/source/inspector_xml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
23 changes: 23 additions & 0 deletions pkg/util/source/inspector_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down
28 changes: 28 additions & 0 deletions pkg/util/source/inspector_yaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
})
})
}

0 comments on commit 699810e

Please sign in to comment.