This repository has been archived by the owner on Oct 25, 2022. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from montaro/cloud-events-example
Cloud Events Example
- Loading branch information
Showing
4 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# Receive Cloud Events from an external solution | ||
|
||
This is an example scenario which demonstrates how Kyma can receive Cloud Events from an external solution. To make things easier, this scenario uses a **local Kyma installation**. | ||
|
||
This scenario uses a mocked external solution. You can mock the sending of Events using an HTTP client. | ||
You can also use other mocked or real solutions. | ||
The runtime flow involves following steps: | ||
|
||
1. The external solution sends an `order.created` Event. | ||
2. The Event is accepted by Kyma. | ||
3. The Event triggers the deployed lambda. | ||
4. The lambda prints out CE context attributes. | ||
|
||
## Prerequisites | ||
|
||
### Install Kyma locally | ||
|
||
Use these [instructions](https://github.com/kyma-project/kyma/blob/master/docs/kyma/04-02-local-installation.md) to install and configure Kyma locally. | ||
|
||
### Create a Namespace | ||
|
||
Create a Namespace called `workshop`. You can choose a different name, but remember to use it in the commands. | ||
|
||
### Create Application | ||
|
||
1. In the Kyma Console, go to **Integration** > **Application** > **Create Application**. | ||
2. Enter the Application name: sample-external-solution. | ||
|
||
## Installation | ||
|
||
### Establish secure connection | ||
|
||
Use the [connector service](https://github.com/kyma-project/kyma/blob/master/docs/application-connector/02-02-connector-service.md) to establish a secure connection between the mocked external solution and your application. | ||
|
||
Follow these steps connect an external solution to Kyma: | ||
1. Clone [this repository](https://github.com/janmedrek/one-click-integration-script). | ||
|
||
2. In the Kyma Console, navigate to **Integration** > **Applications** > **sample-external-solution**. | ||
3. Click **Connect Application**. | ||
4. Copy the token. | ||
|
||
5. Use the one-click-generation [helper script](https://github.com/janmedrek/one-click-integration-script) to generate the certificate: | ||
|
||
```bash | ||
./one-click-integration.sh -u <paste URL here> | ||
``` | ||
|
||
This script generates a `generated.pem` file. It contains the signed certificate and key that you will use for subsequent communications. | ||
|
||
> **NOTE** The token expires quickly, so use it right away or generate a new one. | ||
### Mock an external solution | ||
|
||
Use any HTTP client, such as curl or postman, to send a request from the mocked external solution to Kyma. | ||
|
||
### Register Events | ||
|
||
1. Register Events via the metadata API using [`register-events.json`](./register-events.json): | ||
|
||
```bash | ||
# Using httpie | ||
http POST https://gateway.kyma.local/sample-external-solution/v1/metadata/services --cert=generated.pem --verify=no < register-events.json | ||
# Using curl | ||
curl -X POST -H "Content-Type: application/json" -d @./register-events.json https://gateway.kyma.local/sample-external-solution/v1/metadata/services --cert generated.pem -k | ||
``` | ||
|
||
To verify the Event flow, navigate to **Integration** > **Applications** > **sample-external-solution**. You can see the registered Events. | ||
|
||
### Bind Application | ||
|
||
1. Navigate to **Integration** > **Applications** > **sample-external-solution** | ||
2. Create a binding with the `workshop` Namespace. | ||
|
||
### Add Events and APIs to the Namespace | ||
|
||
1. Select the `workshop` Namespace and go to **Service Management** > **Catalog**. | ||
2. Click **Services** to see the registered Events. | ||
3. Click on the Event entry to reveal details. | ||
4. Click **Add once** button to add Events to your Namespace. | ||
5. Go to **Service Instances** > **Services** tab to see if the Events are available. | ||
|
||
### Create lambda | ||
|
||
1. Create the lambda definition in lambda ui using [lambda.js](./lambda.js) in the workshop namespace | ||
|
||
2. Click **Select Function trigger** button to select an Event trigger, then choose | ||
**order.created**. | ||
|
||
## Runtime | ||
|
||
### Publish the Event | ||
|
||
Use the certificate generated by the `./one-click-integration.sh` script to send a Cloud Event to the gateway using any HTTP client, such as curl, httpie, or postman. You can also use CloudEvents SDK. For details, see [this example](./example.go) | ||
|
||
## Verification | ||
|
||
To check if the lambda function was triggered properly, inspect the Pod logs in the `workshop` Namespace: | ||
|
||
```bash | ||
kubectl -n work logs lambdaname-xxx-xxxx -c lambdaname -f | ||
``` | ||
|
||
You can also find traces under `https://jaeger.kyma.local/`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"crypto/tls" | ||
"crypto/x509" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"time" | ||
|
||
cloudevents "github.com/cloudevents/sdk-go" | ||
"github.com/google/uuid" | ||
) | ||
|
||
func main() { | ||
event := cloudevents.NewEvent() | ||
event.Context = cloudevents.EventContextV03{}.AsV03() | ||
event.SetID(uuid.New().String()) | ||
event.SetType("order.created") | ||
event.SetSource("external-application") | ||
event.SetTime(time.Now()) | ||
event.SetExtension("eventtypeversion", "v1") | ||
event.SetDataContentType("application/json") | ||
event.SetData(23) | ||
|
||
// Add path to client certificate and key | ||
cert, err := tls.LoadX509KeyPair("generated.crt", "generated.key") | ||
if err != nil { | ||
log.Fatalln("Unable to load cert", err) | ||
} | ||
clientCACert, err := ioutil.ReadFile("generated.crt") | ||
if err != nil { | ||
log.Fatal("Unable to open cert", err) | ||
} | ||
|
||
clientCertPool := x509.NewCertPool() | ||
clientCertPool.AppendCertsFromPEM(clientCACert) | ||
|
||
tlsConfig := &tls.Config{ | ||
Certificates: []tls.Certificate{cert}, | ||
RootCAs: clientCertPool, | ||
InsecureSkipVerify: true, | ||
} | ||
|
||
tlsConfig.BuildNameToCertificate() | ||
|
||
client := &http.Client{ | ||
Transport: &http.Transport{TLSClientConfig: tlsConfig}, | ||
} | ||
target := "https://gateway.kyma.local/sample-external-solution/v2/events" | ||
t, err := cloudevents.NewHTTPTransport( | ||
cloudevents.WithTarget(target), | ||
cloudevents.WithStructuredEncoding()) | ||
|
||
t.Client = client | ||
c, err := cloudevents.NewClient(t) | ||
if err != nil { | ||
panic("unable to create cloudevent client: " + err.Error()) | ||
} | ||
_, err = c.Send(context.Background(), event) | ||
if err != nil { | ||
panic("failed to send cloudevent: " + err.Error()) | ||
} | ||
fmt.Printf("Successfully sent a new event to: %s", target) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module.exports = { | ||
main: function (event, context) { | ||
console.log(event); | ||
console.log("Cloud Events Attributes"); | ||
console.log("ce-specversion: " + event.extensions.request.headers['ce-specversion']); | ||
console.log("ce-type: " + event.extensions.request.headers['ce-type']); | ||
console.log("ce-source: " + event.extensions.request.headers['ce-source']); | ||
console.log("ce-id: " + event.extensions.request.headers['ce-id']); | ||
console.log("ce-time: " + event.extensions.request.headers['ce-time']); | ||
console.log("ce-eventtypeversion: " + event.extensions.request.headers['ce-eventtypeversion']); | ||
console.log("ce-knativehistory: " + event.extensions.request.headers['ce-knativehistory']); | ||
console.log("content-type: " + event.extensions.request.headers['content-type']); | ||
return event.data; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
{ | ||
"name": "es-all-events", | ||
"provider": "Amazing Web Shop using Kyma", | ||
"description": "Sample service for e-2-e flow", | ||
"events": { | ||
"spec": { | ||
"asyncapi": "1.0.0", | ||
"info": { | ||
"title": "ES Events", | ||
"version": "1.0.0", | ||
"description": "Description of all the EC events\n" | ||
}, | ||
"baseTopic": "stage.com.external.solution", | ||
"topics": { | ||
"order.created.v1": { | ||
"subscribe": { | ||
"summary": "Event containing information about the order added.", | ||
"payload": { | ||
"type": "object", | ||
"properties": { | ||
"orderCode": { | ||
"title": "OrderCode", | ||
"description": "Resource identifier", | ||
"type": "string" | ||
} | ||
}, | ||
"example": { | ||
"orderCode": "4caad296-e0c5-491e-98ac-0ed118f9474e" | ||
} | ||
} | ||
} | ||
}, | ||
"payment.received.v1": { | ||
"subscribe": { | ||
"summary": "Event containing information about the payment received.", | ||
"payload": { | ||
"type": "object", | ||
"properties": { | ||
"orderCode": { | ||
"title": "paymentReceivedCode", | ||
"description": "Resource identifier", | ||
"type": "string" | ||
} | ||
}, | ||
"example": { | ||
"orderCode": "b5870936-16d4-45e1-b9c6-4a3cd4417187" | ||
} | ||
} | ||
} | ||
}, | ||
"address.updated.v1": { | ||
"subscribe": { | ||
"summary": "Event containing information about the updated addrees", | ||
"payload": { | ||
"type": "object", | ||
"properties": { | ||
"orderCode": { | ||
"title": "addressUpdatedCode", | ||
"description": "Resource identifier", | ||
"type": "string" | ||
} | ||
}, | ||
"example": { | ||
"orderCode": "c3ec6858-de3d-4e0a-9d14-779ed023c7ee" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |