mirror of https://github.com/knative/docs.git
Added a cloudevents sample using Vert.x (#2480)
* Added a cloudevents sample using vertx * Suggestions * index * image name fix Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Support K_SINK Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * New APIs Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Pretty md Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Using 2.0.0-milestone1 Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
parent
634df4693a
commit
100918f280
|
@ -0,0 +1,6 @@
|
||||||
|
# Target dir
|
||||||
|
**/target/
|
||||||
|
|
||||||
|
# Idea files
|
||||||
|
**/*.iml
|
||||||
|
**/.idea/
|
|
@ -0,0 +1,123 @@
|
||||||
|
# Vert.x + CloudEvents + Knative
|
||||||
|
|
||||||
|
A simple web app written in Java using Vert.x that can receive CloudEvents. It
|
||||||
|
supports running in two modes:
|
||||||
|
|
||||||
|
1. The default mode has the app reply to your input events with the output
|
||||||
|
event, which is simplest for demonstrating things working in isolation, but
|
||||||
|
is also the model for working for the Knative Eventing `Broker` concept. The
|
||||||
|
input event is modified assigning a new source and type attribute.
|
||||||
|
|
||||||
|
2. `K_SINK` mode has the app send events to the destination encoded in
|
||||||
|
`$K_SINK`, which is useful to demonstrate how folks can synthesize events to
|
||||||
|
send to a Service or Broker when not initiated by a Broker invocation (e.g.
|
||||||
|
implementing an event source). The input event is modified assigning a new
|
||||||
|
source and type attribute.
|
||||||
|
|
||||||
|
The application will use `$K_SINK`-mode whenever the environment variable is
|
||||||
|
specified.
|
||||||
|
|
||||||
|
Follow the steps below to create the sample code and then deploy the app to your
|
||||||
|
cluster. You can also download a working copy of the sample, by running the
|
||||||
|
following commands:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone -b "{{< branch >}}" https://github.com/knative/docs knative-docs
|
||||||
|
cd knative-docs/docs/serving/samples/cloudevents/cloudevents-vertx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Before you begin
|
||||||
|
|
||||||
|
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||||
|
[installation instructions](../../../../install/README.md) if you need to
|
||||||
|
create one.
|
||||||
|
- [Docker](https://www.docker.com) installed and running on your local machine,
|
||||||
|
and a Docker Hub account configured (we'll use it for a container registry).
|
||||||
|
|
||||||
|
## Build and deploy the sample
|
||||||
|
|
||||||
|
To build the image, run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mvn compile jib:build -Dimage=<image_name>
|
||||||
|
```
|
||||||
|
|
||||||
|
To deploy the Knative Service, look in the `service.yaml` and replace `<image>`
|
||||||
|
with the deployed image name. Then run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl apply -f service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing the sample
|
||||||
|
|
||||||
|
Get the URL for your Service with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ kubectl get ksvc
|
||||||
|
NAME URL LATESTCREATED LATESTREADY READY REASON
|
||||||
|
cloudevents-vertx http://cloudevents-java.xip.io cloudevents-vertx-86h28 cloudevents-vertx-86h28 True
|
||||||
|
```
|
||||||
|
|
||||||
|
Then send a CloudEvent to it with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ curl \
|
||||||
|
-X POST -v \
|
||||||
|
-H "content-type: application/json" \
|
||||||
|
-H "ce-specversion: 1.0" \
|
||||||
|
-H "ce-source: http://curl-command" \
|
||||||
|
-H "ce-type: curl.demo" \
|
||||||
|
-H "ce-id: 123-abc" \
|
||||||
|
-d '{"name":"Dave"}' \
|
||||||
|
http://cloudevents-java.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also send CloudEvents spawning a temporary curl pod in your cluster
|
||||||
|
with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ kubectl run curl \
|
||||||
|
--image=curlimages/curl --rm=true --restart=Never -ti -- \
|
||||||
|
-X POST -v \
|
||||||
|
-H "content-type: application/json" \
|
||||||
|
-H "ce-specversion: 1.0" \
|
||||||
|
-H "ce-source: http://curl-command" \
|
||||||
|
-H "ce-type: curl.demo" \
|
||||||
|
-H "ce-id: 123-abc" \
|
||||||
|
-d '{"name":"Dave"}' \
|
||||||
|
http://cloudevents-java.default.svc
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see on the console:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
> POST / HTTP/1.1
|
||||||
|
> Host: localhost:8080
|
||||||
|
> User-Agent: curl/7.69.1
|
||||||
|
> Accept: */*
|
||||||
|
> content-type: application/json
|
||||||
|
> ce-specversion: 1.0
|
||||||
|
> ce-source: http://curl-command
|
||||||
|
> ce-type: curl.demo
|
||||||
|
> ce-id: 123-abc
|
||||||
|
> Content-Length: 15
|
||||||
|
>
|
||||||
|
< HTTP/1.1 202 Accepted
|
||||||
|
< ce-specversion: 1.0
|
||||||
|
< ce-id: 123-abc
|
||||||
|
< ce-source: https://github.com/knative/docs/docs/serving/samples/cloudevents/cloudevents-vertx
|
||||||
|
< ce-type: curl.demo
|
||||||
|
< content-type: application/json
|
||||||
|
< content-length: 15
|
||||||
|
<
|
||||||
|
{"name":"Dave"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
title: "Cloud Events - Java and Vert.x"
|
||||||
|
linkTitle: "Java and Vert.x"
|
||||||
|
weight: 1
|
||||||
|
type: "docs"
|
||||||
|
---
|
||||||
|
|
||||||
|
{{% readfile file="README.md" %}}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.knative.examples</groupId>
|
||||||
|
<artifactId>cloudevents-example-vertx</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<vertx.verticle>org.knative.examples.cloudevents.vertx.CloudEventSampleVerticle</vertx.verticle>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.cloudevents</groupId>
|
||||||
|
<artifactId>cloudevents-core</artifactId>
|
||||||
|
<version>2.0.0-milestone1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.cloudevents</groupId>
|
||||||
|
<artifactId>cloudevents-http-vertx</artifactId>
|
||||||
|
<version>2.0.0-milestone1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.google.cloud.tools</groupId>
|
||||||
|
<artifactId>jib-maven-plugin</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
<configuration>
|
||||||
|
<container>
|
||||||
|
<jvmFlags>
|
||||||
|
<jvmFlag>-Dorg.slf4j.simpleLogger.defaultLogLevel=warn</jvmFlag>
|
||||||
|
</jvmFlags>
|
||||||
|
<mainClass>org.knative.examples.cloudevents.vertx.CloudEventSampleVerticle</mainClass>
|
||||||
|
</container>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- With this plugin you can locally test the application using `mvn vertx:run` -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>io.reactiverse</groupId>
|
||||||
|
<artifactId>vertx-maven-plugin</artifactId>
|
||||||
|
<version>1.0.22</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,10 @@
|
||||||
|
apiVersion: serving.knative.dev/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: cloudevents-vertx
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: <image>
|
|
@ -0,0 +1,151 @@
|
||||||
|
package org.knative.examples.cloudevents.vertx;
|
||||||
|
|
||||||
|
import io.cloudevents.CloudEvent;
|
||||||
|
import io.cloudevents.core.builder.CloudEventBuilder;
|
||||||
|
import io.cloudevents.core.message.MessageReader;
|
||||||
|
import io.cloudevents.http.vertx.VertxMessageFactory;
|
||||||
|
import io.vertx.core.AbstractVerticle;
|
||||||
|
import io.vertx.core.Handler;
|
||||||
|
import io.vertx.core.Promise;
|
||||||
|
import io.vertx.core.Vertx;
|
||||||
|
import io.vertx.core.http.*;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class CloudEventSampleVerticle extends AbstractVerticle {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Vertx vertx = Vertx.vertx();
|
||||||
|
vertx.deployVerticle(new CloudEventSampleVerticle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(Promise<Void> startPromise) {
|
||||||
|
HttpServer server = vertx.createHttpServer();
|
||||||
|
|
||||||
|
// Get the port
|
||||||
|
int port = Optional.ofNullable(System.getenv("PORT")).map(Integer::parseInt).orElse(8080);
|
||||||
|
|
||||||
|
// Get the sink uri, if any
|
||||||
|
Optional<URI> env = Optional.ofNullable(System.getenv("K_SINK")).map(URI::create);
|
||||||
|
if (env.isPresent()) {
|
||||||
|
server.requestHandler(generateSinkHandler(vertx.createHttpClient(), env.get()));
|
||||||
|
} else {
|
||||||
|
// If K_SINK is not set, just echo back the events
|
||||||
|
server.requestHandler(generateEchoHandler());
|
||||||
|
}
|
||||||
|
|
||||||
|
server
|
||||||
|
// Listen and complete verticle deploy
|
||||||
|
.listen(port, serverResult -> {
|
||||||
|
if (serverResult.succeeded()) {
|
||||||
|
System.out.println("Server started on port " + serverResult.result().actualPort());
|
||||||
|
startPromise.complete();
|
||||||
|
} else {
|
||||||
|
System.out.println("Error starting the server");
|
||||||
|
serverResult.cause().printStackTrace();
|
||||||
|
startPromise.fail(serverResult.cause());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an handler that does the echo of the received event
|
||||||
|
*/
|
||||||
|
public static Handler<HttpServerRequest> generateEchoHandler() {
|
||||||
|
return request -> {
|
||||||
|
// Transform the HttpRequest to Event
|
||||||
|
VertxMessageFactory
|
||||||
|
.createReader(request)
|
||||||
|
.map(MessageReader::toEvent)
|
||||||
|
.onComplete(asyncResult -> {
|
||||||
|
if (asyncResult.succeeded()) {
|
||||||
|
CloudEvent event = asyncResult.result();
|
||||||
|
System.out.println("Received event: " + event);
|
||||||
|
|
||||||
|
// Let's modify the event changing the source
|
||||||
|
CloudEvent outputEvent = CloudEventBuilder
|
||||||
|
.v1(event)
|
||||||
|
.withSource(URI.create("https://github.com/knative/docs/docs/serving/samples/cloudevents/cloudevents-vertx"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Set response status code
|
||||||
|
HttpServerResponse response = request
|
||||||
|
.response()
|
||||||
|
.setStatusCode(202);
|
||||||
|
|
||||||
|
// Reply with the event in binary mode
|
||||||
|
VertxMessageFactory
|
||||||
|
.createWriter(response)
|
||||||
|
.writeBinary(outputEvent);
|
||||||
|
} else {
|
||||||
|
System.out.println("Error while decoding the event: " + asyncResult.cause());
|
||||||
|
|
||||||
|
// Reply with a failure
|
||||||
|
request
|
||||||
|
.response()
|
||||||
|
.setStatusCode(400)
|
||||||
|
.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an handler that sink the does the echo of the received event
|
||||||
|
*/
|
||||||
|
public static Handler<HttpServerRequest> generateSinkHandler(HttpClient client, URI sink) {
|
||||||
|
return serverRequest -> {
|
||||||
|
// Transform the HttpRequest to Event
|
||||||
|
VertxMessageFactory
|
||||||
|
.createReader(serverRequest)
|
||||||
|
.map(MessageReader::toEvent)
|
||||||
|
.onComplete(asyncResult -> {
|
||||||
|
if (asyncResult.succeeded()) {
|
||||||
|
CloudEvent event = asyncResult.result();
|
||||||
|
System.out.println("Received event: " + event);
|
||||||
|
|
||||||
|
// Let's modify the event changing the source
|
||||||
|
CloudEvent outputEvent = CloudEventBuilder
|
||||||
|
.v1(event)
|
||||||
|
.withSource(URI.create("https://github.com/knative/docs/docs/serving/samples/cloudevents/cloudevents-vertx"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Prepare the http request to the sink
|
||||||
|
HttpClientRequest sinkRequest = client.postAbs(sink.toString());
|
||||||
|
|
||||||
|
// Define how to handle the response from the sink
|
||||||
|
sinkRequest.handler(sinkResponse -> {
|
||||||
|
if (sinkResponse.statusCode() >= 200 && sinkResponse.statusCode() < 300) {
|
||||||
|
serverRequest
|
||||||
|
.response()
|
||||||
|
.setStatusCode(202)
|
||||||
|
.end();
|
||||||
|
} else {
|
||||||
|
System.out.println("Error received from sink: " + sinkResponse.statusCode() + " " + sinkResponse.statusMessage());
|
||||||
|
serverRequest
|
||||||
|
.response()
|
||||||
|
.setStatusCode(500)
|
||||||
|
.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send the event to K_SINK
|
||||||
|
VertxMessageFactory
|
||||||
|
.createWriter(sinkRequest)
|
||||||
|
.writeBinary(event);
|
||||||
|
} else {
|
||||||
|
System.out.println("Error while decoding the event: " + asyncResult.cause());
|
||||||
|
|
||||||
|
// Reply with a failure
|
||||||
|
serverRequest
|
||||||
|
.response()
|
||||||
|
.setStatusCode(400)
|
||||||
|
.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue